이 챕터의 범위: Deployment와 배포 전략
- 컨테이너화된 애플리케이션을 운영하다 보면 새 버전 배포가 반복적으로 발생한다
- Kubernetes는 Deployment 리소스를 통해 이 과정을 선언적으로, 자동으로 처리한다
- 이 챕터는 Deployment의 동작 원리와 네 가지 배포/릴리즈 전략을 다룬다
0. Contents
선언적 배포의 핵심
- Kubernetes에서 애플리케이션을 배포한다는 것은 YAML 파일을 작성하고
kubectl apply를 실행하는 것이다 - 그 뒤의 모든 과정은 Kubernetes가 처리한다
- Pod 생성
- 헬스체크
- 순차 교체
- 실패 시 롤백
- 이것이 선언적 배포의 핵심이다
1. Problem & Solution
1.1 Problem
마이크로서비스 환경의 업데이트
- 마이크로서비스 환경에서는 서비스 수가 많다
- 각 서비스가 독립적으로 업데이트된다
한 서비스를 새 버전으로 교체하는 단계
- 새 버전 Pod 실행
- 기존 Pod 안전하게 종료 (graceful shutdown)
- 새 Pod 정상 실행 여부 확인
- 실패 시 이전 버전으로 롤백
문제: 수동 배포와 스크립트의 한계
- 이 과정을 수동으로 하면 → 사람 실수가 생긴다
- 스크립트로 자동화하면 → 유지 비용이 크다
- 서비스가 많아질수록 배포 자체가 병목이 된다
업데이트 방식 두 가지
| 방식 | 설명 | 단점 |
|---|---|---|
| 다운타임 허용 | 기존 전부 종료 후 새 버전 실행 | 서비스 중단 |
| 다운타임 없음 | 구버전과 신버전 동시 실행 | 리소스 2배 사용 |
1.2 Solution
해법: Deployment 리소스
- Kubernetes의 Deployment 리소스가 이 문제를 해결한다
- Deployment는 “이런 상태여야 해"라고 선언해두면 나머지를 자동으로 처리하는 주문서다
| 누가 | 할 일 |
|---|---|
| 개발자 | YAML 파일 작성 + kubectl apply |
| Kubernetes | Pod 생성, 교체, 헬스체크, 롤백 전부 |
자동화의 효과
- 릴리즈 사이클마다 수십 번 배포가 반복되는 환경에서, 이 자동화는 운영 비용을 크게 줄인다
2. How Deployment Works
2.1 Deployment → ReplicaSet → Pod
Deployment와 ReplicaSet의 관계
- Deployment는 직접 Pod를 만들지 않는다
- 내부적으로 ReplicaSet을 생성하고, ReplicaSet이 Pod를 관리한다
업데이트 시 ReplicaSet 동작
- 새 ReplicaSet이 추가로 생성된다
- 기존 ReplicaSet의 Pod를 하나씩 줄이면서 새 ReplicaSet의 Pod를 늘린다
- 업데이트가 완료된 후에도 기존 ReplicaSet은 삭제되지 않고 replicas=0 상태로 남는다
- 롤백 시 재사용하기 위해서다
2.2 Prerequisites for Deployment
컨테이너의 두 가지 전제 조건
- Deployment가 Pod를 예측 가능하게 시작하고 종료하려면 컨테이너가 두 가지를 갖춰야 한다
| 조건 | 설명 | 관련 챕터 |
|---|---|---|
| Lifecycle 이벤트 처리 | SIGTERM 수신 시 작업을 마무리하고 종료 | Chapter 5, Managed Lifecycle |
| Health-check endpoint | readinessProbe로 준비 완료 여부를 알림 | Chapter 4, Health Probe |
전제 조건이 없을 때
- 이 두 가지가 없으면 Kubernetes는 알 수 없다
- Pod가 언제 준비됐는지
- 언제 안전하게 종료할 수 있는지
2.3 kubectl rollout
YAML 수정과 rollout 명령어
- Deployment는 YAML 파일 수정만으로도 관리할 수 있다
- 일상적인 작업에는
kubectl rollout명령어가 편리하다
참고: 명령형에서 선언형으로
- Kubernetes 1.18 이전에는
kubectl rolling-update명령어가 있었다- 클라이언트(kubectl)가 각 업데이트 단계를 직접 서버에 지시하는 명령형 방식이었다
- 현재의
kubectl rollout은 선언형 방식이다- 서버 측에서 Deployment 선언을 기반으로 Kubernetes가 알아서 처리한다
| 명령어 | 역할 |
|---|---|
kubectl rollout status | 현재 배포 진행 상태 확인 |
kubectl rollout pause | 롤아웃 일시 중지 |
kubectl rollout resume | 일시 중지된 롤아웃 재개 |
kubectl rollout undo | 이전 버전으로 롤백 |
kubectl rollout history | 배포 히스토리 확인 |
kubectl rollout restart | 현재 Pod 재시작 (업데이트 없이) |
3. Rolling Deployment
Deployment의 기본 전략
- RollingUpdate는 Deployment의 기본 전략이다
- Pod를 하나씩 교체하면서 항상 일정 수 이상의 Pod가 살아있도록 보장한다
- → 서비스 중단 없이 업데이트할 수 있다
3.1 Example YAML
# Example 3-1. Deployment for a rolling update
apiVersion: apps/v1
kind: Deployment
metadata:
name: random-generator
spec:
replicas: 3 # Pod 3개 유지 (롤링 업데이트는 2개 이상 필요)
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # 업데이트 중 추가로 띄울 수 있는 Pod 수 → 최대 4개
maxUnavailable: 1 # 동시에 꺼져도 되는 Pod 수 → 최소 2개 유지
minReadySeconds: 60 # 새 Pod readinessProbe 성공 후 60초 대기
selector:
matchLabels:
app: random-generator
template:
metadata:
labels:
app: random-generator
spec:
containers:
- image: k8spatterns/random-generator:1.0
name: random-generator
readinessProbe: # 롤링 배포에서 핵심. 절대 빠뜨리면 안 됨
exec:
command: [ "stat", "/tmp/random-generator-ready" ]
3.2 maxSurge & maxUnavailable
설정 단위와 기본값
- 두 필드 모두 절댓값 또는 퍼센트(%)로 설정할 수 있다
- 퍼센트일 때 replicas 수를 기준으로 계산한다
- maxSurge는 올림
- maxUnavailable은 내림으로 처리한다
- 기본값은 둘 다 25%다
replicas: 3, maxSurge: 1, maxUnavailable: 1 기준
- 최대 Pod 수 = 3 + 1 = 4개 (maxSurge)
- 최소 Pod 수 = 3 - 1 = 2개 (maxUnavailable)
- → 업데이트 중 항상 2~4개 사이에서 유지
값 크기에 따른 차이
- 숫자를 키우면 → 교체 속도가 빨라진다
- 줄이면 → 느리지만 안정적이다
3.3 minReadySeconds
준비 완료 인정 기준
- 새 Pod의 readinessProbe가 이 시간(초) 동안 연속으로 성공해야 “준비 완료"로 인정한다
- 그 뒤에 다음 Pod 교체를 시작한다
큰 값의 장점
- 값을 크게 설정할수록 안전하다
- 교체 사이사이에 여유가 생겨
kubectl rollout pause로 일시 중지하기도 쉽다
3.4 Rolling Update Step-by-Step
전체 흐름 요약
- 아래는 전체 흐름을 한 장으로 정리한 그림이다
업데이트 중 Pod 수
- 업데이트 내내 Pod 수는 2개(최소)와 4개(최대) 사이에서 유지된다
- 사용자는 서비스 중단을 느끼지 못한다
3.5 How to Trigger an Update
업데이트 시작 방법 세 가지
# 1. 새 YAML 파일로 통째로 교체
kubectl replace -f new-deployment.yaml
# 2. 특정 부분만 수정
kubectl patch deployment random-generator \
-p '{"spec":{"template":{"spec":{"containers":[{"name":"random-generator","image":"k8spatterns/random-generator:2.0"}]}}}}'
# 또는 에디터로 직접 수정
kubectl edit deployment random-generator
# 3. 이미지만 바꿀 때 (가장 간단)
kubectl set image deployment/random-generator \
random-generator=k8spatterns/random-generator:2.0
| 방법 | 언제 쓰나 |
|---|---|
kubectl replace | 변경사항이 많을 때 |
kubectl patch / edit | 일부 필드만 수정할 때 |
kubectl set image | 이미지 버전만 바꿀 때 |
3.6 Benefits of Deployment
네 가지 구조적 장점
- 명령형 방식의 단점을 해결하는 것 외에 Deployment는 네 가지 구조적 장점을 가진다
서버 측 자동 관리
- 업데이트 전 과정이 서버에서 처리된다
- 클라이언트(개발자)의 개입 없이 Kubernetes가 상태를 유지한다
선언적 목표 지향
- “어떻게 해라"가 아니라 “이런 상태여야 해"를 선언한다
- 도달 방법은 Kubernetes가 결정한다
환경 간 재사용
- YAML 파일은 단순 문서가 아니라 실행 가능한 객체다
- 개발 → 스테이징 → 운영 환경에서 같은 파일을 그대로 사용할 수 있다
버전 관리와 롤백
- 업데이트 과정이 전부 기록되고 버전이 매겨진다
kubectl rollout history로 확인한다kubectl rollout undo로 언제든 롤백할 수 있다
4. Fixed Deployment (Recreate)
RollingUpdate의 단점: 두 버전 동시 실행
- RollingUpdate의 단점은 업데이트 중 두 버전이 동시에 실행된다는 것이다
- API가 하위 호환이 되지 않는 변경이 있을 때 문제가 생긴다
예: 응답 필드명 변경
- 응답 필드명이
price에서amount로 바뀌었다면- v1 Pod와 v2 Pod가 공존하는 시간 동안 클라이언트는 어떤 응답이 올지 예측할 수 없다
- 이 경우 Recreate 전략을 사용한다
spec:
strategy:
type: Recreate # maxUnavailable = replicas 전체로 설정하는 것과 같음
Recreate의 동작
- Recreate는
maxUnavailable을 replicas 수 전체로 설정한 것과 동일하게 동작한다 - 기존 Pod를 전부 종료한 뒤 새 Pod를 전부 동시에 시작한다
- 중간에 다운타임이 발생한다
- 대신 두 버전이 절대 공존하지 않는다는 것이 보장된다
| RollingUpdate | Recreate | |
|---|---|---|
| 다운타임 | 없음 | 있음 |
| v1/v2 공존 | 있음 | 없음 |
| API 호환성 문제 | 발생 가능 | 없음 |
| 언제 사용 | 일반적인 업데이트 | API 크게 변경 시 |
5. Blue-Green Release
기본 리소스 조합으로 만드는 전략
- Blue-Green은 Kubernetes 기본 제공 전략이 아니다
- Deployment와 Service 같은 기본 리소스를 조합해서 구현하는 고급 릴리즈 전략이다
구현 방식
# Blue Deployment (기존 v1.0)
metadata:
name: app-blue
spec:
replicas: 3
template:
metadata:
labels:
app: random-generator
version: v1.0 # Blue 식별 라벨
# Green Deployment (새 v1.1)
metadata:
name: app-green
spec:
replicas: 3
template:
metadata:
labels:
app: random-generator
version: v1.1 # Green 식별 라벨
# Service - selector 변경으로 트래픽 전환
spec:
selector:
app: random-generator
version: v1.0 # → v1.1로 바꾸면 즉시 Green으로 전환
전환 흐름
| 내용 | |
|---|---|
| 장점 | 한 버전만 서비스 → 클라이언트 단순, 즉시 롤백 가능 |
| 단점 1 | 두 환경이 동시에 뜨는 동안 리소스 2배 필요 |
| 단점 2 | 오래 실행 중인 프로세스나 DB 스키마 변경 시 복잡성 증가 |
6. Canary Release
전략 개요: 일부 Pod 먼저 교체
- Canary는 전체 Pod 중 일부만 새 버전으로 교체해서 소수의 사용자가 먼저 경험하게 하는 전략이다
- 새 버전에 문제가 없다고 확인되면 나머지를 교체한다
이름의 유래
- 광산에서 유독가스 감지를 위해 카나리아 새를 먼저 들여보내던 데서 이름이 유래했다
구현: 두 개의 Deployment
# 기존 Deployment (v1) - replicas 많음
metadata:
name: app-v1
spec:
replicas: 4
# Canary Deployment (v2) - replicas 적음
metadata:
name: app-v2
spec:
replicas: 1 # 전체의 20%만
트래픽 분산 방식
- 두 Deployment가 같은 라벨을 공유하면 Service가 자동으로 트래픽을 분산한다
전체 5개 Pod 중
- v1 Pod 4개 → 트래픽 80%
- v2 Pod 1개 → 트래픽 20%
확인 후 전환 과정
# v2 문제없으면 점진적 전환
kubectl scale deployment app-v2 --replicas=5
kubectl scale deployment app-v1 --replicas=0
# v2 문제 있으면 즉시 롤백
kubectl delete deployment app-v2
Canary와 RollingUpdate의 목적 차이
- 겉보기에 비슷하지만 목적이 다르다
| RollingUpdate | Canary | |
|---|---|---|
| 목적 | 빠른 전체 교체 | 안전한 검증 후 교체 |
| 전환 주체 | Kubernetes 자동 | 사람이 판단 |
| 모니터링 | 없음 | 각 단계마다 확인 |
| 트래픽 조절 | 불가 | 가능 |
7. Strategy Comparison
기본 전략과 고급 전략
- 기본 전략(RollingUpdate, Recreate)은 Kubernetes가 완전 자동으로 처리한다
- 고급 전략(Blue-Green, Canary)은 전환 시점을 사람이 판단해야 한다
- Kubernetes가 직접 지원하지 않는다
8. Higher-Level Deployments
별도 플랫폼이 필요한 이유
- Deployment는 RollingUpdate와 Recreate만 기본 제공한다
- Blue-Green과 Canary를 선언적으로 자동화하려면 별도 플랫폼이 필요하다
공통 기반: Operator 패턴
- 이 플랫폼들은 모두 Operator 패턴(Chapter 28)을 기반으로 동작한다
- 새로운 커스텀 리소스 타입을 도입해 롤아웃 동작을 선언하면, Operator가 서버 측에서 필요한 작업을 처리한다
- 일부는 업데이트 오류 시 자동 롤백도 지원한다
Flagger
- Flux CD GitOps 도구의 일부다
- 카나리와 Blue-Green 배포를 지원한다
- 인그레스 컨트롤러와 서비스 메시와 통합해 트래픽 분할을 처리한다
- 커스텀 메트릭으로 롤아웃 상태를 모니터링하고 실패 시 자동 롤백한다
Argo Rollouts
- Argo CD GitOps 생태계의 일부로, Kubernetes를 위한 CD 솔루션이다
- Flagger와 기능이 유사하며, 인그레스 컨트롤러와 서비스 메시를 지원한다
- Flagger와 Argo Rollouts 중 선택은 어떤 GitOps 플랫폼을 사용하는지에 따라 결정하면 된다
Knative
- Kubernetes 위의 서버리스 플랫폼이다
- 트래픽 기반 오토스케일링이 핵심 기능이다(Chapter 29)
- 트래픽 분할을 통한 간단한 배포 지원도 제공한다
- Flagger나 Argo Rollouts만큼 고급 롤아웃 기능을 제공하지는 않는다
- 이미 Knative를 사용하는 환경이라면 별도 도구 없이 활용할 수 있다
소속 재단
- 세 프로젝트 모두 CNCF(Cloud Native Computing Foundation) 소속이다
9. Q & A
Q1. Deployment와 Pod를 직접 만드는 것의 차이
Pod 직접 생성과 Deployment의 차이
- Pod를 직접 생성하면 해당 Pod가 종료될 때 아무도 살려주지 않는다
- Deployment를 사용하면 Pod가 죽어도 Kubernetes가 자동으로 새 Pod를 만들어 선언된 수를 유지한다
결론: 운영 환경은 Deployment
- Deployment 없이 Pod를 직접 운영하는 것은 구성 파일 없이 서버를 수동으로 관리하는 것과 같다
- 운영 환경에서는 반드시 Deployment를 사용해야 한다
Q2. Rolling Update 중 두 버전이 공존하면 문제가 없나
문제없는 경우: 하위 호환 변경
- API 응답 구조가 동일하게 유지되는 경우라면 문제없다
- 하위 호환성이 보장되는 변경이 이에 해당한다
- 예: 기존 필드를 유지하면서 새 필드를 추가하는 경우
문제가 되는 경우: 하위 호환이 깨지는 변경
- 기존 필드를 삭제하거나 이름을 변경하는 등 하위 호환이 깨지는 변경
- → 두 버전 공존이 클라이언트 오류를 유발한다
- 이 경우 Recreate 또는 Blue-Green 전략을 선택해야 한다
Q3. Blue-Green과 Canary의 선택 기준
같은 문제, 다른 방식
- 두 전략 모두 두 버전 공존 문제를 해결하지만 방식이 다르다
Blue-Green: 순간 전환
- Blue-Green은 전환이 순간적으로 이루어진다
- 신버전이 완전히 준비된 후 트래픽을 한꺼번에 전환한다
- → 전환 중 두 버전이 동시에 트래픽을 받는 시간이 없다
- 대신 리소스가 일시적으로 2배 필요하다
Canary: 점진적 전환
- Canary는 소수 사용자에게 먼저 노출해서 실제 트래픽으로 검증한 뒤 점진적으로 전환한다
- 리소스 효율은 좋다
- 대신 검증 기간 동안 두 버전이 공존한다
선택 기준
- API가 크게 바뀌었다면 → Blue-Green이 맞다
- 새 버전의 안정성을 실사용자로 검증하면서 위험을 최소화하고 싶다면 → Canary가 맞다
