[Kubernetes] Canary 배포 동작 원리 - Flagger의 내부 메커니즘 완벽 분석
Flagger를 사용한 Canary 배포의 내부 동작 원리를 깊이 있게 분석하고, Primary/Canary Deployment의 역할, 트래픽 분기 메커니즘, Promotion 과정을 완벽히 이해한다.
들어가며
이전 글에서 Canary 배포의 개념과 Flagger의 역할을 살펴봤다면, 이번에는 실제 내부에서 어떻게 동작하는지 깊이 파고들어 보자.
많은 개발자들이 Canary 배포를 사용하지만, 실제로 내부에서:
- Flagger가 어떤 순서로 리소스를 생성하는지
- Primary와 Canary Deployment가 어떻게 분리되는지
- 트래픽 비율과 Pod 수가 어떤 관계인지
- Promotion이 실제로 무엇을 의미하는지
이런 내부 메커니즘을 제대로 이해하는 경우는 드물다.
이 글에서는 Flagger의 내부 동작 원리를 단계별로 분석하여, Canary 배포가 실제로 어떻게 작동하는지 명확히 이해해본다.
1. Canary 배포의 시작점
Canary CRD 생성
모든 것은 사용자가 Canary CRD(Custom Resource Definition)를 생성하는 것에서 시작된다.
apiVersion: flagger.app/v1beta1
kind: Canary
metadata:
name: my-app
namespace: default
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: my-app # 기존 Deployment
service:
port: 8080
analysis:
interval: 30s
threshold: 5
maxWeight: 50
stepWeight: 10
Flagger의 감시 시작
Flagger는 Kubernetes 컨트롤러로서 Canary CRD를 watch하고 있다가, 새로운 Canary 리소스가 생성되거나 targetRef로 지정된 Deployment에 변경이 발생하면 즉시 반응한다.
사용자
│
├─ kubectl apply -f canary.yaml
↓
Kubernetes API Server
│
├─ Canary CRD 생성
↓
Flagger (watch)
│
└─ "my-app Deployment를 Canary 방식으로 관리 시작!"
2. Flagger가 수행하는 기본 흐름
Canary CRD가 생성되면 Flagger는 다음 순서로 동작한다.
Step 1: Primary Deployment 생성
기존 Deployment를 복제하여 <name>-primary Deployment를 생성한다.
# 원본: my-app
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
replicas: 3
template:
spec:
containers:
- name: my-app
image: my-app:v1.0
# Flagger가 생성 ↓
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app-primary # ← 복제본
spec:
replicas: 3
template:
spec:
containers:
- name: my-app
image: my-app:v1.0 # 동일한 이미지
Step 2: Canary Deployment 준비
새 버전이 배포되면 <name>-canary Deployment를 생성한다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app-canary # ← 새 버전
spec:
replicas: 1 # 초기에는 적은 수
template:
spec:
containers:
- name: my-app
image: my-app:v2.0 # 새 버전
Step 3: Service 분리
기존 Service를 Primary/Canary용으로 분리한다.
# Primary Service
apiVersion: v1
kind: Service
metadata:
name: my-app-primary
spec:
selector:
app: my-app-primary
---
# Canary Service
apiVersion: v1
kind: Service
metadata:
name: my-app-canary
spec:
selector:
app: my-app-canary
Step 4: IngressRoute 트래픽 제어
Traefik의 경우 IngressRoute의 weight를 조정하여 트래픽을 분기한다.
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: my-app
spec:
routes:
- match: Host(`my-app.example.com`)
kind: Rule
services:
- name: my-app-primary
port: 8080
weight: 90 # Primary 90%
- name: my-app-canary
port: 8080
weight: 10 # Canary 10%
3. Deployment 구성의 의미
Primary Deployment의 역할
현재 안정 버전을 제공하는 실제 운영 Deployment다.
- 실제 프로덕션 트래픽의 기준
- 항상 안정적인 버전 유지
- Canary 검증이 끝나면 새 버전으로 업데이트
Canary Deployment의 역할
새 버전을 검증하는 테스트 Deployment다.
- 새 버전의 안정성을 확인하는 대상
- 검증이 끝나면 삭제되거나 대기 상태로 유지
- 실패 시 즉시 중단 가능
원본 Deployment의 운명
기존 “원본 Deployment”는:
초기 상태
─────────────────────
my-app (원본)
├─ 트래픽 받음
└─ 실제 서비스 제공
Flagger 초기화 후
─────────────────────
my-app (원본)
├─ 트래픽 받지 않음 ✗
├─ Flagger가 관리용으로 사용
└─ 실제로는 사용되지 않음
my-app-primary (복제본)
├─ 실제 트래픽 받음 ✓
└─ 운영 서비스 제공
중요: 원본 Deployment는 Flagger가 Primary를 생성한 이후 더 이상 트래픽을 받지 않는다. Flagger가 새 버전을 감지하는 템플릿으로만 사용된다.
4. 트래픽 분기 방식
Traefik IngressRoute의 Weight 기반 분기
Flagger는 IngressRoute의 weight 값을 단계별로 조정하여 트래픽을 분배한다.
단계별 트래픽 분배 예시
# 1단계: 초기 (90% / 10%)
services:
- name: my-app-primary
weight: 90
- name: my-app-canary
weight: 10
# 2단계: 검증 통과 (75% / 25%)
services:
- name: my-app-primary
weight: 75
- name: my-app-canary
weight: 25
# 3단계: 계속 진행 (50% / 50%)
services:
- name: my-app-primary
weight: 50
- name: my-app-canary
weight: 50
# 4단계: 최종 (0% / 100%)
services:
- name: my-app-primary
weight: 0
- name: my-app-canary
weight: 100
실제 동작 흐름
사용자 요청
↓
Traefik Ingress Controller
│
├─ weight 계산 (90:10)
├─ 90%는 → my-app-primary Service
└─ 10%는 → my-app-canary Service
↓
각 Service의 Endpoints로 전달
│
├─ my-app-primary Pod 1, 2, 3
└─ my-app-canary Pod 1
Flagger의 역할
Flagger는 트래픽을 직접 제어하지 않는다. 대신:
- 메트릭을 분석
- 다음 단계로 진행 가능한지 판단
- IngressRoute의 weight 값을 업데이트
- 실제 트래픽 분배는 Traefik이 수행
Flagger (판단)
↓
"메트릭 OK → weight를 20%로 증가"
↓
IngressRoute 수정 (kubectl patch)
↓
Traefik (실행)
↓
"weight 20% 적용 완료"
5. Canary Pod 수와 트래픽 100%의 관계
오해하기 쉬운 점
많은 사람들이 “트래픽 100%를 받으려면 Canary Pod 수도 100%여야 한다”고 생각한다.
❌ 잘못된 이해
Primary: 10 Pods (0% 트래픽)
Canary: 10 Pods (100% 트래픽)
✅ 올바른 이해
Primary: 10 Pods (0% 트래픽)
Canary: 3 Pods (100% 트래픽) ← 적은 수로 시작
↓
트래픽 증가 감지
↓
HPA가 Canary를 자동 확장
↓
Canary: 10 Pods (100% 트래픽)
동작 원리
초기 상태
# Canary Deployment
spec:
replicas: 1 # 처음엔 적게 시작
트래픽 증가
1단계: Canary 10% 트래픽
├─ Pod 1개로도 충분히 처리 가능
└─ HPA 동작 안 함
2단계: Canary 25% 트래픽
├─ 트래픽 증가 → CPU/메모리 사용량 증가
└─ HPA가 감지 → Pod 2개로 증가
3단계: Canary 50% 트래픽
├─ 더 많은 요청 처리 필요
└─ HPA가 Pod 5개로 증가
4단계: Canary 100% 트래픽
├─ 모든 트래픽을 Canary가 처리
└─ HPA가 필요한 만큼 확장 (예: 10개)
핵심 정리
| 구분 | 설명 |
|---|---|
| 트래픽 비율 | IngressRoute의 weight로 제어 |
| Pod 수 | HPA가 실제 부하에 따라 자동 조정 |
| 관계 | 트래픽 비율 ≠ Pod 비율 |
| 수용 능력 | HPA가 자동으로 보정 |
트래픽 제어 (Flagger)
↓
트래픽 증가
↓
부하 증가 (CPU/메모리)
↓
HPA 감지
↓
Pod 자동 확장
결론: Canary Pod는 처음에 적은 수로 시작하고, 트래픽이 증가하면 HPA가 자동으로 확장한다. 트래픽 비율과 Pod 비율은 독립적이다.
6. 메트릭 기반 검증
Flagger는 각 단계에서 메트릭을 분석하여 다음 단계로 진행할지 결정한다.
검증 메트릭
analysis:
metrics:
# 1. 오류율
- name: request-success-rate
thresholdRange:
min: 99 # 성공률 99% 이상
# 2. 지연 시간
- name: request-duration
thresholdRange:
max: 500 # 응답시간 500ms 이하
# 3. 에러율
- name: error-rate
thresholdRange:
max: 1 # 에러율 1% 이하
검증 프로세스
1. Canary 10% 배포
↓
2. interval (30초) 동안 대기
↓
3. Prometheus에서 메트릭 수집
├─ request-success-rate: 99.5% ✓
├─ request-duration: 450ms ✓
└─ error-rate: 0.3% ✓
↓
4. 모든 메트릭이 기준 통과
↓
5. 다음 단계로 진행 (20%)
기준 초과 시 동작
1. Canary 20% 배포
↓
2. 메트릭 수집
├─ request-success-rate: 97% ✗ (기준: 99%)
├─ request-duration: 650ms ✗ (기준: 500ms)
└─ error-rate: 3% ✗ (기준: 1%)
↓
3. 실패 카운트 증가 (1/5)
↓
4. 다시 메트릭 수집
├─ 여전히 기준 미달
└─ 실패 카운트 증가 (2/5, 3/5, ...)
↓
5. threshold (5) 도달
↓
6. 자동 롤백 시작
├─ Canary 중단
├─ 트래픽 100% Primary로 복귀
└─ Canary Deployment 스케일 다운
메트릭 수집 흐름
┌──────────────┐
│ Canary Pod │
│ (v2.0) │
└──────┬───────┘
│ 메트릭 노출 (:9090/metrics)
↓
┌──────────────┐
│ Prometheus │ ← Scrape 메트릭
└──────┬───────┘
│ 저장된 메트릭
↓
┌──────────────┐
│ Flagger │ ← PromQL 쿼리
└──────┬───────┘
│ 분석 결과
↓
진행 / 롤백 결정
7. Promotion (승격) 단계
Canary가 모든 검증을 통과하면 Promotion(승격)이 수행된다.
Promotion의 정확한 의미
많은 사람들이 오해하는 부분이다.
❌ 잘못된 이해
Canary Deployment가 Primary Deployment가 된다
✅ 올바른 이해
Primary Deployment의 이미지를
Canary 이미지로 교체한다
Promotion 실제 동작
1단계: Canary 검증 완료
Primary Deployment (my-app-primary)
├─ image: my-app:v1.0
└─ replicas: 10
Canary Deployment (my-app-canary)
├─ image: my-app:v2.0
└─ replicas: 3
└─ 모든 메트릭 통과 ✓
2단계: Flagger가 Primary 업데이트
# Before
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app-primary
spec:
template:
spec:
containers:
- name: my-app
image: my-app:v1.0 # ← 구버전
# After (Flagger가 수정)
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app-primary
spec:
template:
spec:
containers:
- name: my-app
image: my-app:v2.0 # ← 새버전으로 교체
3단계: Kubernetes Rolling Update
Primary Deployment에서 일반적인 Rolling Update가 발생한다.
Primary Deployment의 Rolling Update
──────────────────────────────────
1. 새 Pod (v2.0) 생성
├─ v1.0 Pod: 10개
└─ v2.0 Pod: 1개 (생성 중)
2. 새 Pod 준비 완료
├─ v2.0 Pod: Ready
└─ 구 Pod 1개 종료 시작
3. 순차적 교체
├─ v1.0 Pod: 9개
└─ v2.0 Pod: 2개
4. 반복...
├─ v1.0 Pod: 5개
└─ v2.0 Pod: 6개
5. 최종 완료
├─ v1.0 Pod: 0개 (종료)
└─ v2.0 Pod: 10개 (실행 중)
4단계: Canary Deployment 정리
Canary Deployment (my-app-canary)
├─ 더 이상 사용되지 않음
├─ Scale down to 0
└─ 또는 삭제
Promotion 후 최종 상태
Primary Deployment (my-app-primary)
├─ image: my-app:v2.0 ← 새 버전
├─ replicas: 10
└─ 트래픽 100%
Canary Deployment (my-app-canary)
├─ image: my-app:v2.0
├─ replicas: 0 ← 대기 상태
└─ 다음 배포를 위해 대기
원본 Deployment (my-app)
├─ Flagger가 계속 watch
└─ 다음 이미지 변경 감지 대기
8. 실패 시 동작 (Rollback)
메트릭이 기준을 충족하지 못하면 자동 롤백이 발생한다.
롤백 트리거
analysis:
threshold: 5 # 5회 연속 실패 시 롤백
롤백 프로세스
1단계: 메트릭 실패 감지
Canary 25% 진행 중
↓
메트릭 수집
├─ success-rate: 97% ✗ (기준: 99%)
└─ duration: 700ms ✗ (기준: 500ms)
↓
실패 카운트: 1/5
2단계: 재시도
30초 대기 (interval)
↓
다시 메트릭 수집
├─ 여전히 기준 미달
└─ 실패 카운트: 2/5
↓
계속 재시도...
└─ 실패 카운트: 3/5, 4/5, 5/5
3단계: 자동 롤백 시작
threshold (5) 도달
↓
Flagger: "롤백 시작!"
↓
1. IngressRoute weight 즉시 원복
├─ Canary: 0%
└─ Primary: 100%
2. Canary Deployment 중단
└─ Scale down to 0
3. 알림 발송
└─ Slack: "Canary 배포 실패 - 롤백 완료"
4단계: 롤백 완료
Primary Deployment
├─ image: my-app:v1.0 ← 구버전 유지
├─ replicas: 10
└─ 트래픽 100% (영향 없음)
Canary Deployment
├─ image: my-app:v2.0 ← 실패한 버전
├─ replicas: 0
└─ 중단됨
롤백의 특징
| 항목 | 설명 |
|---|---|
| 속도 | 즉시 (수 초 내) |
| 영향 범위 | Canary 트래픽만 (Primary 무영향) |
| 데이터 손실 | 없음 |
| 사용자 영향 | 최소화 (일부 트래픽만 영향) |
9. 전체 흐름 다이어그램
성공 시나리오
[초기 상태]
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
원본 Deployment (my-app)
└─ image: v1.0
↓ Canary CRD 생성
[Flagger 초기화]
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Primary Deployment (my-app-primary)
└─ image: v1.0
└─ 트래픽: 100%
Canary Deployment (my-app-canary)
└─ image: v1.0
└─ 대기 중
↓ 새 버전 배포 (v2.0)
[Canary 시작]
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Primary: v1.0 (90%)
Canary: v2.0 (10%)
↓ 메트릭 검증 (30초)
메트릭 분석
├─ success-rate: 99.5% ✓
├─ duration: 450ms ✓
└─ error-rate: 0.3% ✓
↓ 통과
[Canary 진행]
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Primary: v1.0 (75%)
Canary: v2.0 (25%)
↓ 계속 검증
Primary: v1.0 (50%)
Canary: v2.0 (50%)
↓ 최종 단계
Primary: v1.0 (0%)
Canary: v2.0 (100%)
↓ 모든 검증 통과
[Promotion]
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Primary 이미지 교체: v1.0 → v2.0
Rolling Update 시작...
↓ Rolling Update 완료
[완료 상태]
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Primary Deployment
├─ image: v2.0
└─ 트래픽: 100%
Canary Deployment
├─ image: v2.0
└─ 대기 (replicas: 0)
실패 시나리오
[Canary 진행 중]
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Primary: v1.0 (80%)
Canary: v2.0 (20%)
↓ 메트릭 검증
메트릭 분석
├─ success-rate: 97% ✗
├─ duration: 700ms ✗
└─ 실패 카운트: 1/5
↓ 재시도
메트릭 분석
├─ 여전히 기준 미달
└─ 실패 카운트: 2/5
↓ 계속 재시도
실패 카운트: 5/5 (threshold 도달)
↓ 자동 롤백
[롤백 수행]
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
트래픽 즉시 원복
├─ Primary: 100%
└─ Canary: 0%
Canary Deployment 중단
└─ Scale down to 0
알림 발송
└─ Slack: "배포 실패 - 롤백 완료"
↓
[롤백 완료]
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Primary Deployment
├─ image: v1.0 (유지)
└─ 트래픽: 100%
Canary Deployment
├─ image: v2.0 (실패)
└─ 중단됨
10. 실전 예시
시나리오: 결제 서비스 새 버전 배포
초기 환경
# payment-service Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: payment-service
spec:
replicas: 5
template:
spec:
containers:
- name: payment
image: payment:v1.0.0
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
HPA 설정
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: payment-service
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: payment-service
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
Canary CRD 생성
apiVersion: flagger.app/v1beta1
kind: Canary
metadata:
name: payment-service
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: payment-service
service:
port: 8080
analysis:
interval: 1m
threshold: 3
maxWeight: 50
stepWeight: 10
metrics:
- name: request-success-rate
thresholdRange:
min: 99.9 # 결제 서비스는 높은 기준
- name: request-duration
thresholdRange:
max: 200 # 빠른 응답 필요
webhooks:
- name: load-test
url: http://flagger-loadtester/
metadata:
cmd: "hey -z 1m -q 50 -c 5 http://payment-service:8080/health"
새 버전 배포
# 이미지 업데이트
kubectl set image deployment/payment-service payment=payment:v2.0.0
Flagger 동작 로그
[00:00:00] Canary 감지
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Deployment/payment-service 이미지 변경 감지
From: payment:v1.0.0
To: payment:v2.0.0
[00:00:05] 초기화 시작
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✓ payment-service-primary Deployment 생성
├─ image: payment:v1.0.0
└─ replicas: 5
✓ payment-service-canary Deployment 생성
├─ image: payment:v2.0.0
└─ replicas: 1 ← 적은 수로 시작
✓ Service 분리 완료
├─ payment-service-primary
└─ payment-service-canary
✓ IngressRoute 설정 완료
├─ Primary: 100%
└─ Canary: 0%
[00:01:00] Canary 진행 시작
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
IngressRoute 업데이트
├─ Primary: 90%
└─ Canary: 10%
Load test 시작...
└─ hey -z 1m -q 50 -c 5 http://payment-service:8080/health
[00:02:00] 메트릭 분석 (1차)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Prometheus 쿼리 실행...
✓ request-success-rate: 99.95% (기준: 99.9%)
✓ request-duration: 150ms (기준: 200ms)
결과: 통과 ✓
HPA 상태 확인
├─ Primary: 5 Pods (CPU: 45%)
└─ Canary: 1 Pod (CPU: 60%) ← 아직 확장 안 함
[00:03:00] 트래픽 증가
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
IngressRoute 업데이트
├─ Primary: 80%
└─ Canary: 20%
[00:04:00] 메트릭 분석 (2차)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✓ request-success-rate: 99.92%
✓ request-duration: 165ms
결과: 통과 ✓
HPA 상태 확인
├─ Primary: 5 Pods (CPU: 35%)
└─ Canary: 2 Pods (CPU: 75%) ← HPA가 확장 시작
[00:05:00] 트래픽 증가
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
IngressRoute 업데이트
├─ Primary: 70%
└─ Canary: 30%
[00:06:00] 메트릭 분석 (3차)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✓ request-success-rate: 99.93%
✓ request-duration: 170ms
결과: 통과 ✓
HPA 상태 확인
├─ Primary: 4 Pods (CPU: 40%)
└─ Canary: 3 Pods (CPU: 70%)
[00:07:00] 트래픽 증가
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
IngressRoute 업데이트
├─ Primary: 60%
└─ Canary: 40%
[00:08:00] 메트릭 분석 (4차)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✓ request-success-rate: 99.91%
✓ request-duration: 175ms
결과: 통과 ✓
HPA 상태 확인
├─ Primary: 3 Pods (CPU: 35%)
└─ Canary: 4 Pods (CPU: 72%)
[00:09:00] 트래픽 증가 (maxWeight 도달)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
IngressRoute 업데이트
├─ Primary: 50%
└─ Canary: 50%
maxWeight (50%) 도달
└─ 자동 진행 일시 중지
[00:10:00] 메트릭 분석 (5차)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✓ request-success-rate: 99.94%
✓ request-duration: 172ms
결과: 통과 ✓
HPA 상태 확인
├─ Primary: 3 Pods (CPU: 40%)
└─ Canary: 5 Pods (CPU: 68%)
모든 검증 통과 → Promotion 시작
[00:11:00] Promotion 수행
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Primary Deployment 이미지 교체
From: payment:v1.0.0
To: payment:v2.0.0
Kubernetes Rolling Update 시작...
├─ v1.0.0: 3 Pods
└─ v2.0.0: 1 Pod (생성 중)
[00:11:30] Rolling Update 진행 중
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
├─ v1.0.0: 2 Pods
└─ v2.0.0: 2 Pods
[00:12:00] Rolling Update 진행 중
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
├─ v1.0.0: 1 Pod
└─ v2.0.0: 3 Pods
[00:12:30] Rolling Update 완료
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Primary Deployment
├─ image: payment:v2.0.0
├─ replicas: 5 (모두 v2.0.0)
└─ 트래픽: 100%
Canary Deployment
├─ Scale down to 0
└─ 대기 상태
[00:13:00] 배포 완료
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✓ 배포 성공
✓ 총 소요 시간: 13분
✓ 롤백 없음
✓ 사용자 영향 최소화
알림 발송
└─ Slack: "payment-service v2.0.0 배포 완료 ✓"
11. 핵심 요약
Canary 배포 내부 메커니즘
1. 시작점
- 사용자가 Canary CRD 생성
- Flagger가 CRD를 watch
- Deployment 변경 감지 시 자동 시작
2. Deployment 구성
| Deployment | 역할 | 이미지 | 트래픽 |
|---|---|---|---|
| 원본 | 템플릿 (사용 안 됨) | 최신 | 0% |
| Primary | 실제 운영 서비스 | 안정 버전 | 90% → 0% |
| Canary | 새 버전 검증 | 새 버전 | 10% → 100% |
3. 트래픽 분기
- 제어: IngressRoute의 weight 기반
- 실행: Traefik/Istio 등 Ingress Controller
- 조정: Flagger가 단계별로 weight 변경
4. Pod 수와 트래픽
트래픽 비율 (IngressRoute weight)
↓
부하 증가
↓
HPA 감지
↓
Pod 자동 확장
핵심: 트래픽 비율 ≠ Pod 비율
5. 메트릭 검증
- 각 단계마다 메트릭 분석
- 기준 초과 시 자동 롤백
- threshold 도달 시 중단
6. Promotion
Canary 검증 완료
↓
Primary 이미지 교체
↓
Kubernetes Rolling Update
↓
Canary 정리
핵심: Canary가 Primary가 되는 것이 아니라, Primary 이미지만 교체
7. 실패 시 동작
- threshold 도달 시 자동 롤백
- 트래픽 즉시 Primary로 복귀
- Canary 중단
- Primary는 영향 없음
결론
Canary 배포는 단순히 “일부 트래픽으로 테스트”하는 것을 넘어, 정교한 내부 메커니즘을 통해 안전한 배포를 보장한다.
핵심 이해
- Flagger의 역할: 오케스트레이터 (실제 트래픽 제어는 Ingress Controller)
- Deployment 분리: Primary (운영) / Canary (검증)
- 트래픽과 Pod: 독립적 (HPA가 자동 조정)
- Promotion: 이미지 교체 + Rolling Update
- 안전장치: 메트릭 기반 자동 롤백
실전 적용 팁
✅ DO
- 충분한 interval: 최소 30초~1분 (메트릭 안정화)
- 적절한 stepWeight: 10% 권장 (너무 크면 위험)
- 명확한 메트릭: 성공률, 응답시간, 에러율
- HPA 설정: Canary Pod 자동 확장 허용
- 알림 설정: Slack, Email로 상태 공유
❌ DON’T
- 너무 짧은 interval: 메트릭 수집 전에 판단
- 너무 관대한 threshold: 문제를 놓칠 수 있음
- maxWeight 100%: 전체 자동 배포는 위험
- HPA 미설정: Canary가 트래픽 처리 못 함
다음 단계
- 실습 환경 구축
- Kubernetes 클러스터 준비
- Flagger 설치
- Prometheus 설정
- Traefik 또는 Istio 설정
- 테스트 배포
- 간단한 애플리케이션으로 시작
- 메트릭 기준 조정
- 롤백 시나리오 테스트
- 프로덕션 적용
- 중요도 낮은 서비스부터
- 메트릭 모니터링 강화
- 알림 체계 구축
- 점진적 확대
내부 메커니즘을 정확히 이해하면, Canary 배포를 더 효과적으로 활용하고 문제 상황에서도 빠르게 대응할 수 있다!
댓글남기기