infra
Platform

모듈 맵

[SW Eng] 릴리스 전략 — 블루그린·카나리·롤링·기능 플래그

0 / 38 완료

펼치기
0 / 38 완료0%

PM·SRE를 위한 소프트웨어 엔지니어링 · 16 / 38

[SW Eng] 릴리스 전략 — 블루그린·카나리·롤링·기능 플래그

프로덕션에 새 버전을 '어떻게' 내보낼지 — 점진 배포로 위험을 줄이고 빠르게 롤백하는 전략을 PM·인프라 관점에서 정리합니다

🚨INCIDENT ALERT
HIGH

새 버전을 전체 사용자에게 한 번에 배포했습니다. 5분 뒤 에러율이 치솟습니다. 롤백하려는데 "이전 버전이 어디 있죠? 빌드 다시 해야 하나요?"로 또 20분이 흘러갑니다. 그사이 전체 사용자가 장애를 겪습니다. 옆 팀은 같은 위험한 변경을 5% 사용자에게만 먼저 흘렸습니다. 지표가 나빠지자 그 5%만 영향받은 채 1분 만에 되돌렸습니다. 릴리스 전략은 '무엇을 배포하나'가 아니라 '어떻게 내보내고 어떻게 되돌리나'입니다. 같은 코드도 전략에 따라 장애 반경과 복구 속도가 완전히 달라집니다.

이번 챕터에서 배울 것
  • 1블루그린·카나리·롤링 배포의 구조와 롤백 방식을 구분할 수 있다
  • 2기능 플래그가 "배포와 노출을 분리"하는 원리를 설명할 수 있다
  • 3점진 배포가 관측성·자동 롤백과 결합돼야 함을 설명할 수 있다
  • 4상황(위험도·비용·인프라)에 맞는 릴리스 전략을 고를 수 있다

점진 배포 — 장애 반경을 줄인다

💡개념

한 번에 전부 vs 조금씩 확대

가장 단순한 배포는 '한 번에 전부 교체'지만, 문제가 있으면 전체 사용자가 즉시 영향받습니다. 점진 배포는 이 위험을 줄입니다.

배포 전략 3종 — 롤링은 인스턴스를 하나씩 교체(추가 환경 불필요, 두 버전 공존), 카나리는 소수 트래픽(5→25→50→100%)으로 관찰하며 확대(빠른 롤백, 관측성 필수), 블루-그린은 두 환경을 라우터로 한 번에 전환(즉시 전환·롤백, 두 환경 비용)확대

핵심: 점진 배포는 장애 반경(blast radius) 을 줄이고 롤백을 빠르게 합니다. 단, 카나리·롤링은 SLO·에러버짓·포스트모템의 관측성이 있어야 "이상 감지 → 롤백"이 작동합니다.

릴리스 전략 비교 — 블루그린·카나리·롤링확대

위 그림처럼 블루그린은 즉각 전환·롤백이 강점이지만 환경 비용이 2배고, 카나리는 소수 영향으로 데이터 기반 확대가 가능하지만 관측성 인프라가 필수이며, 롤링은 추가 환경 없이 점진 교체하지만 두 버전이 잠시 공존합니다.

기능 플래그 — 배포와 노출의 분리

💡개념

코드는 배포하되, 노출은 스위치로 제어

브랜치 전략에서 잠깐 본 기능 플래그를 제대로 봅니다. 핵심은 배포(코드가 prod에 존재) ≠ 릴리스(사용자에게 노출) 를 분리하는 것입니다.

TEXT
if (featureFlags.isEnabled("new-checkout", user)) {
  // 새 결제 흐름
} else {
  // 기존 흐름
}

→ 새 결제 코드를 배포(prod에 존재)하되 플래그 OFF로 숨김
→ 준비되면 ON: 내부직원 → 5% → 전체 점진 노출(카나리와 결합)
→ 문제 발생: 재배포 없이 플래그 OFF로 '즉시' 차단(kill switch)

