
Blue-Green / Canary 배포: 서비스를 중단 없이 업데이트하는 기술
\"점검 안내: 오전 2시~6시 서비스 중단\" — 2026년에도 이런 공지를 보내야 할까? Rolling, Blue-Green, Canary 배포 전략의 원리부터 AWS 구현, 실전 사례까지. 서비스를 멈추지 않고 업데이트하는 방법을 알아본다.

\"점검 안내: 오전 2시~6시 서비스 중단\" — 2026년에도 이런 공지를 보내야 할까? Rolling, Blue-Green, Canary 배포 전략의 원리부터 AWS 구현, 실전 사례까지. 서비스를 멈추지 않고 업데이트하는 방법을 알아본다.
새벽 2시. 서버실 형광등 아래에서 엔지니어 세 명이 긴장한 얼굴로 모니터를 바라본다. 한 명이 "배포 시작합니다"라고 말하고, 서버를 내린다. 그 순간부터 시계와의 싸움이 시작된다. 4시간 안에 새 버전을 올리고, 테스트하고, 문제가 없는지 확인해야 한다. 만약 뭔가 잘못되면? 다시 이전 버전으로 되돌려야 한다. 시간은 오전 6시까지밖에 없다.
2026년인데, 왜 아직도 이런 일이 벌어질까?
이유는 간단하다. 배포 = 서비스 중단이라는 공식을 깨지 못했기 때문이다.
하지만 넷플릭스는 하루에 수천 번 배포한다. 아마존은 평균 11.7초마다 코드를 프로덕션에 올린다. 사용자는 전혀 눈치채지 못한다. 어떻게?
답은 배포 전략(Deployment Strategy)에 있다. 이 글에서는 서비스를 한 번도 멈추지 않고 업데이트하는 핵심 기술 — Rolling, Blue-Green, Canary 배포 — 의 원리부터 실전 구현까지 풀어본다.
전통적인 배포(Recreate 또는 Big Bang 배포)는 단순하다. 기존 서버를 전부 내리고, 새 버전을 전부 올린다. 마치 가게를 닫고, 인테리어를 바꾸고, 다시 여는 것과 같다.
이 방식의 문제점은 명확하다:
현대 소프트웨어 개발에서 배포 전략은 "선택"이 아니라 생존 전략이다. 그래서 업계는 수십 년에 걸쳐 서비스를 멈추지 않고 업데이트하는 방법을 발전시켜 왔다.

Rolling 배포는 가장 직관적인 무중단 배포 방식이다. 서버(인스턴스)를 한 대씩 또는 몇 대씩 순서대로 교체한다. 전체를 한꺼번에 내리지 않으므로, 나머지 서버들이 트래픽을 계속 처리한다.
비유하자면: 도로 위의 차선을 하나씩 보수하는 것과 같다. 전체 도로를 폐쇄하지 않고, 한 차선씩 작업하면서 나머지 차선으로 교통을 유지한다.
서버 4대가 v1을 실행하고 있다고 가정하자.
배포 중에는 v1과 v2가 동시에 존재한다. 이것이 Rolling 배포의 가장 큰 특징이자 주의점이다.
예를 들어, 쇼핑몰 API에서 v1은 장바구니 응답에 totalPrice를 보내고, v2는 totalAmount로 필드명을 바꿨다면? Step 2 시점에는 서버 A(v2)와 서버 B~D(v1)가 공존한다. 프론트엔드가 두 형식을 모두 처리하지 못하면, 일부 사용자에게 에러가 발생한다.
이것을 호환성(backward compatibility) 문제라고 하며, Rolling 배포에서 가장 신경 써야 하는 부분이다.

Blue-Green 배포는 완전히 동일한 두 세트의 프로덕션 환경을 유지하는 전략이다. 한쪽(Blue)은 현재 라이브 버전, 다른 쪽(Green)은 새 버전을 준비하는 용도다.
비유하자면: 연극 무대가 두 개인 극장이다. 한쪽 무대에서 공연이 진행되는 동안, 다른 무대에서 다음 공연을 세팅한다. 준비가 끝나면 관객석을 180도 돌려서 새 무대를 보여준다. 관객은 전환이 일어나는 순간을 거의 느끼지 못한다.
핵심은 트래픽 라우팅의 분리다. 서버를 내리는 것이 아니라, 로드밸런서가 가리키는 방향만 바꾼다. 라우팅 변경은 밀리초 단위로 일어나므로, 사용자 입장에서 다운타임은 0에 가깝다.
# Green 타겟 그룹으로 트래픽 100% 전환
aws elbv2 modify-listener \
--listener-arn arn:aws:elasticloadbalancing:ap-northeast-2:...:listener/... \
--default-actions Type=forward,TargetGroupArn=arn:aws:...:targetgroup/green-tg/...
# 문제 발생 시 즉시 Blue로 롤백
aws elbv2 modify-listener \
--listener-arn arn:aws:elasticloadbalancing:ap-northeast-2:...:listener/... \
--default-actions Type=forward,TargetGroupArn=arn:aws:...:targetgroup/blue-tg/...

