Showing Posts From

배포롤백재배포

배포-롤백-재배포: 저녁 7시부터 밤 10시까지의 카오스

배포-롤백-재배포: 저녁 7시부터 밤 10시까지의 카오스

배포-롤백-재배포: 저녁 7시부터 밤 10시까지의 카오스 저녁 7시, "이번엔 다를 거야" 금요일 저녁 7시. 배포 버튼을 눌렀다. "이번엔 로컬에서 완벽하게 테스트했어." 그렇게 생각했다. 정말로.테스트 코드도 돌렸다. 로컬에서 3번 확인했다. 스테이징 환경도 문제없었다. "30분이면 끝나겠지." 주말 전에 깔끔하게 마무리하고 싶었다. 그래야 주말에 슬랙 알림 안 들리니까. 배포 스크립트가 돌아간다. Building... ✓ Testing... ✓ Deploying... ✓완벽하다. 그런데. 7시 12분, 첫 번째 신호 슬랙에 메시지가 떴다. "결제가 안 돼요?" 고객사 담당자다. 금요일 저녁인데 왜 일하시나. "확인해보겠습니다." 손이 떨린다. 아니, 떨리지 않았다. 아직은. 로그를 확인한다. Error: Payment gateway timeout Retry count: 3 Status: Failed"아." 결제 모듈이다. 방금 리팩토링한 거.7시 20분, 롤백 1차 시도 당황하지 말자. 롤백하면 된다. git revert HEAD docker-compose down docker-compose up -d익숙한 명령어들. 이론상 5분이면 끝난다. 그런데 Docker 컨테이너가 안 내려간다. "뭐가 문제야." 강제 종료한다. docker kill. 다시 올린다. 이미지를 못 찾는다. 이전 버전 이미지를 내가 언제 지웠지? "아, 지난주에 디스크 용량 확보한다고..." 다시 빌드해야 한다. 이전 버전으로. 체크아웃한다. 빌드한다. 10분 걸린다. 금요일 저녁 7시 30분인데 배포가 죽어있다. 고객사 담당자가 또 메시지를 보냈다. "아직도 안 되는데요?" "죄송합니다. 5분만 더 기다려주세요." 거짓말이다. 10분은 더 걸린다. 7시 35분, 문제의 본질 롤백이 완료됐다. 이전 버전이 떴다. 결제를 테스트한다. 여전히 안 된다. "???" 이전 버전인데 왜 안 되지? 로그를 뒤진다. 30분 전 로그를 본다. 배포 전 로그. 결제는 잘 됐다. 그럼 뭐가 문제지? 환경변수를 확인한다. PAYMENT_API_KEY=*** PAYMENT_TIMEOUT=3000타임아웃이 3초다. 이전엔 10초였는데. "누가 바꿨지?" 나다. 어제 '최적화'한다고.환경변수는 코드 롤백으로 안 돌아간다. AWS 콘솔에서 직접 바꿔야 한다. 콘솔 들어간다. ECS 태스크 정의. 환경변수 수정. 새 리비전 생성. 서비스 업데이트. 또 5분. 고객사 담당자: "지금 주문 못 받고 있어요. 매출 손실인데요." 식은땀이 난다. 8시 05분, 두 번째 배포 환경변수 수정 완료. 서비스 재시작. 헬스체크 통과. 결제 테스트. 성공. "드디어." 고객사에 메시지 보낸다. "정상화됐습니다. 불편 드려 죄송합니다." 답장이 빠르다. "근데 관리자 페이지가 안 열려요?" "..." 관리자 페이지? 그건 또 뭐야. 확인한다. 500 에러. "이건 또 뭔데." 로그를 본다. Error: Database migration pending Run 'npm run migrate' to apply migrations마이그레이션. 롤백하면서 DB도 롤백했어야 했다. 그런데 나 백업 안 만들었다. "망했다." 8시 25분, 데이터베이스 지옥 DB 마이그레이션은 롤백이 까다롭다. 특히 테이블 구조를 바꿨으면. 마이그레이션 파일을 연다. 오늘 배포에서 뭘 바꿨는지 확인한다. ALTER TABLE payments ADD COLUMN gateway_version VARCHAR(10);컬럼 하나 추가했다. 이전 코드는 이 컬럼을 모른다. "괜찮아. 컬럼 하나 지우면 돼." 그런데 이미 데이터가 들어가 있다. 오늘 7시 이후 결제 시도들. 지우면 안 된다. 데이터 손실이다. 컬럼은 남기고 코드를 수정해야 한다. 이전 버전 코드에 컬럼 참조를 추가. 핫픽스다. 금요일 밤 8시 30분에. 코드를 연다. 손이 빠르게 움직인다. // 긴급 수정 const payment = await db.payments.findOne({ // gateway_version 무시 attributes: { exclude: ['gateway_version'] } });더러운 코드다. 나중에 리팩토링해야 한다. 지금은 일단 돌아가게. 커밋. 푸시. 빌드. 배포. 또 10분. 에너지 드링크를 연다. 세 번째다. 8시 50분, 재배포의 공포 새 버전이 올라간다. 정확히는 "이전 버전 + 긴급 패치". 헬스체크. 통과. 결제 테스트. 성공. 관리자 페이지. 로딩된다. "끝났나?" 고객사에 다시 메시지 보낸다. "이번엔 정말 정상화됐습니다." 5분 동안 답이 없다. 불안하다. 답장이 온다. "네, 잘 되네요. 고생하셨습니다." 긴장이 풀린다. 등받이에 몸을 기댄다. 그런데 또 슬랙 알림. 다른 채널이다. 운영팀. "배송 조회가 느려진 것 같은데요?" "..." 9시 10분, 끝나지 않는 밤 배송 조회 API를 확인한다. 응답 속도가 느리다. 평소 200ms인데 지금 2초. "왜지." New Relic을 연다. 쿼리 성능 모니터링. SELECT * FROM orders WHERE status = 'shipped' ORDER BY created_at DESC;인덱스가 없다. 이전 버전에는 있었는데. 마이그레이션 롤백하면서 인덱스도 날아갔다. 내가 수동으로 복구 안 했다. "진짜 미치겠네." DB 콘솔 접속. 인덱스 다시 생성. CREATE INDEX idx_orders_status_created ON orders(status, created_at);10초 걸린다. 작은 테이블이라 다행이다. 배송 조회 다시 테스트. 200ms로 돌아왔다. "이제 됐지?" 슬랙을 본다. 30분 동안 새 메시지 없다. 좋은 신호다. 9시 45분, 사후 정리 모니터링 대시보드를 30분 동안 지켜본다.결제: 정상 관리자 페이지: 정상 배송 조회: 정상 에러율: 0.1% (평소 수준) 응답 속도: 정상괜찮다. 정말 끝난 것 같다. 사후 기록을 남긴다. 노션에. [장애 리포트] 2024.XX.XX 결제 장애 - 발생 시간: 19:12 - 복구 시간: 21:00 - 원인: 환경변수 타임아웃 설정 + DB 마이그레이션 롤백 미숙 - 영향: 결제 불가 48분, 관리자 페이지 불가 30분 - 대응: 환경변수 복구, 핫픽스 배포, 인덱스 재생성재발 방지책을 쓴다. 1. 환경변수 변경 이력 관리 2. 롤백 체크리스트 작성 (DB, 환경변수 포함) 3. 스테이징에서 롤백 테스트 4. 금요일 저녁 배포 자제4번은 지킬 수 있을까. 모르겠다. 밤 10시, 퇴근 책상을 정리한다. 에너지 드링크 캔 3개. 과자 봉지 2개. 터미널을 닫는다. 20개 탭. 맥북을 끈다. 아니, 못 끈다. 슬랙 알림 들어야 해서. 슬립 모드로. 집에 간다. 가방에 맥북과 충전기. 지하철에서 슬랙을 확인한다. 습관이다. 새 메시지 없다. 다행이다. 집 도착. 10시 40분. 샤워한다. 침대에 눕는다. 맥북을 옆에 둔다. "내일 아침에 로그 확인해야지." 그런 생각을 하다가 잠든다. 토요일 새벽 2시 슬랙 알림에 깬다. "결제 오류 알림" 눈을 비빈다. 맥북을 연다. 에러율 스파이크. 5분 전부터. "또?" 터미널을 연다. 손이 자동으로 움직인다. ssh production docker logs app -f로그가 흐른다. 에러가 보인다. Error: Payment gateway connection refused외부 결제 게이트웨이 문제다. 우리 쪽 이슈가 아니다. 공지를 올린다. "외부 결제 시스템 장애로 일시적으로 결제가 불가합니다. 복구 중입니다." 거짓말이다. 우리가 복구할 수 있는 게 아니다. 결제사 상태 페이지를 확인한다. "일부 서비스 장애 조치 중". "할 수 있는 게 없네." 맥북을 닫는다. 다시 눕는다. 잠이 안 온다. 월요일 아침 대표가 묻는다. "금요일에 뭐 있었어요?" "배포 장애 있었습니다." "심각했어요?" "2시간 정도 복구했습니다." "다음부턴 조심해요." "네." 조심한다고 안 생긴다. 혼자라서 생기는 거다. 코드 리뷰 없다. 더블체크 없다. 롤백 도와줄 사람 없다. 전부 나다. 기획자가 묻는다. "이번 주에 신규 기능 배포 가능해요?" "지난주 롤백 정리하고 해야 할 것 같은데요." "급한 건데..." "네, 해보겠습니다." 혼자라는 것 풀스택 개발자. 멋있는 말이다. 뭐든 할 수 있다는 뜻. 근데 뭐든 혼자 해야 한다는 뜻이기도 하다. 배포도 혼자. 롤백도 혼자. 장애 대응도 혼자. 실수해도 혼자. 수습도 혼자. 금요일 저녁 7시의 "이번엔 다를 거야"는 항상 거짓말이 된다. 그래도 다음 주 금요일에 또 배포한다. "이번엔 정말 다를 거야." 또 거짓말이겠지.다음 배포는 목요일로 미루기로 했다. 금요일은 너무 위험하다. 근데 목요일도 비슷할 거다.