요청을 한 건도 흘리지 않고 인스턴스를 교체하는 절차.
순서
신버전
- ① 기동 · 워밍업
- ② 준비(readiness) 통과 후에야 트래픽 투입
구버전
- ③ 헬스체크를 실패로 전환
- ④ LB 가 이 서버를 뺄 때까지 기다린다 ← 가장 자주 빠뜨린다
- ⑤ 새 요청 수용 중단
- ⑥ 처리 중인 요청 완료 대기 (grace period)
- ⑦ 종료
④를 빠뜨리면
헬스체크 실패 → LB 가 알아채기까지 시차가 있다 그 시차 동안 새 요청이 계속 오는데 이미 닫았다면 전부 실패한다
대기 시간 ≥ 헬스체크 주기 × 실패 임계 + 여유
- 예) 주기 5초 · 실패 2회 → 최소 10초 + 여유
"배포할 때만 5xx 가 잠깐 튄다" 의 대부분이 이것이다
②를 빠뜨리면
기동 직후에는 커넥션 풀·캐시가 비어 있고 JIT 도 안 데워져 있다 준비 전에 트래픽이 들어오면 배포 직후에만 5xx·지연이 튄다
- 준비 상태(readiness)와 살아있음(liveness)을 구분한다
- 필요하면 워밍업 요청을 스스로 돌린 뒤 준비 완료를 알린다
정지 시그널
컨테이너 기본 흐름
- SIGTERM → (terminationGracePeriodSeconds) → SIGKILL
grace period 가 처리 시간보다 짧으면 결국 잘린다
- 가장 긴 요청의 처리 시간 + 여유로 잡는다
- 배치성 긴 작업은 그 경로를 별도 워커로 분리하는 편이 낫다
nginx 는 SIGTERM 이 '즉시 종료' 다
- STOPSIGNAL SIGQUIT 를 지정하거나 종료 훅에서 quit 를 보낸다
- 그대로 두면 배포마다 진행 중 요청이 끊긴다
앞단 리로드로 하는 전환
nginx -t && nginx -s reload
- 검증 실패면 아무것도 바뀌지 않는다 (원자적)
- 배포 스크립트는 반드시 -t 를 앞에 둔다
- 성공 후에도 access log 의 상태 코드 분포를 잠시 지켜본다
확인 방법
배포 중에 부하를 걸고 실패율을 본다
- 5xx 가 0 인가
- 499 가 늘지 않는가 (클라이언트가 포기하고 있다는 뜻)
- p99 가 튀지 않는가
한 번이라도 실측하지 않으면 '무중단이라고 믿는 배포' 가 된다
배포 전략별 차이
-
롤링 — 인스턴스를 순차 교체. 자원 추가가 적다
- 구·신 버전이 공존한다 → 호환성이 전제다
-
블루-그린 — 전체를 새로 띄우고 한 번에 전환. 롤백이 빠르다
- 자원이 두 배 든다
-
카나리 — 일부 트래픽만 새 버전으로. 위험을 줄인다
- 지표 비교 체계가 있어야 의미가 있다
-
앞단에서 보면 셋 다 'upstream 목록을 어떻게 바꾸느냐' 의 차이다
구·신 공존이 만드는 문제
롤링·카나리에서는 두 버전이 동시에 돈다
깨지는 지점
- DB 스키마 — 컬럼을 지우면 구버전이 죽는다
- 추가 → 양쪽 지원 → 제거 의 3단계로 나눈다 (확장-수축)
- 세션·캐시 직렬화 형식이 바뀌면 서로 못 읽는다
- API 응답 필드를 지우면 구버전 클라이언트가 깨진다
"배포는 무중단인데 데이터가 깨진다" 가 여기서 나온다
면접 함정
- ❌ "SIGTERM을 처리하면 무중단" → LB에서 빠지는 시간을 기다리지 않으면 그 사이 요청이 실패한다.
- ❌ "헬스체크만 통과하면 트래픽을 받아도 된다" → 워밍업 전에는 느리거나 실패한다.