Back to Notes

Notes

K8s 10. Deployment와 Rollout

Kubernetes Deployment의 구조와 desired state, ReplicaSet, Pod template, rolling update, rollback, scaling, troubleshooting 흐름을 운영 관점에서 정리한다.

Published
Updated
Area
Cloud Infrastructure
Type
concept
Series
Kubernetes Essentials
Category
Notes
KubernetesDeploymentReplicaSetPodRolling UpdateRollbackTroubleshootingReadiness ProbeRolloutkubectl

Kubernetes에서 application을 배포할 때 가장 자주 사용하는 workload object는 Deployment다. Pod를 직접 만들 수도 있지만, 운영 환경에서 중요한 것은 단순히 container 하나를 실행하는 것이 아니라, 원하는 replica 수를 유지하고, 새 version을 안전하게 배포하고, 문제가 생기면 상태를 확인하고 되돌릴 수 있는 구조를 갖추는 것이다.

Deployment는 이 역할을 담당한다.

Deployment

ReplicaSet

Pod

Container

Deployment는 단순히 Pod 하나를 만드는 YAML이 아니다. Deployment는 “이 application을 어떤 container image로 몇 개 replica만큼 계속 유지할 것인가”를 선언하고, Kubernetes가 그 desired state를 실제 ReplicaSetPod로 맞추게 하는 workload controller다.


핵심 요약

Deployment는 stateless application 운영의 기본 단위다.

원하는 replica 수
Pod template
ReplicaSet 생성
rolling update
rollout status
rollback
self-healing

핵심 구조는 다음이다.

Deployment

ReplicaSet

Pod

Container

문제가 생겼을 때는 다음 세 층으로 나눠서 보는 것이 좋다.

Manifest / API layer
  → YAML, apiVersion, kind, selector, field 위치 확인

Controller / Rollout layer
  → Deployment condition, ReplicaSet, rollout status 확인

Pod / Runtime layer
  → Pod status, events, logs, probes, image pull, app error 확인

한 문장으로 정리하면 다음과 같다.

Kubernetes Deployment는 stateless application의 desired state를 선언하고, ReplicaSet과 Pod를 통해 replica 유지, rolling update, rollback, self-healing을 수행하게 하는 Kubernetes의 핵심 workload controller다.


Deployment를 왜 쓰는가?

Kubernetes에서 가장 작은 실행 단위는 Pod다. 그래서 처음에는 “그냥 Pod YAML을 만들면 되지 않나?”라고 생각할 수 있다.

예를 들어 Pod 하나를 직접 만들 수 있다.

apiVersion: v1
kind: Pod
metadata:
  name: api
spec:
  containers:
    - name: api
      image: registry.example.com/api:1.0.0
      ports:
        - containerPort: 3000

이 YAML은 Pod 하나를 만든다. 하지만 운영 환경에서는 Pod를 직접 관리하는 방식이 적합하지 않다.

문제가 많다.

Pod가 죽으면 누가 다시 만들 것인가?
Pod를 3개 유지하려면 어떻게 할 것인가?
image version을 바꿀 때 기존 Pod와 새 Pod를 어떻게 교체할 것인가?
rollout이 실패하면 어떻게 되돌릴 것인가?
Pod가 어느 ReplicaSet에 속하는지 어떻게 추적할 것인가?

Deployment는 이 문제를 해결한다.

Deployment는 “Pod 하나를 만들어라”가 아니라 다음처럼 선언한다.

이 image를 사용하는 Pod를 항상 3개 유지해라.
새 version으로 바뀌면 안전하게 rollout해라.
문제가 생기면 rollout status를 확인하고 rollback할 수 있게 해라.

Deployment의 기본 구조

가장 기본적인 Deployment 예시는 다음과 같다.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
spec:
  replicas: 3
  selector:
    matchLabels:
      app: api
  template:
    metadata:
      labels:
        app: api
    spec:
      containers:
        - name: api
          image: registry.example.com/api:1.0.0
          ports:
            - containerPort: 3000

이 YAML을 한 줄씩 보면 Deployment의 핵심이 보인다.


apiVersion

apiVersion: apps/v1

Deploymentapps/v1 API group에 속한다.

주의할 점은 apiVersion이 application version이 아니라는 것이다. application을 upgrade한다고 해서 apiVersion을 바꾸는 것이 아니다. image tag나 Pod template을 바꾸는 것이지, Deployment API version을 application version처럼 올리는 것이 아니다.

잘못된 사고방식:

apiVersion: apps/v1
image: api:1.0.0

upgrade 후

apiVersion: apps/v2
image: api:2.0.0