장점:

  • 미완성 기능을 main에 머지·배포해도 안전(Trunk-based 가능케 함).
  • 릴리스 타이밍을 코드 배포와 분리 → 마케팅 일정에 맞춰 ON.
  • 즉시 롤백: 코드 롤백보다 빠른 플래그 OFF.
  • 점진 노출·A/B 테스트: 특정 그룹에만 노출해 실험.

주의: 플래그가 쌓이면 코드가 복잡해지므로(if 분기 누적), 완전히 출시된 플래그는 정리(cleanup) 해야 합니다 — 이는 기술 부채와 리팩터링의 부채 항목입니다.

기능 플래그 — 배포와 노출 분리확대

위 그림처럼 기능 플래그는 코드를 prod에 배포하되 플래그 OFF로 숨겨두고, 준비가 됐을 때 내부→5%→전체로 점진 노출하며, 문제 시 재배포 없이 즉시 kill switch로 차단합니다.

어떤 릴리스 전략을 쓸까
위험 큰 변경, 실시간 지표로 검증하며 내보내고 싶다카나리 + 관측성5%→점진 확대, 자동 롤백 연결
빠른 전환·즉시 롤백이 중요, 두 환경 비용 감당 가능블루-그린라우터 전환
추가 환경 없이 무중단 점진 교체롤링버전 공존 호환성 확인
배포와 노출 시점을 분리, 즉시 끄고 싶다기능 플래그kill switch·A/B·점진 노출

롤백 준비 점검 — 직접 확인

1롤백 가능성과 이전 버전 보존 확인

릴리스 전략의 절반은 '되돌릴 수 있는가'입니다. 이전 버전이 보존돼 있고 한 번에 롤백 가능한지 미리 확인합니다(장애 순간엔 늦습니다).

Kubernetes
# 쿠버네티스: 배포 이력과 즉시 롤백 가능 여부
kubectl rollout history deployment/app          # 리비전 목록
kubectl rollout undo deployment/app             # 직전 버전으로 롤백

# 이전 이미지 태그가 레지스트리에 남아 있나(롤백 기준점)
# (남아 있어야 빠른 롤백 가능 — latest만 쓰면 못 돌아감)

# 기능 플래그로 끌 수 있는 기능인가(가장 빠른 롤백)
echo "kill switch 가능 기능 목록 확인"
OUTPUT
$ 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를 덮어쓰면 같은 태그가 다른 코드라 롤백이 무의미. 시맨틱 버저닝의 불변 태그가 전제
  • 카나리/롤링이면 "무슨 지표가 X 넘으면 롤백"을 사전 정의했는지 확인 — 기준 없으면 점진 배포의 의미가 없다. 가능하면 자동 롤백 연결
  • 기능 플래그로 끌 수 있는 변경이면 그게 가장 빠른 롤백(재배포 불필요) — 위험 기능은 플래그 뒤에 두는 것을 릴리스 계획에 포함

카나리 배포 — 점진 트래픽 확대와 자동 롤백확대

위 그림처럼 카나리 배포는 5% → 25% → 50% → 100% 순으로 트래픽을 확대하며, 에러율·응답시간 등 지표가 임계를 넘으면 그 비율만 영향받은 채 즉시 v1으로 롤백합니다.

상황: 새 버전을 전체에 한 번에 배포했는데 장애가 났습니다. 롤백하려니 "이전 이미지를 latest로 덮어써서" 되돌릴 대상이 없고, 재빌드에 20분이 걸려 그동안 전체 사용자가 장애를 겪습니다.

원인: 두 가지 실패가 겹쳤습니다. (1) 일괄 배포로 장애 반경이 100%, (2) 가변 태그(latest) 사용으로 이전 버전이 보존되지 않아 롤백 불가. 릴리스 전략과 버저닝이 모두 부재했습니다.

진단 — 사전 점검(배포 전):

