Pod & Workload Resources
K8s의 최소 배포 단위 Pod와 이를 관리하는 상위 오브젝트들
1. Pod
1.1 Pod란
Pod는 K8s에서 생성/관리할 수 있는 최소 배포 단위. 하나 이상의 컨테이너를 포함하며, 같은 Pod 내 컨테이너는 네트워크와 스토리지를 공유함.
| 특성 | 설명 |
|---|---|
| 네트워크 공유 | 같은 Pod 내 컨테이너는 localhost로 통신 |
| 스토리지 공유 | Volume을 통해 파일시스템 공유 가능 |
| 생명주기 | Pod 삭제 시 모든 컨테이너가 함께 삭제됨 |
| IP | Pod 하나에 IP 하나. 내부 컨테이너는 포트로 구분 |
1.2 Pod 생명주기
stateDiagram-v2
[*] --> Pending: 생성 요청
Pending --> Running: 스케줄링 + 컨테이너 시작
Running --> Succeeded: 정상 종료 (Job)
Running --> Failed: 비정상 종료
Running --> Unknown: 노드 통신 끊김
Succeeded --> [*]
Failed --> [*]
| 상태 | 의미 |
|---|---|
| Pending | 스케줄링 대기 또는 이미지 다운로드 중 |
| Running | 하나 이상의 컨테이너가 실행 중 |
| Succeeded | 모든 컨테이너 정상 종료 (exitCode 0) |
| Failed | 하나 이상의 컨테이너 비정상 종료 |
| Unknown | 노드와 통신 불가 |
1.3 Multi-container 패턴
하나의 Pod에 여러 컨테이너를 넣는 패턴. 메인 앱을 보조하는 역할.
| 패턴 | 역할 | 예시 |
|---|---|---|
| Sidecar | 메인 앱을 보조 | 로그 수집기, 프록시 (Istio Envoy) |
| Ambassador | 외부 통신을 대리 | DB 프록시, API Gateway |
| Adapter | 출력을 표준 형식으로 변환 | 로그 포맷 변환, 메트릭 변환 |
1.4 Init Container
메인 컨테이너 이전에 실행되는 초기화 컨테이너. 순차적으로 실행되며, 모든 Init Container가 성공해야 메인 컨테이너가 시작됨.
spec:
initContainers:
- name: wait-for-db
image: busybox
command: ['sh', '-c', 'until nslookup db-service; do sleep 2; done']
containers:
- name: app
image: my-app:v1
활용: DB 준비 대기, 설정 파일 다운로드, 권한 설정, 마이그레이션 실행
1.5 Probe (헬스 체크)
| Probe | 목적 | 실패 시 |
|---|---|---|
| Liveness | 컨테이너가 살아있는가 | 재시작 |
| Readiness | 트래픽을 받을 준비가 되었는가 | Service에서 제외 (재시작 안 함) |
| Startup | 앱이 시작되었는가 (느린 앱용) | 시작 실패로 판단 → 재시작 |
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 15
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
Probe 방식: HTTP GET, TCP Socket, gRPC, Exec(명령 실행)
1.6 Pod Disruption Budget (PDB)
자발적 중단(노드 drain, 업그레이드) 시 최소 가용 Pod 수를 보장하는 오브젝트.
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: web-pdb
spec:
minAvailable: 2 # 또는 maxUnavailable: 1
selector:
matchLabels:
app: web
2. ReplicaSet
선언된 수만큼 Pod를 유지하는 컨트롤러. 직접 사용하는 경우는 거의 없고 Deployment가 내부적으로 관리함.
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web
image: nginx:1.25
- Pod가 죽으면 자동으로 새 Pod 생성 (자가치유)
- Label Selector로 관리 대상 Pod를 식별
3. Deployment
3.1 가장 많이 사용하는 워크로드
Deployment = ReplicaSet + 롤링 업데이트/롤백 기능.
flowchart TB
Deployment["Deployment<br/>(v2로 업데이트)"]
Deployment --> RS1["ReplicaSet v1<br/>(replicas: 0)"]
Deployment --> RS2["ReplicaSet v2<br/>(replicas: 3)"]
RS1 --> Pod1_old["Pod v1 (삭제됨)"]
RS2 --> Pod1["Pod v2"]
RS2 --> Pod2["Pod v2"]
RS2 --> Pod3["Pod v2"]
3.2 배포 전략
| 전략 | 동작 | 다운타임 |
|---|---|---|
| RollingUpdate (기본) | 새 Pod를 점진적으로 생성하면서 구 Pod를 삭제 | ❌ 없음 |
| Recreate | 모든 구 Pod를 삭제한 후 새 Pod 생성 | ✅ 있음 |
spec:
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # 원하는 수 대비 추가 생성 가능한 Pod 수
maxUnavailable: 0 # 원하는 수 대비 동시에 사용 불가능한 Pod 수
3.3 롤백
# 업데이트 히스토리
kubectl rollout history deployment/web
# 이전 버전으로 롤백
kubectl rollout undo deployment/web
# 특정 리비전으로 롤백
kubectl rollout undo deployment/web --to-revision=2
# 업데이트 상태 확인
kubectl rollout status deployment/web
4. StatefulSet
4.1 상태가 있는 워크로드
| Deployment | StatefulSet | |
|---|---|---|
| Pod 이름 | 랜덤 (web-7d9f8-xk2p) | 순차적 (db-0, db-1, db-2) |
| 생성/삭제 순서 | 동시 | 순차적 (0→1→2, 삭제는 역순) |
| 네트워크 ID | 불안정 (재시작 시 변경) | 안정적 (Headless Service) |
| 스토리지 | 공유 또는 없음 | Pod별 고유 PVC |
| 용도 | 무상태 앱 (웹 서버, API) | 상태 앱 (DB, 메시지 큐, ZooKeeper) |
4.2 Headless Service
StatefulSet의 각 Pod에 안정적인 DNS 이름을 부여.
apiVersion: v1
kind: Service
metadata:
name: db
spec:
clusterIP: None # Headless
selector:
app: db
ports:
- port: 5432
---
# Pod DNS: db-0.db.default.svc.cluster.local
# db-1.db.default.svc.cluster.local
4.3 volumeClaimTemplates
Pod마다 고유한 PVC를 자동 생성.
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 10Gi
# → db-0은 data-db-0 PVC, db-1은 data-db-1 PVC 사용
5. DaemonSet
모든 (또는 특정) 노드에 Pod를 하나씩 배포.
| 활용 | 예시 |
|---|---|
| 로그 수집 | Fluentd, Filebeat |
| 모니터링 | node-exporter, Datadog Agent |
| 네트워크 | CNI 플러그인 (Calico, Cilium) |
| 스토리지 | CSI 노드 플러그인 |
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: node-exporter
spec:
selector:
matchLabels:
app: node-exporter
template:
spec:
containers:
- name: node-exporter
image: prom/node-exporter:latest
노드가 추가되면 자동으로 Pod가 생성되고, 노드가 제거되면 Pod도 삭제됨.
6. Job & CronJob
6.1 Job — 일회성 작업
apiVersion: batch/v1
kind: Job
metadata:
name: db-backup
spec:
completions: 1 # 성공해야 하는 Pod 수
backoffLimit: 3 # 재시도 횟수
template:
spec:
containers:
- name: backup
image: postgres:16
command: ["pg_dump", "-h", "db", "-U", "admin", "-d", "mydb"]
restartPolicy: Never
6.2 CronJob — 주기적 작업
apiVersion: batch/v1
kind: CronJob
metadata:
name: db-backup-cron
spec:
schedule: "0 2 * * *" # 매일 02:00
jobTemplate:
spec:
template:
spec:
containers:
- name: backup
image: postgres:16
command: ["pg_dump", "..."]
restartPolicy: Never
7. 워크로드 선택 가이드
flowchart TD
Start["어떤 워크로드?"]
Start -->|"무상태 앱<br/>(웹, API)"| Deployment["Deployment"]
Start -->|"상태 앱<br/>(DB, 큐)"| StatefulSet["StatefulSet"]
Start -->|"모든 노드에<br/>하나씩"| DaemonSet["DaemonSet"]
Start -->|"일회성 작업"| Job["Job"]
Start -->|"주기적 작업"| CronJob["CronJob"]
다음 글
→ #4 Service & Networking — ClusterIP, NodePort, Ingress, CNI, NetworkPolicy