올바른 사고방식:

apiVersion은 Kubernetes API의 version이다.
application version은 container image tag 또는 appVersion 등으로 관리한다.

즉 application upgrade는 보통 다음을 바꾸는 것이다.

image: registry.example.com/api:1.1.0

apiVersion은 Kubernetes object schema를 가리키는 것이지, application version을 가리키는 것이 아니다.


kind

kind: Deployment

이 resource가 Deployment임을 나타낸다.

Deployment는 Pod를 직접 만드는 object가 아니라, ReplicaSet을 통해 Pod 집합을 관리하는 controller object다.

Deployment
  → ReplicaSet 생성/관리
  → ReplicaSet이 Pod 생성/관리

metadata.name

metadata:
  name: api

Deployment의 이름이다.

이 이름은 이후 명령에서 사용된다.

kubectl get deployment api
kubectl describe deployment api
kubectl rollout status deployment/api
kubectl rollout history deployment/api

운영 환경에서는 namespace도 함께 명시하는 것이 안전하다.

kubectl get deployment api -n production
kubectl describe deployment api -n production
kubectl rollout status deployment/api -n production

spec.replicas

spec:
  replicas: 3

원하는 Pod replica 수다.

이 값은 “현재 3개 만들고 끝”이 아니라 “항상 3개를 유지”하라는 desired state다.

desired replicas = 3
actual replicas = 2
action = Pod 1개 추가 생성

Pod 하나가 죽으면 ReplicaSet이 새 Pod를 만든다. Node 장애 등으로 Pod가 사라져도 Kubernetes는 가능한 범위에서 desired replica 수를 맞추려 한다.


spec.selector

selector:
  matchLabels:
    app: api

Deployment가 어떤 Pod를 자기 관리 대상으로 볼지 결정하는 selector다.

이 selector는 매우 중요하다. 아래의 Pod template label과 맞아야 한다.

template:
  metadata:
    labels:
      app: api

즉 다음 둘은 연결되어야 한다.

Deployment selector:
  app=api

Pod template label:
  app=api

만약 selector와 template label이 맞지 않으면 Deployment가 자신이 만든 Pod를 제대로 관리할 수 없다.


spec.template

template:
  metadata:
    labels:
      app: api
  spec:
    containers:
      - name: api
        image: registry.example.com/api:1.0.0

templateDeployment가 만들 Pod의 설계도다.

Deployment 자체는 container를 직접 실행하지 않는다. Deployment는 이 Pod template을 기준으로 ReplicaSet을 만들고, ReplicaSet이 Pod를 만든다.

Deployment.spec.template

ReplicaSet

Pod

Deployment에서 rollout이 발생하는 핵심 기준도 이 spec.template이다.

예를 들어 다음 변경은 새 revision을 만든다.

container image 변경
container env 변경
Pod template label 변경
Pod template annotation 변경
probe 변경
resource requests/limits 변경

반면 replicas만 바꾸는 scaling은 일반적으로 새 revision을 만들지 않는다.


Deployment, ReplicaSet, Pod의 관계

Deployment를 이해하려면 이 세 object의 역할을 분리해야 한다.

Object역할
Deploymentapplication의 desired state와 rollout 전략을 관리
ReplicaSet특정 Pod template에 해당하는 Pod replica 수를 유지
Pod실제 container가 실행되는 단위

구조는 다음과 같다.

Deployment/api

ReplicaSet/api-7f9d8c9c8

Pod/api-7f9d8c9c8-abcde
Pod/api-7f9d8c9c8-fghij
Pod/api-7f9d8c9c8-klmno

image를 api:1.0.0에서 api:1.1.0으로 바꾸면 새 ReplicaSet이 만들어진다.

Deployment/api
  ├─ ReplicaSet/api-old
  │   └─ Pods using api:1.0.0

  └─ ReplicaSet/api-new
      └─ Pods using api:1.1.0

rolling update 중에는 old ReplicaSet과 new ReplicaSet이 동시에 존재할 수 있다.

api:1.0.0 Pod 2개
api:1.1.0 Pod 1개

잠시 후

api:1.0.0 Pod 1개
api:1.1.0 Pod 2개

완료 후

api:1.0.0 Pod 0개
api:1.1.0 Pod 3개

Deployment 생성 흐름

Deployment YAML을 적용한다.

kubectl apply -f deployment.yaml

그러면 Kubernetes 내부에서는 대략 다음 일이 발생한다.

