4.8. 배포 전략
어떨 때 읽는 장인가
- 새 버전을 배포하는데 서비스가 끊기면 안 될 때
- 문제가 생기면 즉시 되돌려야 할 때
- 새 버전을 일부 사용자에게 먼저 보여 주고 싶을 때
- 어느 방식을 쓸지 정해야 할 때
앞의 4.2~4.7 장이 무엇으로 배포하는가(Console·Jenkins·Bastion·CI 도구·ArgoCD)를 다뤘다면, 이 장은 어떤 순서로 바꾸는가 를 다룹니다. 어느 경로로 배포하든 여기서 고른 방식을 그대로 쓸 수 있습니다.
네 가지 비교
롤링 업데이트 와 Recreate 는 Deployment 설정으로 끝나지만, 블루그린 과 카나리 는 Deployment 설정이 아닙니다. Service 를 어떻게 두느냐로 만드는 방식 입니다.
| 전략 | 무엇으로 하는가 | 서비스 중단 | 되돌리는 속도 | 필요한 자원 |
|---|---|---|---|---|
| 롤링 업데이트 | Deployment 설정 | 없음 | 롤백에 시간이 걸림 | 조금 더 |
| Recreate | Deployment 설정 | 있음 | 다시 배포해야 함 | 그대로 |
| 블루그린 | Deployment 2개 + Service 선택 조건 전환 | 없음 | 즉시 | 두 배 |
| 카나리 | Deployment 2개 + 복제본 비율 | 없음 | 빠름 | 조금 더 |
Kubernetes 가 직접 지원하는 것은 앞의 둘뿐입니다. 뒤의 둘은 이미 있는 기능(Service 의 레이블 선택)을 조합해 만듭니다.
롤링 업데이트 — 하나씩 바꾸기
기본값입니다. 새 파드를 하나 띄우고 준비되면 옛 파드를 하나 내리는 식으로 교체합니다.
설정은 Deployment 의 strategy 한 곳에서 끝납니다(3.2 장).
| 좋은 점 | 아쉬운 점 |
|---|---|
| 설정이 간단합니다 | 교체 중에 두 버전이 동시에 돕니다 |
| 자원을 조금만 더 씁니다 | 되돌리려면 다시 롤링으로 바꿔야 해 시간이 걸립니다 |
| 서비스가 끊기지 않습니다 | 문제를 늦게 발견하면 이미 대부분 교체된 뒤입니다 |
대부분의 경우 이것으로 충분합니다. 아래 방식은 이것으로 안 되는 사정이 있을 때 씁니다.
Recreate — 다 내리고 다시 띄우기
옛 파드를 전부 내린 뒤 새 파드를 띄웁니다. 그 사이 서비스가 멈춥니다.
두 버전이 동시에 돌면 안 될 때만 씁니다.
| 쓰는 경우 | 이유 |
|---|---|
| 데이터베이스 스키마가 바뀜 | 옛 버전이 새 스키마를 읽지 못합니다 |
같은 파일을 쓰는데 ReadWriteOnce | 두 파드가 동시에 붙을 수 없습니다(6.1 장) |
| 배타적 잠금을 쓰는 프로그램 | 둘이 동시에 돌면 충돌합니다 |
블루그린 — 다 띄운 뒤 한 번에 옮기기
같은 애플리케이션을 Deployment 두 개로 나눠 두고, Service 가 어느 쪽을 볼지 바꾸는 방식입니다. Service 는 레이블로 파드를 고르므로(5.1 장) 그 조건만 바꾸면 트래픽이 통째로 옮겨 갑니다.
COP 는 이 구성을 샘플 애플리케이션에 미리 만들어 둡니다. egov 네임스페이스를 보면
Deployment 가 넷 있습니다.
| Deployment | 레이블 | 용도 |
|---|---|---|
egov | application: egov | 기본 배포 |
egov-blue | application: egov-blue | 블루그린의 한쪽 |
egov-green | application: egov-green | 블루그린의 다른 쪽 |
egov-hpa | application: egov-hpa | 자동 확장 시연용(3.5 장) |
아래 설명은 이 실제 구성을 그대로 따릅니다.
1. Deployment 를 두 벌 만듭니다. 레이블 하나로 구분합니다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: egov-blue
namespace: egov
spec:
replicas: 2
selector:
matchLabels:
application: egov-blue # 이 값으로 Service 가 고릅니다
template:
metadata:
labels:
application: egov-blue
spec:
containers:
- name: egov-blue
image: registry.example.com/apps/egov:1.0.0
egov-green 은 위와 같고 이름과 레이블만 egov-green, 이미지는 새 버전으로 둡니다.
COP 는 두 벌을 각각 빌드·배포할 수 있게 스크립트 디렉터리도 나눠 둡니다. Bastion 의
workspaces/apps/egov/ 아래에 egov-blue·egov-green 디렉터리가 따로 있고, 각각의
env.sh 에 자기 Deployment 이름이 들어 있습니다(4.5 장). 그래서 한쪽만 새
버전으로 배포할 수 있습니다.
2. Service 는 한쪽만 가리킵니다.
apiVersion: v1
kind: Service
metadata:
name: egov-blue-green
namespace: egov
labels:
application: egov-blue-green
spec:
type: ClusterIP
selector:
application: egov-blue # 지금은 blue 로 보냅니다
ports:
- protocol: TCP
port: 8080
targetPort: 8080
Ingress 는 이 Service 하나만 가리키므로 외부 주소는 전환해도 바뀌지 않습 니다.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: egov-blue-green
namespace: egov
spec:
ingressClassName: default
rules:
- host: egov-blue-green.apps.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: egov-blue-green # Service 는 그대로, 뒤만 바뀝니다
port:
number: 8080
3. 새 버전을 먼저 띄워 확인합니다. egov-green 은 Service 가 가리키지 않으므로 사용자
트래픽을 받지 않습니다. 확인용 Service 를 하나 더 두면 미리 시험할 수 있습니다.
apiVersion: v1
kind: Service
metadata:
name: egov-preview # 확인 전용
namespace: egov
spec:
selector:
application: egov-green
ports:
- port: 8080
targetPort: 8080
4. 전환합니다. Service 의 선택 조건을 egov-green 으로 바꿉니다. Console 의 Service
상세에서 편집하거나 YAML 편집 기로 고칩니다(1.2 장).
spec:
selector:
application: egov-green # egov-blue → egov-green
되돌릴 때는 이 값을 egov-blue 로 돌리면 끝입니다. 옛 버전 파드가 그대로 떠 있으므로 몇
초 안에 원래대로 돌아갑니다. 이것이 블루그린의 가장 큰 이점입니다.
Jenkins 작업이 이 전환을 대신합니다(4.4 장). 전환 대상을 고르면 위 Service 선택 조건 변경을 수행합니다. 실제로 하는 일은 이 한 가지뿐입니다.
| 좋은 점 | 아쉬운 점 |
|---|---|
| 되돌리기가 즉시 됩니다 | 두 버전이 동시에 떠 있어 자원이 두 배 필요합니다 |
| 새 버전을 미리 확인할 수 있습니다 | 데이터베이스를 공유하면 두 버전이 함께 쓸 수 있어야 합니다 |
| 두 버전이 섞여 돌지 않습니다 | 관리할 자원이 늘어납니다 |
전환 뒤 옛 버전을 바로 지우지 마십시오. 문제가 늦게 드러날 수 있으므로 하루 이틀 남겨 두었다가 정리하는 것이 안전합니다. 자원이 아까우면 복제본을 0 으로 줄여 둡니다.
카나리 — 일부에게만 먼저
새 버전을 소수의 파드로만 띄워 일부 사용자에게 먼저 보여 주고, 문제가 없으면 비율을 늘려 갑니다. 광부가 유해 가스를 알아채려고 데려간 새에서 온 이름입니다.
COP 가 미리 만들어 주지는 않습니다. 블루그린과 달리 준비된 구성이 없어 직접 만들어야 합니다. 다만 자원 구성은 블루그린과 거의 같고 Service 가 양쪽을 모두 가리킨다 는 점만 다릅니다.
1. 두 Deployment 에 공통 레이블을 하나 둡니다.
# 안정 버전
apiVersion: apps/v1
kind: Deployment
metadata:
name: egov-stable
namespace: egov
spec:
replicas: 9
selector:
matchLabels:
application: egov-canary # 공통 — Service 가 이것을 봅니다
track: stable # 구분용
template:
metadata:
labels:
application: egov-canary
track: stable
spec:
containers:
- name: egov
image: registry.example.com/apps/egov:1.0.0
# 새 버전 — 처음에는 1개만
apiVersion: apps/v1
kind: Deployment
metadata:
name: egov-canary
namespace: egov
spec:
replicas: 1
selector:
matchLabels:
application: egov-canary # 같은 값
track: canary # 여기만 다릅니다
template:
metadata:
labels:
application: egov-canary
track: canary
spec:
containers:
- name: egov
image: registry.example.com/apps/egov:1.1.0
2. Service 는 공통 레이블만 봅니다.
apiVersion: v1
kind: Service
metadata:
name: egov-canary
namespace: egov
spec:
selector:
application: egov-canary # track 은 넣지 않습니다
ports:
- port: 8080
targetPort: 8080
track 을 빼는 것이 핵심입니다. 넣으면 한쪽만 대상이 되어 블루그린과 같아집니다.
3. 복제본 비율로 단계를 올립니다.
| 단계 | egov-stable | egov-canary | 새 버전이 받는 비율 |
|---|---|---|---|
| 시작 | 9 | 1 | 10% |
| 1차 확대 | 7 | 3 | 30% |
| 2차 확대 | 5 | 5 | 50% |
| 완료 | 0 | 10 | 100% |
Console 의 복제본 수 조절로 단계를 올립니다(위 "복제본 수 조절"). 문제가 보이면 카나리 쪽을 0 으로 내리면 즉시 멈춥니다.
| 좋은 점 | 아쉬운 점 |
|---|---|
| 문제가 있어도 일부 사용자만 겪습니다 | 비율이 파드 수로만 정해집니다 |
| 실제 트래픽으로 확인할 수 있습니다 | 두 버전이 동시에 돌므로 호환되어야 합니다 |
| 자원을 조금만 더 씁니다 | 단계를 사람이 올려야 합니다 |
비율이 정확하지 않습니다. 이 방식의 트래픽 비율은 파드 개수 비율입니다. "5% 에게만" 처럼 세밀하게 나누려면 파드가 20개는 있어야 합니다.