Kubernetes 업데이트 전략 정리 — Rolling/Blue-Green/Canary
K8s 업데이트 전략은 두 추상화 층위로 나눠서 본다. 하나는 K8s API의 update strategy인 RollingUpdate·Recreate·OnDelete이고, 다른 하나는 배포 패턴인 Rolling·Blue-Green·Canary다. NVIDIA Driver Operator 같은 host kernel 결합 워크로드까지 함께 정리한다.
[01] Rolling Update 개요
K8s의 기본 무중단 배포 전략. Deployment의 Pod를 점진적으로 교체하여 두 버전이 일시적으로 공존하다가 최종적으로 새 버전으로 완전히 전환된다.
1-1. 동작 방식
새 ReplicaSet을 생성하고, 기존 ReplicaSet의 Pod를 줄이면서 새 Pod를 늘려가는 방식이다.
graph LR
OLD["ReplicaSet v1
(10 Pods)"] -->|점진 감소| MID["v1: 8 / v2: 4
(공존)"]
MID -->|점진 교체| NEW["ReplicaSet v2
(10 Pods)"]
style OLD fill:#ffcccc,stroke:#c62828
style MID fill:#fff3e0,stroke:#e65100
style NEW fill:#e8f5e9,stroke:#2e7d32
1-2. 핵심 파라미터
spec.strategy.rollingUpdate 하위:
| 파라미터 | 의미 | 기본값 |
|---|---|---|
maxUnavailable |
동시에 사용 불가능할 수 있는 최대 Pod 수 | 25% |
maxSurge |
desired replica를 초과해 추가로 띄울 수 있는 최대 Pod 수 | 25% |
예: replicas=10, maxUnavailable=2, maxSurge=2 → 항상 최소 8개가 동작하고, 최대 12개까지 띄우며 교체한다.
1-3. 주요 명령어
1
2
3
4
kubectl set image deployment/myapp container=myapp:v2 # 트리거
kubectl rollout status deployment/myapp # 진행 상황
kubectl rollout history deployment/myapp # 이력
kubectl rollout undo deployment/myapp # 롤백
1-4. 전제 조건
- Pod에 적절한
readinessProbe설정: 새 Pod가 트래픽을 받을 준비가 됐는지 판단한다 - Stateful 워크로드는 StatefulSet 순차 업데이트 또는 Recreate 전략이 더 적합한 경우 있음
[02] 배포 패턴 비교: Rolling / Blue-Green / Canary
2-1. Blue/Green Deployment
동일한 환경 두 개를 완전히 분리해서 운영하다가 트래픽을 한 번에 스위치한다. Blue가 현재 버전, Green이 신규 버전이다.
1
2
3
4
5
6
7
[Service] ──► Blue (v1) ✅ 현재 트래픽
Green (v2) 🟢 대기 (검증 중)
↓ 스위치
[Service] ──► Blue (v1) ⚪ 대기 (롤백용)
Green (v2) ✅ 현재 트래픽
| 항목 | 내용 |
|---|---|
| 장점 | 즉시 롤백, 두 버전이 트래픽에 동시 노출 안 됨 |
| 단점 | 리소스 2배, DB 스키마 호환성 이슈 |
2-2. Canary Deployment
신규 버전에 소수 트래픽을 먼저 흘려보내 검증한 뒤 비율을 점진적으로 증가시킨다.
1
2
3
4
5
6
v1 (95%) ──┐
v2 (5%) ──┴──► 메트릭 관찰 (에러율, 레이턴시)
↓ 정상이면 비율 ↑
v1 (50%) / v2 (50%)
↓
v1 (0%) / v2 (100%)
| 항목 | 내용 |
|---|---|
| 장점 | 실 트래픽 검증, 영향 범위 최소화 |
| 단점 | 구현 복잡, observability 인프라 필수 |
2-3. 비교표
| 항목 | Rolling Update | Blue/Green | Canary |
|---|---|---|---|
| 리소스 부담 | 낮음 (maxSurge만큼) |
높음 (2배) | 중간 |
| 롤백 속도 | 느림 (재배포) | 즉시 (스위치) | 즉시 (라우팅 변경) |
| 트래픽 분리 | 불가 (혼재) | 완전 분리 | 비율 제어 |
| 구현 난이도 | 매우 낮음, K8s 기본 제공 | 중간 | 높음 |
| 검증 방식 |
readinessProbe 위주 |
사전 스모크 테스트 | 실 트래픽 메트릭 |
| 적합 케이스 | 대부분 stateless 워크로드 | DB/캐시 호환성 검증 필요 | 리스크 큰 변경, A/B 테스트 |
[03] K8s API 차원의 Update Strategy
K8s API spec이 직접 정의한 update enum 값.
| Workload | 사용 가능한 strategy |
|---|---|
| Deployment |
RollingUpdate, Recreate
|
| StatefulSet |
RollingUpdate, OnDelete
|
| DaemonSet |
RollingUpdate, OnDelete
|
3-1. 각 전략의 동작
| 전략 | 동작 | K8s 컨트롤러가 자동 처리? |
|---|---|---|
RollingUpdate |
점진 교체, maxUnavailable/maxSurge 준수 |
O |
Recreate |
모든 구버전 Pod 종료 후 신버전 생성 (다운타임 발생) | O |
OnDelete |
Pod가 명시적으로 삭제될 때만 새 버전으로 교체 | X, 사람 또는 Operator가 직접 |
3-2. DaemonSet에는 Recreate가 없다
DaemonSet은 노드당 1개 Pod 모델이라 Recreate가 의미상 부적합하다. 대신 OnDelete가 그 역할을 일부 대체하며, 보통 Operator가 노드별 교체 로직을 추가로 구현한다.
[04] 두 추상화 층위의 구분 (핵심 개념)
4-1. 흔한 오해
“K8s resource의 update는 Rolling Update / Blue-Green / Canary 3개로 분류된다”
→ 부정확하다. 두 다른 추상화 층위가 섞여 있다.
4-2. 두 층위의 정의
| 층위 | 정체 | 항목 |
|---|---|---|
| A: K8s 리소스 update 방법 = K8s API strategy | K8s가 리소스 spec을 어떻게 변경하는가 |
RollingUpdate, Recreate, OnDelete
|
| B: 배포 패턴 | 애플리케이션의 새 버전을 사용자에게 어떻게 노출하는가 | Rolling Update, Blue/Green, Canary |
“K8s API의 update strategy”와 “K8s resource의 업데이트 방법”은 둘 다 A층위를 가리키는 같은 말이다. 표현만 다를 뿐 동일한 대상이다. 실제 구분선은 A층위와 B층위 사이에 있다.
4-3. 두 층위의 관계
graph TD
subgraph B["B층위: 배포 패턴 (애플리케이션 버전 전환 방식)"]
B1["Rolling Update"]
B2["Blue/Green"]
B3["Canary"]
end
subgraph A["A층위: K8s 리소스 update 방법 = API strategy"]
A1["RollingUpdate"]
A2["Recreate"]
A3["OnDelete"]
end
B1 -.->|uses| A1
B2 -.->|uses| A1
B3 -.->|uses| A1
style B fill:#e3f2fd,stroke:#1565c0
style A fill:#fff3e0,stroke:#e65100
- A는 K8s가 직접 제공하는 primitive다.
- B는 그 primitive를 조합해서 만드는 상위 패턴이다.
4-4. 이름 충돌
- “Rolling Update”는 A층위와 B층위에 모두 있다. 이름은 같지만 추상화 층위가 다르다.
- “Recreate”도 A층위의 Deployment strategy와 B층위의 개념적 패턴으로 각각 등장한다.
그래서 “K8s 업데이트 분류 = Rolling/Recreate/Blue-Green/Canary”처럼 한 줄로 묶어 부르지만, 실제로는 두 층위가 섞여 있다.
4-5. B층위를 strategy 한 줄로 표현할 수 없는 이유
A층위 strategy는 단일 워크로드 리소스의 update 동작을 정의한다. Blue/Green과 Canary는 여러 리소스를 조합하는 패턴이라 strategy 한 줄로 표현할 수 없다.
| 패턴 | K8s 표현 | A층위 단독 표현? |
|---|---|---|
| Rolling Update | Deployment 하나의 .spec.strategy 필드 |
O |
| Blue/Green | Deployment(blue) + Deployment(green) + Service(selector swap) | X |
| Canary | Deployment 둘 + Ingress/VirtualService(weight) + 메트릭 로직 | X |
4-6. Blue/Green의 K8s 구현 예시
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# blue-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: app-blue
spec:
strategy:
type: RollingUpdate # ← A층위: 이 Deployment의 update strategy
selector:
matchLabels:
app: myapp
color: blue
template:
metadata:
labels:
app: myapp
color: blue
---
# green-deployment.yaml (동일 구조, color: green)
---
# service.yaml — selector를 blue ↔ green으로 스위치
apiVersion: v1
kind: Service
spec:
selector:
app: myapp
color: blue # ← B층위: 이 selector swap이 Blue/Green 패턴 자체
위 예시에서:
- 각 Deployment가 내부적으로 update될 때의 방식은 A층위이며
RollingUpdate다. - 전체적으로 사용자에게 v1 → v2를 노출하는 패턴은 B층위이며 Blue/Green이다.
Blue/Green 패턴을 만들 때 사용하는 K8s strategy는 여전히 RollingUpdate다. B층위는 A층위를 조합해서 만든 상위 개념이다.
4-7. 패턴 → K8s 구현 매핑
| 배포 패턴 | K8s에서의 구현 | A층위 strategy |
|---|---|---|
| Rolling Update |
Deployment 단독, strategy=RollingUpdate |
RollingUpdate |
| Recreate |
Deployment 단독, strategy=Recreate |
Recreate |
| Blue/Green | 두 Deployment + Service selector swap, 또는 Rollout CRD |
각 Deployment는 RollingUpdate
|
| Canary | 두 Deployment + Ingress weight / 서비스 메시, 또는 Rollout CRD |
각 Deployment는 RollingUpdate
|
[05] 외부 솔루션
| 도구 | Blue/Green | Canary | 특징 |
|---|---|---|---|
| Argo Rollouts | O | O |
Rollout CRD가 Deployment 대체. AnalysisRun으로 메트릭 기반 자동 promote/rollback |
| Flagger | O | O | 기존 Deployment 유지. Prometheus 메트릭 기반 progressive delivery 자동화 |
| Istio / Linkerd | O | O | 트래픽 분산 primitive 제공. Argo/Flagger와 조합이 일반적 |
| ingress-nginx | 제한적 | O |
nginx.ingress.kubernetes.io/canary 어노테이션. 메트릭 분석은 별도 |
| 수동 배포, vanilla K8s | 가능 | 사실상 불가 | 두 Deployment + Service patch로 Blue/Green은 그럭저럭 가능, Canary는 트래픽 가중치 제어 불가 |
[06] NVIDIA Driver Operator 케이스 분석
6-1. 왜 노드 안에서 Rolling Update가 불가능한가
NVIDIA driver는 본질이 host kernel module 적재(nvidia.ko, nvidia-uvm.ko, nvidia-modeset.ko)이며, 이로 인한 제약이 있다.
| # | 제약 | 설명 |
|---|---|---|
| 1 | 커널 모듈 싱글톤 | 동일 모듈의 두 버전을 host kernel에 동시 로드 불가. 같은 노드에서 v1·v2 driver pod 공존이 OS 레벨에서 거부됨 |
| 2 | 모듈 unload의 ref count 조건 |
rmmod은 reference count가 0이어야 성공. GPU 사용 중인 컨테이너, nvidia-persistenced, X server 등이 붙어 있으면 EBUSY → 재부팅 필요 |
| 3 | container-toolkit 의존성 |
nvidia-container-toolkit, libnvidia-container, device plugin이 모두 현재 driver를 참조. driver만 교체하면 의존 관계가 깨진다 |
| 4 | 재부팅 강제 케이스 | secure boot + signed module 변경, persistent mode, driver-firmware coupling |
이 모든 제약이 “두 버전 일시 공존”을 전제하는 Rolling Update와 정면 충돌한다.
6-2. 그래도 클러스터 단위 무중단 롤아웃은 가능
1
2
3
4
5
6
7
8
9
for each node (보통 maxUnavailable=1):
cordon # 새 GPU pod 스케줄 차단
drain GPU workloads # PDB 준수
wait module ref_count == 0
unload old module # 실패 → reboot 분기
delete old driver pod (OnDelete)
reconcile new driver pod
wait Ready + module loaded + smoke test
uncordon
6-3. K8s와 Operator의 책임 구분
| 요소 | 누가 정의 / 구현 |
|---|---|
OnDelete enum 값 |
K8s API |
DaemonSet 매니페스트의 updateStrategy.type: OnDelete
|
K8s API spec 위에 사용자가 선언 |
| 노드별 cordon/drain/unload/replace 상태머신 | Operator |
| 클러스터 전체 노드 순차 롤아웃 정책 (maxUnavailable, drainTimeout, rebootStrategy) | Operator |
검증 게이트: nvidia-smi, device plugin 상태 점검 |
Operator |
OnDelete는 K8s가 제공하는 enum 값까지만 정의한다. 노드별로 driver를 안전하게 교체하는 순서와 조건은 Operator가 직접 구현한다.
6-4. 행위적 분류
| 관점 | 실제 모습 |
|---|---|
| A층위, K8s API 레벨 |
OnDelete 전략 |
| 노드 안에서의 동작 | “Recreate처럼 보임”, 두 버전 공존 불가 |
| 클러스터 전체에서의 동작 | “Rolling Update처럼 보임”, 노드별 순차 처리 |
6-5. 설계 의사결정 순서
- A층위 결정: DaemonSet의
updateStrategy.type을RollingUpdate로 둘지OnDelete로 둘지 정한다. driver는OnDelete를 쓴다. - B층위 결정: 그 위에서 어떤 배포 패턴을 구현할지 정한다. driver는 host kernel과 결합돼 Blue/Green과 Canary가 사실상 불가능하므로, 노드별 Recreate를 순차 진행하는 방식이 유일한 선택지다.
[07] 핵심 요약
| # | 요약 |
|---|---|
| 1 | 추상화 층위가 둘로 나뉜다. A층위는 K8s API strategy, B층위는 배포 패턴이다 |
| 2 | A층위 항목: RollingUpdate, Recreate, OnDelete (워크로드 종류별로 사용 가능 값 상이) |
| 3 | B층위 항목: Rolling Update, Blue/Green, Canary. 여기에 Recreate, A/B, Shadow 등이 더해진다 |
| 4 | K8s native로 직접 제공되는 패턴은 Rolling Update와 Recreate뿐. Blue/Green·Canary는 외부 CRD(Argo Rollouts, Flagger) 또는 multi-resource 조합으로 구현 |
| 5 |
OnDelete는 A층위의 enum 값이고, 그것이 활성화됐을 때의 오케스트레이션 로직은 Operator가 직접 구현해야 함 |
| 6 | NVIDIA driver처럼 host kernel과 결합된 워크로드는 Rolling Update가 노드 안에서 물리적으로 불가능. “노드 안은 Recreate, 노드 간은 통제된 Rolling” 패턴이 사실상 유일한 정답 |
두 층위를 구분하면 워크로드마다 어떤 strategy를 고르고 그 위에 어떤 배포 패턴을 올릴지 따로 결정할 수 있다. host kernel과 결합된 워크로드처럼 B층위 선택지가 좁은 경우를 먼저 판별하는 것이 이 구분의 실용적 쓸모다.