1. API Server가 Deployment object를 저장한다.
2. Deployment Controller가 새 Deployment를 감지한다.
3. Deployment Controller가 ReplicaSet을 만든다.
4. ReplicaSet Controller가 필요한 Pod 수를 계산한다.
5. Scheduler가 Pod를 실행할 Node를 선택한다.
6. 각 Node의 kubelet이 container runtime을 통해 container를 실행한다.
7. Deployment status가 업데이트된다.

사용자는 YAML 하나를 적용했지만, 실제로는 여러 controller가 이어서 동작한다.

kubectl apply

Deployment

ReplicaSet

Pod

Container

Deployment 확인 명령

Deployment를 만들었으면 먼저 전체 상태를 확인한다.

kubectl get deployments

예시:

NAME   READY   UP-TO-DATE   AVAILABLE   AGE
api    3/3     3            3           2m

각 column의 의미는 다음과 같다.

항목의미
READY준비된 Pod 수 / 원하는 Pod 수
UP-TO-DATE최신 Pod template 기준으로 생성된 Pod 수
AVAILABLE실제 사용 가능한 Pod 수
AGEresource 생성 후 경과 시간

Pod도 확인한다.

kubectl get pods

ReplicaSet도 확인할 수 있다.

kubectl get replicasets

상세 정보는 describe로 본다.

kubectl describe deployment api

kubectl describe는 resource의 상세 설명과 관련 event/controller 정보를 보여주므로, 단순 get보다 더 많은 힌트를 준다.


Deployment에서 디버깅해야 하는 3개 층

운영 관점에서는 Deployment 문제를 다음 3개 층으로 나눠 보면 좋다.

1. Manifest / API layer
   → YAML이 올바른가? Kubernetes API가 받아들일 수 있는가?

2. Controller / Rollout layer
   → Deployment, ReplicaSet, rollout 상태가 올바른가?

3. Pod / Runtime layer
   → Pod가 실제로 뜨고 application container가 정상 동작하는가?

이 세 층을 분리하면 문제를 훨씬 빠르게 좁힐 수 있다.


1단계: Manifest / API layer 디버깅

첫 번째는 YAML 자체를 확인하는 것이다.

잘못된 YAML은 Kubernetes API Server에서 거절된다.

예를 들어 apiVersion이 틀렸거나, kind가 잘못되었거나, field 위치가 잘못되면 적용되지 않는다.

kubectl apply -f deployment.yaml

가능한 오류:

error: unable to recognize "deployment.yaml": no matches for kind "Deployment" in version "apps/v2"

이런 경우는 application 문제가 아니라 Kubernetes API schema 문제다.

자주 나오는 YAML 실수

apiVersion을 application version처럼 바꿈

잘못된 예:

apiVersion: apps/v2
kind: Deployment
metadata:
  name: api

Deployment의 안정적인 API version은 apps/v1이다. application을 1.0.0에서 2.0.0으로 올린다고 해서 apiVersionapps/v2가 되는 것이 아니다.

올바른 예:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
spec:
  template:
    spec:
      containers:
        - name: api
          image: registry.example.com/api:2.0.0

selector와 template label 불일치

잘못된 예:

selector:
  matchLabels:
    app: api
template:
  metadata:
    labels:
      app: backend

이 경우 Deployment selector는 app=api를 찾지만, template이 만드는 Pod는 app=backend label을 가진다.

올바른 예:

selector:
  matchLabels:
    app: api
template:
  metadata:
    labels:
      app: api

Deployment의 selector와 Pod template label은 반드시 일관되어야 한다.

container port와 Service targetPort 혼동

Deployment:

containers:
  - name: api
    image: registry.example.com/api:1.0.0
    ports:
      - containerPort: 3000

Service:

ports:
  - port: 80
    targetPort: 3000

여기서 containerPort는 container가 listen하는 port이고, targetPort는 Service가 traffic을 보낼 container port다.

자칫 다음처럼 잘못 연결할 수 있다.

targetPort: 8080

application은 3000번에서 listen하는데 Service가 8080으로 보내면 연결이 실패한다.


2단계: Controller / Rollout layer 디버깅

YAML이 적용되었다고 해서 application이 정상 배포된 것은 아니다.

Deployment는 desired state를 선언하고, Kubernetes controller가 이를 실제 상태로 맞춘다. 이 과정에서 rollout 상태를 확인해야 한다.

kubectl rollout status deployment/api

예시:

deployment "api" successfully rolled out

문제가 있으면 rollout이 끝나지 않을 수 있다.

Waiting for deployment "api" rollout to finish: 1 out of 3 new replicas have been updated...

이때는 다음을 확인한다.

kubectl describe deployment api
kubectl get replicasets
kubectl get pods