Canary 배포는 새 버전을 극소수의 사용자에게 먼저 노출하고, 문제가 없으면 점진적으로 전체에 확대하는 전략이다.
이름의 유래는 탄광의 카나리아새(canary in a coal mine)다. 과거 광부들은 독성 가스를 감지하기 위해 카나리아를 탄광에 먼저 보냈다. 카나리아가 무사하면 사람이 들어갔다. 마찬가지로, 소수의 트래픽으로 새 버전을 먼저 "탐지"하고, 안전하면 전체로 확대한다.
Canary 배포의 핵심 가치는 자동화된 의사결정이다. 사람이 모니터를 뚫어져라 쳐다보며 "이거 괜찮은 것 같은데..."라고 판단하는 것이 아니라, 미리 정의한 메트릭 기준에 따라 시스템이 자동으로 진행/롤백을 결정한다.
canary:
steps:
- setWeight: 5
- pause: { duration: 5m }
- analysis:
metrics:
- name: error-rate
threshold: 0.1 # 에러율 0.1% 초과 시 롤백
- name: latency-p99
threshold: 500 # p99 레이턴시 500ms 초과 시 롤백
- name: success-rate
threshold: 99.9 # 성공률 99.9% 미만 시 롤백
- setWeight: 25
- pause: { duration: 10m }
- analysis: ...
- setWeight: 50
- pause: { duration: 10m }
- setWeight: 100
A/B 테스트와 Canary 배포는 둘 다 "일부 사용자에게 다른 버전을 보여준다"는 점에서 비슷해 보인다. 하지만 목적이 완전히 다르다.
| 구분 | Canary 배포 | A/B 테스트 |
|---|---|---|
| 목적 | 안전한 릴리즈 | 비즈니스 실험 |
| 핵심 질문 | "이 버전이 안정적인가?" | "어떤 버전이 전환율이 높은가?" |
| 측정 메트릭 | 에러율, 레이턴시, CPU 사용률 | 클릭률, 전환율, 매출 |
| 트래픽 비율 | 5% → 점진적 확대 | 50:50 (통계적 유의성 확보) |
| 사용자 고정 | 불필요 (랜덤 라우팅) | 필수 (같은 사용자 = 같은 버전) |
| 종료 조건 | 기술 메트릭 정상 → 100% 전환 | 통계적 유의성 확보 → 우승 버전 선택 |
| 담당 팀 | 엔지니어링/DevOps | 프로덕트/마케팅/데이터 |
Canary는 "이 코드가 프로덕션에서 안전한가?"를 확인하고, A/B 테스트는 "어떤 디자인/기능이 비즈니스에 더 유리한가?"를 확인한다.
실무에서는 이 둘을 결합하기도 한다. 새 기능을 Canary로 안전하게 배포한 후, Feature Flag으로 A/B 테스트를 실행하는 식이다. 이 때 Feature Flag이 핵심 역할을 한다.
Feature Flag(기능 플래그, Feature Toggle이라고도 한다)은 코드를 배포하는 것과 기능을 활성화하는 것을 분리하는 기법이다.
쉽게 말하면: 가게에 새 메뉴판을 설치하되, 종이로 가려 놓는 것이다. 메뉴판(코드)은 이미 배포됐지만, 손님(사용자)은 볼 수 없다. 준비가 되면 종이(플래그)만 벗기면 된다.
# 기능 플래그 확인
if feature_flags.is_enabled("new-checkout-flow", user_id=user.id):
# 새로운 결제 플로우
return new_checkout_handler(request)
else:
# 기존 결제 플로우
return legacy_checkout_handler(request)
Feature Flag은 단독으로도 유용하지만, 배포 전략과 결합하면 강력해진다.
이 조합의 장점:
여기까지 세 가지 핵심 배포 전략을 살펴봤다. 이제 한눈에 비교해 보자.
| 항목 | Rolling | Blue-Green | Canary |
|---|---|---|---|
| 다운타임 | 없음 | 없음 | 없음 |
| 배포 속도 | 느림 (순차 교체) | 빠름 (순간 전환) | 느림 (단계적 확대) |
| 롤백 속도 | 느림 (역순 교체) | 즉시 (라우팅 전환) | 빠름 (트래픽 비율 복원) |
| 리스크 | 중간 (점진적이지만 전체 대상) | 낮음 (전환 전 충분한 테스트) | 최소 (소수 트래픽만 노출) |
| 인프라 비용 | 최소 (추가 서버 불필요) | 높음 (2배 환경) | 중간 (소수 추가 인스턴스) |
| 구현 복잡도 | 낮음 | 중간 | 높음 (메트릭 + 자동화) |
| v1/v2 공존 | 있음 (배포 중) | 없음 (순간 전환) | 있음 (단계 진행 중) |
| 실제 트래픽 검증 | 제한적 | 불가 (전환 전 내부 테스트만) | 가능 (핵심 장점) |
| 대표 사용처 | ECS 기본, K8s 기본 | AWS Elastic Beanstalk, 금융 | Netflix, Google, 대형 SaaS |
하나만 선택해야 하는 것은 아니다. 실무에서는 이 전략들을 조합한다. 예를 들어:
이론을 알았으니, 실제로 AWS에서 어떻게 구현하는지 살펴보자. AWS는 각 배포 전략을 위한 도구를 이미 제공하고 있다.
ECS(Elastic Container Service)는 Rolling 배포를 기본 배포 방식으로 제공한다. 별도 설정 없이 바로 사용할 수 있다.
{
"serviceName": "my-web-app",
"desiredCount": 4,
"deploymentConfiguration": {
"minimumHealthyPercent": 50,
"maximumPercent": 200
},
"deploymentController": {
"type": "ECS"
}
}
minimumHealthyPercent: 50 → 배포 중에도 최소 2대(4대의 50%)는 항상 정상 유지maximumPercent: 200 → 배포 중 최대 8대(4대의 200%)까지 동시 실행 가능ECS는 자동으로 새 태스크를 시작하고, 헬스 체크를 통과하면 이전 태스크를 종료한다. 이것만으로도 무중단 Rolling 배포가 완성된다.
ALB(Application Load Balancer)의 가중치 타겟 그룹(Weighted Target Group)을 사용하면 Blue-Green과 Canary 배포를 모두 구현할 수 있다.
# Canary: v2에 5% 트래픽 할당
aws elbv2 modify-rule \
--rule-arn $RULE_ARN \
--actions '[
{
"Type": "forward",
"ForwardConfig": {
"TargetGroups": [
{"TargetGroupArn": "'$BLUE_TG_ARN'", "Weight": 95},
{"TargetGroupArn": "'$GREEN_TG_ARN'", "Weight": 5}
]
}
}
]'
# 안정 확인 후 50:50으로 확대
aws elbv2 modify-rule \
--rule-arn $RULE_ARN \
--actions '[
{
"Type": "forward",
"ForwardConfig": {
"TargetGroups": [
{"TargetGroupArn": "'$BLUE_TG_ARN'", "Weight": 50},
{"TargetGroupArn": "'$GREEN_TG_ARN'", "Weight": 50}
]
}
}
]'
# 최종 전환: v2로 100%
aws elbv2 modify-rule \
--rule-arn $RULE_ARN \
--actions '[
{
"Type": "forward",
"ForwardConfig": {
"TargetGroups": [
{"TargetGroupArn": "'$GREEN_TG_ARN'", "Weight": 100}
]
}
}
]'
CodeDeploy는 AWS의 공식 배포 자동화 서비스다. ECS, EC2, Lambda에 대해 Blue-Green 및 Canary 배포를 코드 한 줄 없이 설정할 수 있다.
version: 0.0
Resources:
- TargetService:
Type: AWS::ECS::Service
Properties:
TaskDefinition: "arn:aws:ecs:ap-northeast-2:...:task-definition/my-app:2"
LoadBalancerInfo:
ContainerName: "my-app"
ContainerPort: 8080
PlatformVersion: "LATEST"
Hooks:
- BeforeAllowTraffic: "arn:aws:lambda:...:function:smoke-test"
- AfterAllowTraffic: "arn:aws:lambda:...:function:integration-test"
BeforeAllowTraffic 훅에서 Lambda를 실행하여 새 버전의 smoke test를 자동으로 수행한다. 테스트가 실패하면 배포를 자동으로 중단하고 롤백한다.
Netflix는 Canary 배포를 가장 정교하게 운영하는 기업 중 하나다. Spinnaker라는 오픈소스 배포 플랫폼을 직접 만들어 공개했다.
Netflix의 Canary 분석 시스템 Kayenta는 단순히 "에러율이 높은가?"만 보지 않는다. 통계적 가설 검정(statistical hypothesis testing)을 사용한다.
Netflix Canary 배포의 핵심 원칙:
Amazon은 One-Box 배포라는 독자적인 Canary 변형을 사용한다. 전체 리전의 서버 중 딱 한 대(one box)에만 새 버전을 배포하고, 그 한 대의 메트릭을 나머지 서버들과 비교한다.
Amazon이 이 방식을 사용하는 이유: 글로벌 규모에서의 안전. 전 세계 수십 개 리전에 동시에 배포하면, 문제 발생 시 영향 범위가 너무 크다. One-Box → Regional → Global의 3단계 확산으로, 문제를 가장 이른 시점에 가장 작은 범위에서 잡는다.
배포 전략을 설명할 때 흔히 빠지는 것이 있다. 데이터베이스다.
애플리케이션 서버는 여러 대를 띄울 수 있고, 트래픽을 나눌 수 있지만, 데이터베이스는 보통 하나다. v1과 v2가 공존하는 Rolling/Canary 배포 중에 DB 스키마가 바뀌면 어떻게 될까?
v1은 user_name 컬럼을 사용하고, v2는 username으로 변경했다고 가정하자.
DB를 v2에 맞게 바꾸면 v1이 깨지고, v1에 맞게 놔두면 v2가 깨진다. Blue-Green 배포라면 순간 전환이므로 이 문제가 상대적으로 적지만, Rolling과 Canary에서는 심각하다.
DB 스키마 변경은 3단계로 나누어 진행한다.
이 패턴의 핵심: DB 변경은 코드 배포보다 최소 한 단계 앞서야 한다. 코드가 v1 → v2로 바뀌기 전에, DB는 이미 v1과 v2를 모두 지원하는 상태여야 한다.
"어떤 전략이 가장 좋은가?"라는 질문에 정답은 없다. 팀의 상황에 따라 다르다.
| 팀 상황 | 추천 전략 | 이유 |
|---|---|---|
| 1~3명, 초기 스타트업 | Rolling (ECS 기본) | 추가 설정 없이 바로 사용. 비용 최소. ECS 서비스 생성만 하면 끝. |
| 5~15명, 성장기 | Blue-Green (CodeDeploy) | 즉시 롤백의 안정감. CodeDeploy가 자동 관리. 모니터링 인프라 구축 시작 시점. |
| 15~50명, 확장기 | Canary + Feature Flag | 다수 팀이 독립 배포. 실제 트래픽 검증 필수. 자동 롤백으로 사고 예방. |
| 50명+, 대규모 | Canary + Feature Flag + A/B | 프로덕트/엔지니어링 협업. 실험 문화. Spinnaker/Argo Rollouts 도입. |
어떤 전략을 선택하든, 다음 사항을 먼저 갖춰야 한다.
process.on('SIGTERM', async () => {
console.log('SIGTERM received. Graceful shutdown...');
// 새 요청 수신 중단
server.close();
// 처리 중인 요청 완료 대기 (최대 30초)
await new Promise(resolve => setTimeout(resolve, 30000));
// DB 연결 종료
await db.disconnect();
process.exit(0);
});
Backward Compatible API: v1과 v2가 공존할 수 있도록, API 변경은 항상 하위 호환성을 유지한다. 필드를 삭제하지 말고, 새 필드를 추가하라.
DB 마이그레이션 분리: 스키마 변경은 코드 배포와 별도로 실행한다. Expand-Contract 패턴을 사용한다.
헬스 체크 엔드포인트: 단순 200 OK가 아니라, DB 연결, 캐시 상태, 의존 서비스 연결까지 확인하는 심층 헬스 체크를 구현한다.
{
"status": "healthy",
"version": "2.3.1",
"uptime": "4h 23m",
"checks": {
"database": { "status": "healthy", "latency_ms": 3 },
"redis": { "status": "healthy", "latency_ms": 1 },
"external_api": { "status": "degraded", "latency_ms": 450 }
}
}
"다음 주 금요일 자정에 배포합니다" — 이 문장에는 무의식적인 가정이 들어 있다. 배포는 특별한 이벤트이고, 위험하고, 사람이 적은 시간에 해야 한다는 가정.
하지만 Netflix, Amazon, Google 같은 기업에서 배포는 이벤트가 아니다. 코드를 푸시하면 자동으로 일어나는 일상이다. 하루에 수천 번 배포하면서도 사용자는 전혀 눈치채지 못한다.
이것이 가능한 이유는 특별한 마법이 아니라, 이 글에서 다룬 기술들의 조합이다:
처음부터 Canary + Feature Flag + 자동 롤백을 구축할 필요는 없다. Rolling 배포로 시작하고, 팀이 성장하고 서비스가 커지면서 한 단계씩 올라가면 된다.
중요한 것은 방향이다. "점검 안내: 오전 2시~6시 서비스 중단"이라는 공지를 보내야 하는 상황에서, 그 공지를 영영 보내지 않아도 되는 상황으로. 그 여정의 첫걸음이 이 글에서 다룬 배포 전략이다.
서비스를 멈추지 않고 업데이트하는 것. 그것은 사용자에 대한 존중이고, 엔지니어 삶의 질에 대한 투자이며, 비즈니스 연속성에 대한 보장이다.