새 버전을 전체 사용자에게 한 번에 배포했습니다. 5분 뒤 에러율이 치솟습니다. 롤백하려는데 "이전 버전이 어디 있죠? 빌드 다시 해야 하나요?"로 또 20분이 흘러갑니다. 그사이 전체 사용자가 장애를 겪습니다. 옆 팀은 같은 위험한 변경을 5% 사용자에게만 먼저 흘렸습니다. 지표가 나빠지자 그 5%만 영향받은 채 1분 만에 되돌렸습니다. 릴리스 전략은 '무엇을 배포하나'가 아니라 '어떻게 내보내고 어떻게 되돌리나'입니다. 같은 코드도 전략에 따라 장애 반경과 복구 속도가 완전히 달라집니다.
- 1블루그린·카나리·롤링 배포의 구조와 롤백 방식을 구분할 수 있다
- 2기능 플래그가 "배포와 노출을 분리"하는 원리를 설명할 수 있다
- 3점진 배포가 관측성·자동 롤백과 결합돼야 함을 설명할 수 있다
- 4상황(위험도·비용·인프라)에 맞는 릴리스 전략을 고를 수 있다
점진 배포 — 장애 반경을 줄인다
한 번에 전부 vs 조금씩 확대
가장 단순한 배포는 '한 번에 전부 교체'지만, 문제가 있으면 전체 사용자가 즉시 영향받습니다. 점진 배포는 이 위험을 줄입니다.
롤링(Rolling): 인스턴스를 하나씩 새 버전으로 교체
[v1][v1][v1][v1] → [v2][v1][v1][v1] → ... → [v2][v2][v2][v2]
장점: 추가 환경 불필요 단점: 두 버전이 잠시 공존(호환성 주의)
카나리(Canary): 새 버전에 소수 트래픽만 → 관찰 → 점진 확대
v2에 5% → (지표 OK) → 25% → 50% → 100%
장점: 이상 시 소수만 영향, 빠른 롤백 단점: 관측성 필수
블루-그린: 두 환경 나란히, 트래픽 한 번에 전환
블루(v1, 현재) ──라우터──▶ 그린(v2, 검증완료)
장점: 전환·롤백 즉시(라우터만) 단점: 두 환경 비용
핵심: 점진 배포는 장애 반경(blast radius) 을 줄이고 롤백을 빠르게 합니다. 단, 카나리·롤링은 [[slo-error-budget]]의 관측성이 있어야 "이상 감지 → 롤백"이 작동합니다.
기능 플래그 — 배포와 노출의 분리
코드는 배포하되, 노출은 스위치로 제어
[[branch-strategy]]에서 잠깐 본 기능 플래그를 제대로 봅니다. 핵심은 배포(코드가 prod에 존재) ≠ 릴리스(사용자에게 노출) 를 분리하는 것입니다.
if (featureFlags.isEnabled("new-checkout", user)) {
// 새 결제 흐름
} else {
// 기존 흐름
}
→ 새 결제 코드를 배포(prod에 존재)하되 플래그 OFF로 숨김
→ 준비되면 ON: 내부직원 → 5% → 전체 점진 노출(카나리와 결합)
→ 문제 발생: 재배포 없이 플래그 OFF로 '즉시' 차단(kill switch)
장점:
- 미완성 기능을 main에 머지·배포해도 안전(Trunk-based 가능케 함).
- 릴리스 타이밍을 코드 배포와 분리 → 마케팅 일정에 맞춰 ON.
- 즉시 롤백: 코드 롤백보다 빠른 플래그 OFF.
- 점진 노출·A/B 테스트: 특정 그룹에만 노출해 실험.
주의: 플래그가 쌓이면 코드가 복잡해지므로(if 분기 누적), 완전히 출시된 플래그는 정리(cleanup) 해야 합니다 — 이는 [[tech-debt-refactoring]]의 부채 항목입니다.
롤백 준비 점검 — 직접 확인
릴리스 전략의 절반은 '되돌릴 수 있는가'입니다. 이전 버전이 보존돼 있고 한 번에 롤백 가능한지 미리 확인합니다(장애 순간엔 늦습니다).
# 쿠버네티스: 배포 이력과 즉시 롤백 가능 여부
kubectl rollout history deployment/app # 리비전 목록
kubectl rollout undo deployment/app # 직전 버전으로 롤백
# 이전 이미지 태그가 레지스트리에 남아 있나(롤백 기준점)
# (남아 있어야 빠른 롤백 가능 — latest만 쓰면 못 돌아감)
# 기능 플래그로 끌 수 있는 기능인가(가장 빠른 롤백)
echo "kill switch 가능 기능 목록 확인"
$ kubectl rollout history deployment/app
REVISION CHANGE-CAUSE
3 app:v1.2.0
4 app:v1.2.1 ← 현재. 문제 시 'undo'로 3(v1.2.0)으로 1분 내 복귀
→ 이전 리비전 보존됨 + 이미지 태그 불변 → 롤백 안전
kubectl rollout history deployment/app- rollout history에 이전 리비전이 남아 있으면 → rollout undo로 즉시 롤백 가능(안전). 이력이 없거나 latest 태그만 쓰면 "되돌릴 곳이 없는" 위험 상태
- 이미지 태그가 불변(v1.2.0처럼 고정)인지 확인 — latest를 덮어쓰면 같은 태그가 다른 코드라 롤백이 무의미. [[semantic-versioning]]의 불변 태그가 전제
- 카나리/롤링이면 "무슨 지표가 X 넘으면 롤백"을 사전 정의했는지 확인 — 기준 없으면 점진 배포의 의미가 없다. 가능하면 자동 롤백 연결
- 기능 플래그로 끌 수 있는 변경이면 그게 가장 빠른 롤백(재배포 불필요) — 위험 기능은 플래그 뒤에 두는 것을 릴리스 계획에 포함
상황: 새 버전을 전체에 한 번에 배포했는데 장애가 났습니다. 롤백하려니 "이전 이미지를 latest로 덮어써서" 되돌릴 대상이 없고, 재빌드에 20분이 걸려 그동안 전체 사용자가 장애를 겪습니다.
원인: 두 가지 실패가 겹쳤습니다. (1) 일괄 배포로 장애 반경이 100%, (2) 가변 태그(latest) 사용으로 이전 버전이 보존되지 않아 롤백 불가. 릴리스 전략과 버저닝이 모두 부재했습니다.
진단 — 사전 점검(배포 전):
□ 이전 버전 이미지/산출물이 불변 태그로 보존돼 있는가?
□ 한 번에 전체가 아니라 점진(카나리/롤링)으로 내보낼 수 있는가?
□ 롤백 명령이 1줄로 준비돼 있는가? (rollout undo 등)
□ 무슨 지표가 나빠지면 롤백할지 기준이 있는가?
해결: (1) 불변 태그(v1.2.0)로 모든 버전을 레지스트리에 보존([[semantic-versioning]]). (2) 위험 변경은 카나리로 5%부터, 관측성으로 지표를 보며 확대. (3) 롤백을 1줄 명령 또는 기능 플래그 OFF로 준비. "어떻게 배포하나"만큼 "어떻게 되돌리나"를 항상 먼저 설계합니다 — 롤백 계획 없는 배포는 도박입니다.
인프라/SRE로서 릴리스 전략은 당신의 핵심 설계 영역입니다 — 카나리/블루그린/롤링을 배포 도구(Argo Rollouts·Spinnaker·K8s)로 구현하고, [[slo-error-budget]]의 지표와 연결해 "에러율이 임계 초과 시 자동 롤백"을 건립니다. 모든 배포에 '되돌리는 길'(불변 태그·rollout undo·기능 플래그 kill switch)을 미리 깔아두는 것이 SRE의 제1원칙입니다. PM은 기능 플래그로 '배포 ≠ 노출'을 활용해 릴리스 타이밍을 마케팅·실험 일정에 맞추고, 카나리로 위험한 변경을 데이터 기반으로 점진 출시합니다. 좋은 릴리스 전략은 장애를 없애는 게 아니라, 장애의 반경과 시간을 작게 만드는 것입니다.
다음 모듈에서는 이 모든 배포의 전제가 되는 '버전을 어떻게 매기고 호환성을 관리하는가' — 시맨틱 버저닝을 다룹니다.