TEXT
□ 이전 버전 이미지/산출물이 불변 태그로 보존돼 있는가?
□ 한 번에 전체가 아니라 점진(카나리/롤링)으로 내보낼 수 있는가?
□ 롤백 명령이 1줄로 준비돼 있는가? (rollout undo 등)
□ 무슨 지표가 나빠지면 롤백할지 기준이 있는가?

해결: (1) 불변 태그(v1.2.0)로 모든 버전을 레지스트리에 보존(시맨틱 버저닝). (2) 위험 변경은 카나리로 5%부터, 관측성으로 지표를 보며 확대. (3) 롤백을 1줄 명령 또는 기능 플래그 OFF로 준비. "어떻게 배포하나"만큼 "어떻게 되돌리나"를 항상 먼저 설계합니다 — 롤백 계획 없는 배포는 도박입니다.

심화 — 롤백을 막는 것은 코드가 아니라 데이터

💡개념

심화: 두 버전이 공존하는 시간 — 점진 배포의 숨은 계약

카나리·롤링·rollout undo를 갖추면 안전해 보이지만, 이 전략들은 모두 구버전과 신버전이 동시에 살아 있는 시간을 만듭니다. 그 시간을 견디는 호환성이 없으면, 위험을 줄이려던 전략이 오히려 사고를 만듭니다.

  • N-1 호환성: 롤링·카나리 동안 v1과 v2는 같은 DB·캐시·세션 저장소를 공유합니다. 세션 직렬화 포맷을 바꾸면 v2가 저장한 세션을 v1이 못 읽어, '배포 중에만 나타났다 사라지는' 간헐 오류가 됩니다. 요청마다 다른 버전에 떨어질 수 있다는 전제로 모든 변경을 설계해야 합니다.
  • rollout undo가 못 되돌리는 것: 코드 리비전은 1분 만에 돌아가도, 이미 실행된 DB 마이그레이션·큐에 쌓인 신형 메시지·사용자 기기에 배포된 모바일 앱은 돌아오지 않습니다. 롤백 계획은 코드만이 아니라 데이터·클라이언트까지 포함해야 완성입니다.
  • 파괴적 변경은 여러 릴리스로 쪼갭니다(expand/contract): 컬럼 rename·삭제처럼 구버전을 깨뜨리는 변경은 한 릴리스에 하지 않습니다 — 먼저 추가하고(expand), 양쪽을 함께 지원하다가, 전 인스턴스가 신버전이 된 다음 릴리스에서 제거(contract)합니다.
  • kill switch의 맹점: 플래그 OFF로 돌아갈 구 경로를 몇 주간 아무도 타지 않았다면, 그 경로는 이미 다른 변경과 어긋나 있을 수 있습니다 — 끄는 순간이 두 번째 장애가 되기도 합니다. 플래그 시스템 자체가 죽었을 때 각 플래그가 어느 쪽으로 동작할지(기본값)까지가 릴리스 설계의 일부입니다.

점진 배포의 성숙도는 배포 도구가 아니라, 변경을 '공존 가능한 조각'으로 쪼개는 팀의 습관에서 드러납니다.

상황: 신버전을 카나리 5%로 내보내기 시작한 지 몇 분 만에, 에러율이 5%가 아니라 거의 전 트래픽에서 급등합니다. 카나리를 즉시 0%로 되돌렸는데도 에러가 계속됩니다 — 롤백을 했는데 장애가 끝나지 않는 상황입니다.

원인: 신버전 배포에 포함된 DB 마이그레이션이 컬럼명을 rename했습니다. 코드는 5%만 신버전이지만 DB는 100% 공유라 마이그레이션은 전역 적용 — 구버전 95%가 존재하지 않는 옛 컬럼을 조회하며 즉사한 것입니다. 카나리 롤백은 코드만 되돌릴 뿐 스키마는 그대로라 에러가 멈추지 않습니다. 파괴적 마이그레이션 앞에서 카나리 5%는 사실상 100% 배포였습니다.

진단:

