블루-그린 배포
Blue-Green Deployment
두 개의 동일한 프로덕션 환경(블루/그린)을 교대로 사용하는 무중단 배포 전략입니다. 새 버전을 비활성 환경에 배포 후 로드밸런서로 트래픽을 전환하여 다운타임 없이 배포하고, 문제 발생 시 즉시 롤백할 수 있습니다.
Blue-Green Deployment
두 개의 동일한 프로덕션 환경(블루/그린)을 교대로 사용하는 무중단 배포 전략입니다. 새 버전을 비활성 환경에 배포 후 로드밸런서로 트래픽을 전환하여 다운타임 없이 배포하고, 문제 발생 시 즉시 롤백할 수 있습니다.
블루-그린 배포(Blue-Green Deployment)는 두 개의 동일한 프로덕션 환경을 유지하면서 배포하는 전략입니다. 현재 트래픽을 받는 환경을 '블루', 새 버전을 배포할 유휴 환경을 '그린'이라 부릅니다. 새 버전 배포 후 테스트를 완료하면 로드밸런서나 DNS를 통해 트래픽을 그린으로 전환합니다.
이 기법은 2010년 Jez Humble과 David Farley의 책 "Continuous Delivery"에서 대중화되었습니다. Netflix, Amazon, Facebook 등 대규모 서비스를 운영하는 기업들이 무중단 배포를 위해 채택했고, Kubernetes와 클라우드 서비스의 발전으로 더욱 쉽게 구현할 수 있게 되었습니다.
핵심 원리는 단순합니다. 블루 환경이 라이브 상태일 때, 그린 환경에 새 버전을 배포하고 충분히 테스트합니다. 모든 검증이 완료되면 로드밸런서 설정만 변경하여 트래픽을 그린으로 전환합니다. 문제가 발생하면 다시 블루로 트래픽을 되돌리는 것으로 즉시 롤백됩니다. 전환 시간은 수 초에 불과합니다.
실무에서 블루-그린 배포는 고가용성이 중요한 서비스에 필수입니다. 다만 인프라 비용이 2배 필요하고, 데이터베이스 스키마 변경 시 추가 고려가 필요합니다. AI 모델 서빙에서도 널리 사용되며, 새 모델 버전을 그린 환경에 배포하고 A/B 테스트 후 전환하는 패턴이 일반적입니다.
┌─────────────────────────────────────────────────────────┐
│ Load Balancer │
│ │ │
│ ┌────────────┴────────────┐ │
│ ▼ ▼ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ 🔵 BLUE │ │ 🟢 GREEN │ │
│ │ (v1.0) │ ──────▶ │ (v2.0) │ │
│ │ [ACTIVE] │ Switch │ [STANDBY] │ │
│ └──────────────┘ └──────────────┘ │
│ │
│ 배포 후 트래픽 전환: Blue → Green │
│ 롤백 필요시: Green → Blue (수 초 내 완료) │
└─────────────────────────────────────────────────────────┘
| 전략 | 다운타임 | 롤백 속도 | 인프라 비용 | 적합한 상황 |
|---|---|---|---|---|
| 블루-그린 | 없음 | 즉시 (수 초) | 2배 | 미션 크리티컬 서비스 |
| 카나리 | 없음 | 빠름 (분) | 1.1~1.5배 | 점진적 검증 필요 시 |
| 롤링 | 없음 | 느림 (분~시간) | 1배 | 비용 민감 환경 |
| 재생성 | 있음 | 느림 | 1배 | 개발/스테이징 환경 |
Kubernetes와 AWS에서 블루-그린 배포를 구현하는 예제입니다.
# blue-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-blue
labels:
app: myapp
version: blue
spec:
replicas: 3
selector:
matchLabels:
app: myapp
version: blue
template:
metadata:
labels:
app: myapp
version: blue
spec:
containers:
- name: myapp
image: myapp:1.0.0
ports:
- containerPort: 8080
readinessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
---
# green-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-green
labels:
app: myapp
version: green
spec:
replicas: 3
selector:
matchLabels:
app: myapp
version: green
template:
metadata:
labels:
app: myapp
version: green
spec:
containers:
- name: myapp
image: myapp:2.0.0 # 새 버전
ports:
- containerPort: 8080
---
# service.yaml (블루로 트래픽 라우팅)
apiVersion: v1
kind: Service
metadata:
name: myapp-service
spec:
selector:
app: myapp
version: blue # 이 값을 green으로 변경하면 전환!
ports:
- port: 80
targetPort: 8080
# 전환 명령어
# kubectl patch service myapp-service -p '{"spec":{"selector":{"version":"green"}}}'
# 롤백 명령어
# kubectl patch service myapp-service -p '{"spec":{"selector":{"version":"blue"}}}'
# appspec.yml (AWS CodeDeploy Blue-Green)
version: 0.0
Resources:
- TargetService:
Type: AWS::ECS::Service
Properties:
TaskDefinition: "arn:aws:ecs:region:account:task-definition/myapp:2"
LoadBalancerInfo:
ContainerName: "myapp"
ContainerPort: 8080
PlatformVersion: "LATEST"
Hooks:
- BeforeInstall: "LambdaFunctionToValidateBeforeInstall"
- AfterInstall: "LambdaFunctionToValidateAfterInstall"
- AfterAllowTestTraffic: "LambdaFunctionToRunTests"
- BeforeAllowTraffic: "LambdaFunctionToValidateBeforeTraffic"
- AfterAllowTraffic: "LambdaFunctionToValidateAfterTraffic"
# deployment-config.json
{
"deploymentConfigName": "CodeDeployDefault.ECSLinear10PercentEvery1Minutes",
"computePlatform": "ECS",
"trafficRoutingConfig": {
"type": "TimeBasedLinear",
"timeBasedLinear": {
"linearInterval": 1,
"linearPercentage": 10
}
}
}
# AWS CLI 배포 명령
# aws deploy create-deployment \
# --application-name MyApp \
# --deployment-group-name MyDeploymentGroup \
# --revision revisionType=S3,bucket=mybucket,key=myapp.zip
#!/bin/bash
# blue-green-switch.sh - Nginx 블루-그린 전환 스크립트
NGINX_CONF="/etc/nginx/conf.d/upstream.conf"
BLUE_PORT=8080
GREEN_PORT=8081
CURRENT=$(grep "server 127.0.0.1:" $NGINX_CONF | grep -oP '\d+')
echo "현재 활성 환경: Port $CURRENT"
if [ "$CURRENT" == "$BLUE_PORT" ]; then
NEW_PORT=$GREEN_PORT
NEW_ENV="GREEN"
else
NEW_PORT=$BLUE_PORT
NEW_ENV="BLUE"
fi
# 새 환경 헬스체크
echo "헬스체크: $NEW_ENV (Port $NEW_PORT)..."
if ! curl -sf http://127.0.0.1:$NEW_PORT/health > /dev/null; then
echo "❌ 헬스체크 실패! 전환 중단"
exit 1
fi
echo "✅ 헬스체크 통과"
# Nginx 설정 업데이트
echo "트래픽 전환: $CURRENT → $NEW_PORT"
sed -i "s/server 127.0.0.1:$CURRENT/server 127.0.0.1:$NEW_PORT/" $NGINX_CONF
# Nginx 리로드 (무중단)
nginx -t && nginx -s reload
echo "✅ 전환 완료! 현재 활성: $NEW_ENV (Port $NEW_PORT)"
# 롤백 스크립트 생성
cat > /tmp/rollback.sh << EOF
sed -i "s/server 127.0.0.1:$NEW_PORT/server 127.0.0.1:$CURRENT/" $NGINX_CONF
nginx -t && nginx -s reload
echo "롤백 완료: Port $CURRENT"
EOF
chmod +x /tmp/rollback.sh
echo "롤백 명령: /tmp/rollback.sh"
"오늘 v2.0 배포는 블루-그린으로 진행합니다. 현재 블루가 라이브고, 그린에 새 버전 배포 후 QA 완료되면 17시에 전환할게요. 혹시 모르니 롤백 담당자 지정해주세요. 전환은 kubectl patch 한 줄이면 됩니다."
"그린 환경에서 메모리 누수 발견됐습니다. 지금 바로 블루로 롤백하겠습니다. 서비스 셀렉터만 바꾸면 되니까 10초 안에 복구됩니다. 롤백 완료되면 그린 환경에서 원인 분석할게요."
"블루-그린의 단점은 인프라 비용이 2배라는 점인데요, 저희 AI 추론 서버처럼 GPU 인스턴스 비용이 높으면 부담됩니다. 카나리 배포로 10%씩 트래픽 이동시키는 게 비용 효율적일 수 있어요."
블루와 그린이 같은 DB를 공유할 때, 스키마 변경은 양쪽 버전과 호환되어야 합니다. 컬럼 삭제는 두 버전 모두 사용하지 않은 후에만 진행하세요.
인메모리 세션을 사용하면 전환 시 사용자 세션이 유실됩니다. Redis나 DB 기반 세션 스토어를 사용하거나 JWT 같은 Stateless 인증을 적용하세요.
전환 전 그린 환경에서 충분한 테스트(스모크 테스트, 로드 테스트)를 수행하세요. 헬스체크 엔드포인트를 구현하고, 전환 후에도 모니터링을 강화하여 문제 발생 시 신속히 롤백하세요.
원인: 8개 서버 중 1개에 새 코드 미배포, 구버전과 신버전 혼재
영향: 잘못된 주문 대량 발생, 45분간 4.4억 달러 손실, 회사 파산
교훈: 블루-그린 배포로 전체 환경 일관성 보장, 배포 검증 자동화 필수
원인: 운영 DB에서 실수로 rm -rf 실행, 백업 미작동
영향: 6시간 데이터 손실, 18시간 서비스 중단
교훈: 블루-그린은 애플리케이션 롤백에는 효과적이나, DB 장애에는 별도 백업 전략 필요
Q1. 블루-그린 배포의 가장 큰 장점은?
Q2. 블루-그린 배포 시 데이터베이스 스키마 변경에 대한 올바른 접근은?
Q3. 카나리 배포와 비교했을 때 블루-그린의 특징은?