rollout 중 확인할 것

새 ReplicaSet이 생성되었는가?
새 Pod가 생성되고 있는가?
old ReplicaSet이 scale down되고 있는가?
new Pod가 Ready 상태가 되는가?
rollout이 progress deadline에 걸렸는가?

Deployment 상세 정보를 보면 Conditions가 나온다.

예시:

Conditions:
  Type           Status  Reason
  Available      True    MinimumReplicasAvailable
  Progressing    True    NewReplicaSetAvailable

문제가 있을 때는 다음과 같은 signal을 볼 수 있다.

ProgressDeadlineExceeded
ReplicaFailure
MinimumReplicasUnavailable

3단계: Pod / Runtime layer 디버깅

DeploymentReplicaSet이 정상처럼 보여도 Pod가 실패할 수 있다.

Pod 상태를 확인한다.

kubectl get pods

예시:

NAME                   READY   STATUS             RESTARTS
api-7f9d8c9c8-abcde    0/1     ImagePullBackOff   0
api-7f9d8c9c8-fghij    0/1     CrashLoopBackOff   5
api-7f9d8c9c8-klmno    1/1     Running            0

여기서 Running만 보면 안 된다. READY도 봐야 한다.

Running
  → container process는 시작됨

Ready
  → traffic을 받을 준비가 됨

Pod 상세 확인

kubectl describe pod api-7f9d8c9c8-abcde

확인할 것:

Events
Image pull error
Scheduling failure
Readiness probe failure
Liveness probe failure
Volume mount failure
Secret/ConfigMap not found
Resource 부족

application log 확인

kubectl logs api-7f9d8c9c8-abcde

container가 재시작 중이라면 이전 container log도 확인한다.

kubectl logs api-7f9d8c9c8-abcde --previous

Kubernetes 문제와 application 문제를 구분해야 한다.

ImagePullBackOff
  → registry, image tag, imagePullSecret 문제 가능성

CrashLoopBackOff
  → application process가 시작 후 종료됨

CreateContainerConfigError
  → ConfigMap, Secret, env, volume 설정 문제 가능성

Pending
  → scheduling, resource, PVC, taint/toleration 문제 가능성

Running but not Ready
  → readinessProbe 실패 또는 app 초기화 지연 가능성

Deployment update

Deployment의 핵심 기능은 update다.

처음에는 api:1.0.0을 배포했다고 하자.

image: registry.example.com/api:1.0.0

새 version이 나오면 image를 바꾼다.

image: registry.example.com/api:1.1.0

그 후 적용한다.

kubectl apply -f deployment.yaml

또는 명령으로 image만 바꿀 수 있다.

kubectl set image deployment/api api=registry.example.com/api:1.1.0

Deployment Controller는 새 Pod template을 감지하고 새 ReplicaSet을 만든다.

old ReplicaSet
  → api:1.0.0

new ReplicaSet
  → api:1.1.0

이후 controlled rate로 Pod를 교체한다.

old Pod 제거
new Pod 생성
readiness 확인
반복

Rolling update

Deployment의 기본 update 전략은 rolling update다.

예를 들어 replica가 3개라면 다음처럼 교체될 수 있다.

초기 상태:
api:1.0.0 × 3
api:1.1.0 × 0

진행 중:
api:1.0.0 × 2
api:1.1.0 × 1

진행 중:
api:1.0.0 × 1
api:1.1.0 × 2

완료:
api:1.0.0 × 0
api:1.1.0 × 3

Deployment update 전략은 다음 field로 조절할 수 있다.

strategy:
  type: RollingUpdate
  rollingUpdate:
    maxUnavailable: 1
    maxSurge: 1
field의미
maxUnavailablerollout 중 unavailable 상태가 허용되는 최대 Pod 수 또는 비율
maxSurgedesired replicas보다 추가로 생성할 수 있는 최대 Pod 수 또는 비율

예를 들어 replicas: 3, maxUnavailable: 1, maxSurge: 1이라면 rollout 중 최대 4개까지 Pod가 생길 수 있고, 최소 2개는 available 상태를 유지하려고 한다.


Deployment rollback

새 version이 문제를 일으키면 rollback이 필요하다.

rollout history를 확인한다.

kubectl rollout history deployment/api

특정 revision을 자세히 볼 수 있다.

kubectl rollout history deployment/api --revision=2

이전 revision으로 되돌린다.

kubectl rollout undo deployment/api

또는 특정 revision으로 되돌린다.

kubectl rollout undo deployment/api --to-revision=1

다만 rollback이 모든 것을 해결하지는 않는다.

