Kubernetes에서 애플리케이션을 구동하면 가장 작은 단위인 파드(Pod)가 생성된다.
하지만 파드는 일시적인 존재로, 장애나 업데이트 시 자동으로 복구되거나 관리되지 않는다는 한계가 있다.
실제 서비스 운영 환경에서는 파드의 수 유지, 무중단 배포, 자동 롤백과 같은 기능이 필요하다.
이 문제를 해결하기 위해 Kubernetes는 Deployment라는 컨트롤러 리소스를 제공한다.
Deployment는 파드의 생애주기를 자동으로 관리하며, 선언적 방식으로 애플리케이션의 상태를 유지한다.
이번 실습에서는 다음의 질문을 중심으로 Deployment를 이해하고 적용해보았다:
- 왜 Deployment가 필요한가?
- 어떤 구조와 역할을 가지고 있는가?
- RollingUpdate, Recreate, Blue/Green 전략은 어떻게 다른가?
- 실시간으로 버전이 교체되는 과정은 어떻게 확인할 수 있는가?
- 문제가 발생했을 때 롤백은 어떻게 처리되는가?
이를 통해 실무에서의 배포 전략과 파드 관리 방식을 직접 경험하고 정리할 수 있었다.
Deployment
파드를 지속적으로 원하는 상태로 유지하고, 자동으로 배포, 복구, 업데이트까지 담당하는 컨트롤러 리소스
왜 필요한가
k8s에서 가장 작은 실행 단위는 파드(Pod), 하지만 파드만 수동으로 만들면 문제가 생김
- 파드가 죽음면 → 자동으로 다시 안 만들어짐
- 여러 개 띄우려면 → 반복적으로 수동 복제
- 롤링 업데이트 → 확인해가며 일일이 삭제하면서 다시 띄워야 함
→ 이걸 자동화 해주는 리소스
핵심 역할
- 파드 수 유지: 설정된 개수를 항상 유지, 죽으면 다시 만들고 반복
- 롤링 업데이트: 새 버전 이미지로 하나 씩 교체하면서 무중단 배포
- 롤백: 문제 발생 시 이전 버전으로 즉시 복구(이전 버전 replicas 0으로 대기)
- 복제: Pod를 원하는 수만큼 자동으로 생성(replicas 설정)
- 셀프힐링: 노드가 죽거나 파드가 종료돼도 자동으로 만들어줌
### ▶ Deployment
apiVersion: apps/v1
kind: Deployment # 파드를 여러 개 관리하고 자동으로 유지하는 리소스
metadata:
namespace: anotherclass-123 # 이 Deployment는 해당 네임스페이스에 속함
name: api-tester-1231 # Deployment 이름 (kubectl 명령에서 사용됨)
labels: # 라벨: 이 리소스를 식별하거나 그룹화할 때 사용
part-of: k8s-anotherclass
component: backend-server
name: api-tester
instance: api-tester-1231
version: 1.0.0
managed-by: dashboard
spec: # spec: 이 리소스가 실제로 어떻게 동작해야 하는지 정의하는 부분
selector: # selector: 어떤 파드를 이 Deployment가 관리할지 지정함
matchLabels: # matchLabels: 라벨이 일치하는 파드를 대상으로 함
part-of: k8s-anotherclass
component: backend-server
name: api-tester
instance: api-tester-1231
replicas: 2 # 파드를 2개 유지함 (장애가 나면 다시 생성)
strategy:
type: RollingUpdate # 무중단 배포 전략. 순차적으로 새 파드를 띄우고 기존 파드를 종료함
template: # 이 템플릿 안에 파드 정의가 들어감
metadata:
labels: # 파드에도 라벨을 붙여서 selector와 연결됨
part-of: k8s-anotherclass
component: backend-server
name: api-tester
instance: api-tester-1231
version: 1.0.0
spec: # 이 파드 안의 컨테이너 구성 정의
nodeSelector:
kubernetes.io/hostname: k8s-master # 이 파드는 k8s-master 노드에만 배치됨
containers:
- name: api-tester-1231 # 컨테이너 이름
image: 1pro/api-tester:v1.0.0 # 사용할 컨테이너 이미지
ports:
- name: http
containerPort: 8080 # 이 컨테이너가 리슨하는 포트
envFrom:
- configMapRef:
name: api-tester-1231-properties # 환경변수를 ConfigMap에서 불러옴
startupProbe: # 시작 시 정상 상태인지 확인하는 probe
httpGet:
path: "/startup" # 어떤 경로를 검사할지
port: 8080 #어떤 포트로 요청할지
periodSeconds: 5 # 몇 초마다 검사할지
failureThreshold: 36 # 몇 번 실패하면 실패로 간주할지
readinessProbe: # 트래픽을 받아도 되는 상태인지 체크
httpGet:
path: "/readiness"
port: 8080
periodSeconds: 10
failureThreshold: 3
livenessProbe: # 살아 있는지 체크. 실패 시 컨테이너 재시작
httpGet:
path: "/liveness"
port: 8080
periodSeconds: 10
failureThreshold: 3
# 이 컨테이너을 돌릴 때 자원을 얼마나 쓸지
resources: # 자원 요청/제한 설정
requests: # 최소 자원 (보장)
memory: "100Mi"
cpu: "100m"
limits: # 최대 자원 (초과 시 제한됨)
memory: "200Mi"
cpu: "200m"
# 볼륨을 어디에 마운트할지
volumeMounts:
- name: files
mountPath: /usr/src/myapp/files/dev # 파드 내 파일이 마운트될 디렉토리
- name: secret-datasource
mountPath: /usr/src/myapp/datasource # DB 정보가 담긴 Secret을 마운트
# 어떤 볼륨을 사용할지
volumes:
- name: files
persistentVolumeClaim:
claimName: api-tester-1231-files # PVC와 연결
- name: secret-datasource
secret:
secretName: api-tester-1231-postgresql # Secret과 연결
주요 필드 설명
1. 메타데이터 관련 → 이 리소스가 뭔지 정의
필드 | 설명 |
apiVersion: apps/v1 | Deployment 리소스는 apps API 그룹에 속하며, 현재 버전은 v1 |
kind: Deployment | 생성할 리소스의 종류가 Deployment |
metadata.name | 이 Deployment의 이름. kubectl get deployment 등 명령어에서 사용 |
metadata.namespace | 이 Deployment가 속한 네임스페이스 |
metadata.labels | 이 리소스를 다른 리소스와 연관시키거나 선택하기 위한 식별자들. 모니터링, 관리 도구에서도 자주 사용됨 |
2. 스펙(spec) → 전체 리소스 제어
2.1 파드 복제 및 유지 전략
필드 | 설명 |
replicas: 2 | 항상 2개의 파드를 유지함. 하나 죽으면 자동으로 다시 생성됨 |
strategy.type: RollingUpdate | 무중단 배포 방식. 새로운 파드를 하나씩 띄우고, 기존 파드를 종료함 |
2.2 selector – 어떤 파드를 관리할지 지정
필드 | 설명 |
selector.matchLabels | 이 라벨이 일치하는 파드만 이 Deployment가 관리함 |
template.metadata.labels | 실제 생성될 파드에 부여할 라벨. 위 selector와 반드시 일치해야 함 |
3. 파드 템플릿 정의(template) → 자신이 관리할 파드의 설정
3.1 스케줄링 관련
필드 | 설명 |
nodeSelector | 특정 노드(k8s-master)에만 이 파드를 배치하도록 지정함. 조건 기반 노드 배치 제어 |
3.2 컨테이너 정의 (containers:)
필드 | 설명 |
name | 컨테이너 이름. Pod 내에서 유일해야 함 |
image | 사용할 Docker 이미지 이름과 태그 |
ports.containerPort | 컨테이너 내부에서 서비스가 사용하는 포트. 예: 8080 |
3.3 환경변수 설정
envFrom:
- configMapRef:
name: api-tester-1231-properties
- Secret을 한꺼번에 파일의 형태로 환경변수로 주입
- spring.datasource.url=${DB_URL} 이런 식으로 코드에서 사용할 수 있음
3.4 헬스체크(프로브)
필드 | 설명 |
startupProbe | 컨테이너가 정상적으로 시작됐는지 확인. 시작 전에만 체크 |
readinessProbe | 트래픽을 받아도 되는 상태인지 체크. 실패하면 서비스에서 제외됨 |
livenessProbe | 컨테이너가 살아 있는지 주기적으로 검사. 실패하면 컨테이너 재시작 |
3.5 자원 제한
resources:
requests:
cpu: "100m"
memory: "100Mi"
limits:
cpu: "200m"
memory: "200Mi"
필드 | 설명 |
requests | 최소 보장 자원. 이만큼은 꼭 주겠다 |
limits | 최대 사용 가능 자원. 이 이상은 제한됨 |
예: CPU 100m → 0.1 core, Memory 100Mi → 약 100MB |
3.6 볼륨 마운트
volumeMounts:
- name: files
mountPath: /usr/src/myapp/files/dev
- 앞에서 배운 PVC로 PV를 마운트함
- 파일 기반 설정 또는 파일 저장에 사용
4. 📦 volumes: 정의
필드 | 설명 |
persistentVolumeClaim.claimName | PVC를 참조하여 외부 저장소를 연결함 |
secret.secretName | Secret을 컨테이너 내부 경로에 마운트할 수 있도록 지정함 |
여기서 사용할 PVC랑 secret 정의함
추가) Deployment 전략(strategy)
spec.starategy는 어떻게 파드를 업데이트할지를 정하는 것
새 버전의 이미지로 바꿀 때 기존 파드를 어떤 방식으로 교체할 것인지를 지정하는 전략
전략은 Recreate와 기본값인 RollingUpdate, k8s 기본 기능은 아닌 Blue/Green이 있음
- Recreate 전략→ 서비스 중단이 필연적으로 발생
- 기존 파드를 전부 종료하고 새 파드를 다시 생성하는 방식
- RollingUpdate 전략→ 서비스 중단 없이 즉 무중단 배포 가능
- maxSurge: 새 파드를 몇 개 더 띄울 수 있는지
- maxUnavailable: 동시에 꺼질 수 있는 기존 파드 수
- 최대 150%의 리소스 사용량 증가가 있음 → 기존의 것을 대체하기 위해 두 버전이 동시에 존재하는 타이밍
- 기존 파드를 하나씩 종료하면서 동시에 새 파드를 생성
- Blue/Green 전략2개의 버전을 완전히 띄우야 하니 리소스 사용량 200% 증가
- 완전히 새로운 버전을 새롭게 배포하고 → 트래픽을 구버전에서 신버전으로 차츰차츰 옮기는 방식
만약 template의 어떠한 값이라도 바뀌면 바로 새 ReplicaSet을 만듬 그 후 정해진 전략으로 배포를 함
→ 템플릿이 바뀌었다는건 Pod를 생성하는 방식이 달라졌다는 것이고 그거에 맞춰 다른 파드도 변경해야하니까.
실습
지금 하나는 V1 하나는 V2로 변경된 상황
V2 생성 중일 때 해당 파드는 V1으로 동작 중 → 이게 롤링업뎃
1. RollingUpdate 하기
// 1) HPA minReplica 2로 바꾸기 (이전 강의에서 minReplicas를 1로 바꿔놨었음)
kubectl patch -n anotherclass-123 hpa api-tester-1231-default -p '{"spec":{"minReplicas":2}}'
// 1) 그외 Deployment scale 명령
kubectl scale -n anotherclass-123 deployment api-tester-1231 --replicas=2
// 1) edit로 모드로 직접 수정
kubectl edit -n anotherclass-123 deployment api-tester-1231
// 2) 지속적으로 Version호출 하기 (업데이트 동안 리턴값 관찰)
while true; do curl http://192.168.56.30:31231/version; sleep 2; echo ''; done;
// 3) 별도의 원격 콘솔창을 열어서 업데이트 실행
kubectl set image -n anotherclass-123 deployment/api-tester-1231 api-tester-1231=1pro/api-tester:v2.0.0
kubectl set image -n anotherclass-123 deployment/api-tester-1231
// update 실행 포맷
// kubectl set image -n <namespace> deployment/<deployment-name> <container-name>=<image-name>:<tag>
kubectl set image -n <namespace> deployment/<deployment-name> <container-name>=<image-name>:<tag>
2. RollingUpdate (maxUnavailable: 0%, maxSurge: 100%) 하기
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: anotherclass-123
name: api-tester-1231
spec:
replicas: 2
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 25% -> 0% # 수정
maxSurge: 25% -> 100% # 수정
kubectl set image -n anotherclass-123 deployment/api-tester-1231 api-tester-1231=1pro/api-tester:v1.0.0
이렇게 Blue/Green 처럼 만들 파드들 동시에 다 띄우고 모두가 활성화 됐을 때 과거의 것이 교체가 됨
이렇게 한 번에 교체되는 모습(v2 -> v1)
3. Recreate 하기
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: anotherclass-123
name: api-tester-1231
spec:
replicas: 2
strategy:
type: RollingUpdate -> Recreate # 수정
rollingUpdate: # 삭제
maxUnavailable: 0% # 삭제
maxSurge: 100% # 삭제
kubectl set image -n anotherclass-123 deployment/api-tester-1231 api-tester-1231=1pro/api-tester:v2.0.0
모든 파드들이 다 내려가고 서비스 중단됨
그 후 모든 파드가 만들어지고 서비스 재개
4. Rollback
// 이전 버전으로 롤백
kubectl rollout undo -n anotherclass-123 deployment/api-tester-1231
마무리
개요의 질문에 대한 답
- 왜 Deployment가 필요한가?
- 파드의 수를 자동으로 유지하고, 무중단 배포 및 복구를 지원해 안정적인 애플리케이션 운영을 가능하게 한다.
- 어떤 구조와 역할을 가지고 있는가?
- Deployment는 템플릿 기반으로 파드를 정의하고, ReplicaSet을 통해 원하는 수의 파드를 지속적으로 관리한다.
- RollingUpdate, Recreate, Blue/Green 전략은 어떻게 다른가?
- RollingUpdate는 점진적 교체, Recreate는 전체 종료 후 재생성, Blue/Green은 새 버전 전체를 띄운 뒤 트래픽 전환 방식이다.
- 실시간으로 버전이 교체되는 과정은 어떻게 확인할 수 있는가?
- 서비스 endpoint를 주기적으로 호출하면서 버전 응답 값의 변경을 통해 업데이트 상태를 확인할 수 있다.(실습으로 확인)
- 문제가 발생했을 때 롤백은 어떻게 처리되는가?
- kubectl rollout undo 명령어를 사용해 이전 버전으로 빠르게 롤백할 수 있다.
- 빠르게 가능한 이유는 이전 버전의 ReplicaSet을 삭제하지 않고, "replicas:0"으로 보관하고 있기 때문임
파드를 자동으로 만들고, 배포하고, 파드 상태도 보는 k8s 운영에 가장 중요한 리소스라고 생각한다.
이번 포스팅을 적으면서 Deployment에 대해서 자세히 알게 됐고 실습을 통해 배포 전략별로 어떻게 동작하는 지 확인했다.
특히 롤링업데이트의 maxUnavailable, maxSurge의 값을 변경하므로써 다양한 배포 전략을 만들 수 있는게 흥미로웠다.
또한 롤링 업데이트는 무중단 배포라는 큰 장점이 있지만, 이전 버전의 파드와 새로운 버전의 파드가 공존해야 한다는 문제 때문에 고려할게 많을 것 같고, 그렇다고 blue/green을 하자니 리소스가 2배나 들고, recreate를 하자니 서비스가 중단되어야 하고..
이런 부분을 설계하고 조정하는게 서비스에 상당히 중요한 부분인 것 같다.
'공부일지 > K8S 스터디' 카테고리의 다른 글
[k8s 스터디] #10 HPA (0) | 2025.05.26 |
---|---|
[k8s 스터디] #09 Service (0) | 2025.05.26 |
[k8s 스터디] #07 PV(Persistent Volume)/PVC(PV Claim) (1) | 2025.05.26 |
[k8s 스터디] #06 ConfigMap, Secret (0) | 2025.05.24 |
[k8s 스터디] #05 Application 기능 이해하기 Probe (0) | 2025.05.11 |