Kubernetes
kubectl logs deploy/app --since=10m | grep -c 'column user_name does not exist'
# 에러가 신버전이 아니라 '구버전' pod에서 대량 발생 — 코드가 아니라 공유 자원 의심
psql -c '\d users'    # user_name → username rename 확인
# 마이그레이션 적용 시각 == 에러 시작 시각 → 확정

해결: 1순위는 코드 롤백이 아니라 스키마 역마이그레이션(컬럼명 복구)으로 구버전을 살리는 것입니다. 재작업은 expand/contract로 진행합니다: 새 컬럼 추가 → 신버전이 양쪽에 쓰기 → 백필 → 전 인스턴스 전환 확인 후 다음 릴리스에서 옛 컬럼 제거. 원칙은 하나입니다 — 마이그레이션은 항상 직전 버전 코드와 호환되게. 배포 전 체크리스트에 "이 릴리스에 구버전을 깨뜨리는 스키마 변경이 있는가"를 넣고, 있다면 점진 배포가 아니라 릴리스 분할부터 합니다.

💼
실무 맥락
현업 패턴

인프라/SRE로서 릴리스 전략은 당신의 핵심 설계 영역입니다 — 카나리/블루그린/롤링을 배포 도구(Argo Rollouts·Spinnaker·K8s)로 구현하고, SLO·에러버짓·포스트모템의 지표와 연결해 "에러율이 임계 초과 시 자동 롤백"을 건립니다. 모든 배포에 '되돌리는 길'(불변 태그·rollout undo·기능 플래그 kill switch)을 미리 깔아두는 것이 SRE의 제1원칙입니다. PM은 기능 플래그로 '배포 ≠ 노출'을 활용해 릴리스 타이밍을 마케팅·실험 일정에 맞추고, 카나리로 위험한 변경을 데이터 기반으로 점진 출시합니다. 좋은 릴리스 전략은 장애를 없애는 게 아니라, 장애의 반경과 시간을 작게 만드는 것입니다.

다음 모듈에서는 이 모든 배포의 전제가 되는 '버전을 어떻게 매기고 호환성을 관리하는가' — 시맨틱 버저닝을 다룹니다.

실전 랩으로 손에 익히기: 릴리스 전략 실습 — 블루그린·카나리·롤링과 기능 플래그를 상황에 맞게 고르고 지표 게이트를 설계합니다.

지식 확인

퀴즈 — 8문제

Q1

카나리 배포(Canary)의 핵심 아이디어는?

Q2

블루-그린 배포의 특징으로 옳은 것은?

Q3

기능 플래그(feature flag)가 '배포'와 '노출'을 분리한다는 의미는?

Q4

점진 배포(카나리/롤링)가 효과를 보려면 반드시 함께 있어야 하는 것은?

Q5

점진 배포에서 카나리가 문제를 보일 때 빠르게 대응하려면 무엇이 준비돼 있어야 하나?

Q6

블루-그린과 카나리 배포의 차이로 옳은 것은?

Q7

[심화] 카나리·롤링 배포는 구버전과 신버전이 동시에 살아 있는 시간을 만든다. 이때 지켜야 할 핵심 원칙은?

Q8

[심화] 카나리를 5%로 제한했는데 에러율이 전체에서 치솟고, 카나리를 0%로 되돌려도 멈추지 않는다. 로그를 보니 에러가 '구버전' pod에서 대량 발생한다. 원인과 처방은?

0 / 8 답변

🧪 실습으로 확인하기

릴리스 전략 — 블루그린·카나리·롤링과 기능 플래그

고급

배포 리스크(롤백 속도 요구·트래픽 규모·상태 유지 여부·DB 마이그레이션 동반)를 진단해 블루그린 / 카나리 / 롤링 중 하나를 근거 있게 고르고, 에러율·지연 지표 게이트로 자동 롤백을 설계하며, 기능 플래그로 "배포"와 "릴리스"를 분리한다.

55📋 3단계💻 직접 환경
실습 시작하기 →

이것도 배워보세요