주의할 점:

Deployment rollback은 Pod template 중심으로 되돌린다.
DB schema migration은 자동으로 되돌리지 않는다.
외부 cache format 변경은 되돌리지 않는다.
message queue payload format 변경도 별도 고려가 필요하다.

Deployment rollback은 application runtime image와 Pod template을 되돌리는 데 유용하지만, application data compatibility는 별도 설계해야 한다.


Deployment scaling

Deployment는 replica 수를 조절할 수 있다.

kubectl scale deployment api --replicas=5

또는 YAML을 수정한다.

spec:
  replicas: 5

이 경우 Deployment는 새 revision을 만들지 않는다. replica 수 변경은 rollout revision의 핵심인 Pod template 변경이 아니기 때문이다.

구분은 다음처럼 정리할 수 있다.

변경새 revision 생성 여부이유
image 변경생성됨.spec.template 변경
container env 변경생성됨.spec.template 변경
Pod label 변경생성됨.spec.template 변경
replicas 변경생성되지 않음Pod template 변경이 아님
annotation이 Pod template 밖에 있음보통 생성되지 않음.spec.template 밖의 변경

Deployment와 Service 연결

Deployment만 만들면 Pod는 생긴다. 하지만 안정적인 network endpoint는 아직 없다.

Pod IP는 바뀔 수 있으므로 Service를 붙여야 한다.

apiVersion: v1
kind: Service
metadata:
  name: api
spec:
  selector:
    app: api
  ports:
    - port: 80
      targetPort: 3000

Service selector는 Pod label과 맞아야 한다.

Service selector:
  app=api

Deployment Pod template label:
  app=api

확인:

kubectl get endpoints api

endpoint가 비어 있으면 Service가 Pod를 찾지 못하는 것이다.

Service는 존재한다.
Deployment도 존재한다.
Pod도 Running이다.
그런데 endpoint가 없다.

가능성:
Service selector와 Pod label 불일치
Pod readiness 실패
namespace 불일치

Deployment troubleshooting에서 Service까지 함께 확인해야 하는 이유다.


readinessProbe가 중요한 이유

Rolling update는 새 Pod가 준비되었다고 판단해야 old Pod를 줄일 수 있다. 이때 readinessProbe가 중요하다.

readinessProbe:
  httpGet:
    path: /ready
    port: 3000
  initialDelaySeconds: 5
  periodSeconds: 10

readinessProbe가 없으면 container process가 시작된 것만 보고 traffic이 갈 수 있다.

문제 상황:

container process 시작

DB connection 아직 준비 안 됨

Service endpoint에 포함

사용자 요청 실패

readinessProbe가 있으면 application이 실제로 요청을 받을 준비가 되었을 때만 endpoint에 들어간다.

Pod Running

readinessProbe 실패

Service endpoint 제외

traffic 전달 안 됨

Deployment의 안정적인 rolling update를 위해 readinessProbe는 사실상 필수에 가깝다.


livenessProbe와 startupProbe

Deployment 운영에서는 livenessProbe도 자주 사용한다.

livenessProbe:
  httpGet:
    path: /healthz
    port: 3000
  initialDelaySeconds: 30
  periodSeconds: 20

livenessProbe는 application이 죽은 상태인지 판단하고, 실패하면 kubelet이 container를 재시작할 수 있다.

하지만 livenessProbe를 너무 공격적으로 설정하면 문제가 생긴다.

일시적인 GC pause
일시적인 dependency 지연
초기 기동이 오래 걸림

livenessProbe 실패

container 재시작

계속 재시작 반복

CrashLoopBackOff

초기 기동이 오래 걸리는 application에는 startupProbe를 고려할 수 있다.

startupProbe:
  httpGet:
    path: /healthz
    port: 3000
  failureThreshold: 30
  periodSeconds: 10

정리하면 다음과 같다.

Probe목적
readinessProbetraffic을 받을 준비가 되었는지 판단
livenessProbeapplication이 살아 있는지 판단하고 재시작 여부 결정
startupProbe느리게 시작하는 application의 초기 기동 보호

Deployment 상태를 읽는 법

Deployment 상태를 볼 때는 단순히 kubectl get deployment만 보면 부족하다.

kubectl get deployment api

출력:

NAME   READY   UP-TO-DATE   AVAILABLE   AGE
api    2/3     3            2           5m

여기서 READY 2/3이라면 원하는 3개 중 2개만 준비된 상태다.

다음으로 봐야 할 것:

kubectl describe deployment api
kubectl get rs
kubectl get pods
kubectl describe pod <pod-name>
kubectl logs <pod-name>

