새 버전을 배포했는데 버그가 있다면? 모든 사용자에게 한 번에 밀어 넣으면 전부 장애를 겪는다.
카나리(Canary)는 일부 트래픽만 새 버전으로 흘려보내 "탄광의 카나리"처럼 이상 징후를 미리 감지하고,
블루-그린(Blue-Green)은 새 버전을 별도 환경에 완전히 띄워둔 뒤 트래픽을 한 번에 전환해
문제가 생기면 즉시 되돌린다. 둘 다 목표는 같다 — 무중단으로, 안전하게 새 버전을 내보내는 것.
인터랙티브 데모
트래픽 분할
안정 버전 v1 90%카나리 v2 10%
요청 흐름 (최근 60건)
v1 요청 / 에러율0 / 0%
v2(카나리) 요청 / 에러율0 / 0%
자동 롤백 임계값에러율 20% 초과 (최소 5건)
배포 설정
배포 로그
환경 구성
사용자 트래픽 100%
→
BLUE (v1)
LIVE
GREEN (v2)
비어 있음
현재 LIVE 환경BLUE (v1)
GREEN 배포 상태비어 있음
헬스체크—
전환 방식
카나리처럼 비율을 서서히 옮기지 않는다.
GREEN이 완전히 준비되면 로드밸런서 설정 한 줄로 트래픽 전부가 순간 이동한다.
문제가 생기면 그 반대 방향으로 한 번 더 순간 이동하면 끝 — 롤백도 즉시.
배포 절차
배포 로그
두 전략, 언제 무엇을
카나리 배포
서서히 트래픽 비율을 늘려가며 검증
일부 사용자만 위험에 노출 (blast radius 작음)
실시간 지표(에러율·지연시간) 관찰이 필수
같은 버전 두 벌을 동시에 운영 → 인프라 복잡도↑
Kubernetes/Istio, Flagger, AWS App Mesh 등에서 지원
블루-그린 배포
한 번에 전체 트래픽을 전환 (all-or-nothing)
배포 전 GREEN에서 충분히 검증 가능
롤백이 즉각적 — 스위치만 되돌리면 끝
동일 규모 환경을 두 벌 유지 → 비용 2배
DB 스키마 등 상태 공유 자원의 하위 호환이 까다로움
핵심 로직 (의사 코드)
# 카나리: 요청마다 가중치 기반으로 버전 선택defroute_canary(canary_pct):
if random() * 100 < canary_pct:
return"v2"# 카나리로return"v1"# 안정 버전으로# 자동 롤백: 카나리 에러율이 임계값을 넘으면 즉시 0%로if v2_requests >= MIN_SAMPLES and v2_error_rate > THRESHOLD:
canary_pct = 0
alert("카나리 에러율 초과 — 자동 롤백")
# 블루-그린: 로드밸런서가 가리키는 대상만 원자적으로 교체defflip(current_live):
return"green"if current_live == "blue"else"blue"
lb.upstream = flip(lb.upstream) # 트래픽 100%가 한 번에 이동
현실에서는
롤링 업데이트와 구분: 카나리·블루-그린은 "구버전 인스턴스를 하나씩 새 버전으로
교체"하는 롤링 업데이트와 다르다. 롤링은 중간에 신구 버전이 섞이지만 트래픽 비율을 의도적으로
제어하지는 않는다.
피처 플래그와의 차이: 배포(코드를 서버에 올리는 것)와 릴리즈(사용자에게 기능을 보이는 것)를
분리하는 것이 피처 플래그다. 카나리·블루-그린은 배포 인프라 수준의 전략이고, 피처 플래그는
코드 수준의 스위치 — 둘을 함께 쓰면 더 세밀하게 제어할 수 있다.
관측 가능성이 전제 조건: 카나리의 자동 판단(에러율·p99 지연시간 등)은 좋은 모니터링
없이는 불가능하다. Flagger, Argo Rollouts 같은 도구가 Prometheus 지표를 보고 자동으로
승격/롤백을 결정한다.
DB 마이그레이션 함정: 블루-그린 전환 순간에도 두 버전이 같은 DB를 볼 수 있어야
한다. 컬럼 삭제·타입 변경처럼 하위 호환이 깨지는 스키마 변경은 여러 배포에 걸쳐
단계적으로(expand-contract) 진행해야 한다.
세션 고정 문제: 카나리 중 같은 사용자가 요청마다 다른 버전에 걸리면 혼란스러울 수
있어, 쿠키·사용자 ID 해시로 같은 사용자는 같은 버전에 계속 붙이는 sticky routing을
쓰기도 한다.