상태를 계층적으로 읽어야 한다.

Deployment
  ↓ desired replicas, rollout condition 확인

ReplicaSet
  ↓ 새 Pod template 기준 ReplicaSet인지 확인

Pod
  ↓ scheduling, image pull, probe, restart 확인

Container logs
  ↓ application error 확인

자주 나오는 Deployment 실패 패턴

ImagePullBackOff

상태:

STATUS: ImagePullBackOff

가능한 원인:

image 이름 오타
tag 없음
private registry 인증 실패
imagePullSecret 누락
registry 접근 불가
node에서 DNS 또는 network 문제

확인:

kubectl describe pod <pod-name>
kubectl get secret
kubectl logs <pod-name>

ImagePullBackOff에서는 container가 시작되지 않았으므로 application log가 없을 수 있다. 이때는 describe pod의 Events가 더 중요하다.


CrashLoopBackOff

상태:

STATUS: CrashLoopBackOff

가능한 원인:

application process가 시작 후 바로 종료
필수 env 누락
ConfigMap/Secret 값 오류
DB 연결 실패 후 process exit
잘못된 command/args
port 충돌
permission 문제

확인:

kubectl logs <pod-name>
kubectl logs <pod-name> --previous
kubectl describe pod <pod-name>

--previous는 재시작된 이전 container의 log를 볼 때 중요하다.


Pending

상태:

STATUS: Pending

가능한 원인:

node resource 부족
PVC가 Bound되지 않음
nodeSelector 조건을 만족하는 node 없음
taint를 toleration하지 못함
image pull 이전 scheduling 단계에서 막힘

확인:

kubectl describe pod <pod-name>
kubectl get nodes
kubectl describe node <node-name>
kubectl get pvc

Running but not Ready

상태:

STATUS: Running
READY: 0/1

가능한 원인:

readinessProbe 실패
application은 떠 있지만 dependency 준비 안 됨
wrong readiness path
wrong readiness port
startup delay

확인:

kubectl describe pod <pod-name>
kubectl logs <pod-name>
kubectl port-forward pod/<pod-name> 3000:3000
curl http://localhost:3000/ready

Deployment debugging checklist

Deployment 문제가 생겼을 때는 다음 순서로 확인하면 좋다.

kubectl get deployments
kubectl describe deployment api
kubectl rollout status deployment/api
kubectl get replicasets
kubectl get pods
kubectl describe pod <pod-name>
kubectl logs <pod-name>
kubectl logs <pod-name> --previous
kubectl get events --sort-by=.metadata.creationTimestamp

각 명령의 목적은 다음과 같다.

명령목적
kubectl get deploymentsDeployment READY, AVAILABLE 상태 확인
kubectl describe deploymentDeployment conditions와 events 확인
kubectl rollout statusrollout 진행/완료 여부 확인
kubectl get replicasetsold/new ReplicaSet 상태 확인
kubectl get podsPod 상태와 restart count 확인
kubectl describe podscheduling, image pull, probe, volume event 확인
kubectl logsapplication log 확인
kubectl logs --previous재시작 전 container log 확인
kubectl get events시간순 cluster event 확인

Deployment와 rollout history

Deployment는 rollout history를 가진다.

kubectl rollout history deployment/api

예시:

REVISION  CHANGE-CAUSE
1         <none>
2         <none>
3         <none>

change cause를 기록하려면 annotation을 사용할 수 있다.

kubectl annotate deployment/api \
  kubernetes.io/change-cause="Update api image to 1.1.0"

또는 배포 도구에서 revision, commit SHA, image tag를 annotation으로 남기는 방식이 좋다.

예시:

metadata:
  annotations:
    app.example.com/git-sha: "abc1234"
    app.example.com/image-tag: "1.1.0"

운영에서는 다음 연결이 중요하다.

Git commit

container image tag

Deployment revision

ReplicaSet

Pod

이 연결이 명확해야 장애 발생 시 어떤 version이 문제였는지 빠르게 찾을 수 있다.


Deployment와 ConfigMap/Secret 변경

자주 실수하는 부분이 있다.

ConfigMap이나 Secret을 바꿨다고 해서 Deployment Pod가 항상 자동으로 재시작되는 것은 아니다.

예를 들어 DeploymentConfigMap을 env로 읽는다고 하자.

envFrom:
  - configMapRef:
      name: api-config

api-config를 수정해도 기존 Pod의 environment variable은 자동으로 바뀌지 않는다. Pod가 재시작되어야 새 env 값을 받는다.

운영에서는 다음 방식을 사용한다.

kubectl rollout restart deployment/api

또는 Helm chart에서 ConfigMap content hash를 Pod template annotation에 넣어 변경 시 rollout이 발생하게 한다.

template:
  metadata:
    annotations:
      checksum/config: "{{ include (print $.Template.BasePath \"/configmap.yaml\") . | sha256sum }}"

핵심은 Deployment revision이 .spec.template 변경에 의해 만들어진다는 점이다. ConfigMap만 바꾸고 Pod template이 그대로면 rollout이 발생하지 않을 수 있다.


Deployment와 resource requests/limits

Deployment에는 container resource 설정도 포함해야 한다.

resources:
  requests:
    cpu: "250m"
    memory: "256Mi"
  limits:
    cpu: "500m"
    memory: "512Mi"
항목의미
requests.cpuscheduler가 배치할 때 고려하는 최소 CPU 요구량
requests.memoryscheduler가 배치할 때 고려하는 최소 memory 요구량
limits.cpucontainer CPU 사용 상한
limits.memory초과 시 OOM kill될 수 있는 memory 상한

requests가 없으면 scheduler가 workload의 resource 요구를 정확히 판단하기 어렵다. limits가 너무 낮으면 application이 자주 OOMKilled될 수 있다.

Deployment가 Pending이거나 OOMKilled가 반복된다면 resource 설정을 확인해야 한다.

kubectl describe pod <pod-name>
kubectl top pod
kubectl top node

Deployment와 HPA

DeploymentHorizontalPodAutoscaler와 함께 자주 사용된다.

kubectl autoscale deployment api --cpu-percent=70 --min=3 --max=10

HPA는 metric을 보고 Deploymentreplicas 값을 조정한다.

CPU usage 증가

HPA가 Deployment replicas 증가

Deployment Controller가 Pod 추가 생성

중요한 점은 HPA도 Deployment의 Pod template을 바꾸지는 않는다는 것이다. HPA는 replica 수를 조정한다.

HPA 변경:
  spec.replicas 조정

Deployment rollout:
  spec.template 변경 시 발생

따라서 HPA로 scale out이 되었다고 해서 새 revision이 만들어지는 것은 아니다.


Deployment와 PodDisruptionBudget

운영 환경에서는 node drain이나 cluster upgrade 중에도 일정 수 이상의 Pod가 유지되어야 할 수 있다.

이때 PodDisruptionBudget을 사용한다.

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: api-pdb
spec:
  minAvailable: 2
  selector:
    matchLabels:
      app: api

의미:

app=api Pod 중 최소 2개는 available 상태로 유지되어야 한다.

Deploymentreplicas: 3이라면 node drain 중에도 최소 2개를 유지하려고 한다.

이것은 rolling update와는 별개의 개념이다. PDB는 voluntary disruption 상황에서 availability를 보호한다.


Deployment와 namespace

Deployment는 namespace-scoped resource다.

kubectl get deployment -n production

같은 이름의 Deployment라도 namespace가 다르면 별개다.

dev/api
staging/api
production/api

문제는 사람이 namespace를 빼먹을 때 자주 발생한다.

kubectl get pods

이 명령은 현재 context의 namespace만 본다. production에 배포했는데 default namespace를 보고 있으면 “Pod가 없다”고 착각할 수 있다.

확인:

kubectl config view --minify
kubectl get pods -A | grep api

운영에서는 명령에 -n을 명시하는 습관이 안전하다.

kubectl get deployment api -n production
kubectl describe deployment api -n production
kubectl logs -n production <pod-name>

Deployment와 label 설계

Deployment에서는 label 설계가 중요하다.

기본 label:

labels:
  app: api

운영에서는 더 체계적인 label을 쓰는 것이 좋다.

labels:
  app.kubernetes.io/name: api
  app.kubernetes.io/instance: api-prod
  app.kubernetes.io/version: "1.1.0"
  app.kubernetes.io/component: backend
  app.kubernetes.io/part-of: commerce
  app.kubernetes.io/managed-by: helm

label은 다음에 사용된다.

Service selector
kubectl get -l
monitoring grouping
logging query
NetworkPolicy selector
PodDisruptionBudget selector
cost allocation
GitOps ownership

label이 엉망이면 Service routing, monitoring, troubleshooting이 모두 어려워진다.


Deployment와 annotation

annotation은 selector용이 아니라 metadata 기록용으로 자주 사용된다.

예시:

metadata:
  annotations:
    app.example.com/git-sha: "abc1234"
    app.example.com/build-url: "[REDACTED]"
    app.example.com/owner: "platform-team"

Pod template annotation을 변경하면 rollout이 발생할 수 있다.

spec:
  template:
    metadata:
      annotations:
        restartedAt: "2026-06-02T10:00:00Z"

kubectl rollout restart도 내부적으로 Pod template annotation을 바꿔 새 rollout을 유도하는 방식으로 이해할 수 있다.


Deployment에서 보안상 주의할 점

Deployment YAML에 secret 값을 직접 넣으면 안 된다.

피해야 할 예:

env:
  - name: DB_PASSWORD
    value: "real-password"

대신 Secret을 참조한다.

env:
  - name: DB_PASSWORD
    valueFrom:
      secretKeyRef:
        name: api-secret
        key: db-password

또한 다음도 고려해야 한다.

runAsNonRoot
readOnlyRootFilesystem
allowPrivilegeEscalation: false
capabilities drop
resource requests/limits
imagePullPolicy
trusted registry
image tag immutability

예시:

securityContext:
  runAsNonRoot: true
  allowPrivilegeEscalation: false
  readOnlyRootFilesystem: true
  capabilities:
    drop:
      - ALL

Deployment는 application 배포의 중심 object이므로 보안 설정도 함께 들어가야 한다.


Deployment를 운영에서 잘 쓰는 패턴

immutable image tag 사용

피해야 할 방식:

image: registry.example.com/api:latest

권장 방식:

image: registry.example.com/api:1.1.0

또는 commit SHA:

image: registry.example.com/api:abc1234

latest는 어떤 image가 배포되었는지 추적하기 어렵고 rollback도 불명확해진다.

readinessProbe 필수화

Production Deployment에는 readinessProbe를 넣는 것이 좋다.

readinessProbe:
  httpGet:
    path: /ready
    port: 3000

rollout 상태를 CI/CD에서 확인

배포 후에는 rollout status를 확인해야 한다.

kubectl rollout status deployment/api -n production

실패하면 pipeline을 실패시켜야 한다.

manifest apply 성공

application 정상 배포

로그와 event를 함께 확인

application 문제는 log에 있고, Kubernetes scheduling/config 문제는 event에 있을 가능성이 높다.

kubectl logs <pod-name>
kubectl describe pod <pod-name>
kubectl get events --sort-by=.metadata.creationTimestamp

전체 mental model

Deployment를 이해하는 흐름은 다음과 같다.

1. Pod는 직접 관리하기에 너무 ephemeral하다.

2. Deployment는 Pod template과 replica 수를 선언한다.

3. Deployment Controller는 desired state를 actual state로 맞춘다.

4. Deployment는 ReplicaSet을 만들고,
   ReplicaSet은 Pod replica 수를 유지한다.

5. image나 env처럼 spec.template이 바뀌면 새 ReplicaSet이 만들어지고 rollout이 시작된다.

6. replicas만 바꾸는 scaling은 새 rollout revision을 만들지 않는다.

7. rollout status, history, undo를 통해 배포 상태를 추적하고 되돌릴 수 있다.

8. Deployment 문제는 Manifest/API layer,
   Controller/Rollout layer,
   Pod/Runtime layer로 나눠서 디버깅해야 한다.

9. Deployment가 정상이어도 Service selector, readinessProbe,
   ConfigMap/Secret, image pull, resource limit 문제로 application은 실패할 수 있다.

10. 운영에서는 immutable image tag, readinessProbe, resource requests/limits,
    rollout verification, secret 분리, label 체계가 중요하다.

요약

Deployment는 단순 Pod 생성 YAML이 아니다. Deployment는 stateless application의 desired state를 선언하고, ReplicaSetPod를 통해 replica 유지, rolling update, rollback, self-healing을 수행하게 하는 Kubernetes의 핵심 workload controller다.

핵심 구조는 다음이다.

Deployment

ReplicaSet

Pod

Container

운영에서는 단순히 kubectl apply가 성공했는지만 보면 안 된다. rollout status, Deployment condition, ReplicaSet, Pod status, events, logs, readinessProbe, Service endpoint까지 함께 확인해야 실제 application이 정상 배포되었는지 판단할 수 있다.

kubectl apply 성공

application 정상 배포

Deployment AVAILABLE
  +
Pod Ready
  +
Service endpoint 정상
  +
application log 정상
  =
운영 가능한 배포 상태

한 문장으로 정리하면 다음과 같다.

Kubernetes Deployment는 stateless application의 desired state를 선언하고, ReplicaSet과 Pod를 통해 replica 유지, rolling update, rollback, self-healing을 수행하게 하는 Kubernetes의 핵심 workload controller다.