[K8s] Pod: 컨테이너의 최소 단위, sidecar, lifecycle
Pod, K8s Pod, sidecar container, init container, pause container, pod lifecycle
정의
Pod = K8s 의 가장 작은 배포 단위. 1개 이상의 컨테이너 + 공유 네트워크 + 공유 스토리지.
IMPORTANT
Pod 는 컨테이너의 wrapping 이 아니다. 서로 강하게 결합한 컨테이너들의 묶음 (메인 + sidecar). 단일 컨테이너 pod 가 가장 흔함.
구조
flowchart TB
subgraph Pod
Pause["pause container<br/>(네트워크 namespace)"]
Main[Main container<br/>nginx]
Side[Sidecar container<br/>logger]
Init["Init container<br/>(완료 후 종료)"]
end
Pod --> Net[공유 IP + 포트]
Pod --> Vol[공유 volume]
라이프사이클
stateDiagram-v2
[*] --> Pending: scheduled
Pending --> ContainerCreating: pull image
ContainerCreating --> Running: init + main start
Running --> Succeeded: 모든 컨테이너 0 exit
Running --> Failed: 컨테이너 fail
Running --> Terminating: delete
Terminating --> [*]
| Phase | 의미 |
|---|---|
| Pending | 스케줄링 대기 / 이미지 pull |
| Running | 모든 컨테이너 시작 |
| Succeeded | 모든 컨테이너 성공 종료 |
| Failed | 컨테이너 실패 |
| Unknown | API server 통신 실패 |
YAML 예시
apiVersion: v1
kind: Pod
metadata:
name: web
labels:
app: web
spec:
initContainers:
- name: setup
image: busybox
command: ['sh', '-c', 'echo init done > /shared/ready']
volumeMounts:
- name: shared
mountPath: /shared
containers:
- name: nginx
image: nginx:1.27
ports:
- containerPort: 80
resources:
requests: { cpu: 100m, memory: 128Mi }
limits: { cpu: 500m, memory: 512Mi }
livenessProbe:
httpGet: { path: /, port: 80 }
initialDelaySeconds: 10
readinessProbe:
httpGet: { path: /ready, port: 80 }
volumeMounts:
- name: shared
mountPath: /var/data
- name: log-sidecar
image: fluent-bit:3
volumeMounts:
- name: shared
mountPath: /var/log/source
volumes:
- name: shared
emptyDir: {}
Probes (3종)
| Probe | 목적 | 실패 시 |
|---|---|---|
| Startup | 느린 시작 보호 | 죽인 후 재시작 |
| Liveness | 살아있나 | 컨테이너 재시작 |
| Readiness | 트래픽 받을 준비 | Service endpoint 에서 제외 |
flowchart LR
Start[컨테이너 시작] --> Startup[Startup probe 통과까지<br/>liveness 무시]
Startup --> Live[Liveness 시작]
Startup --> Ready[Readiness 시작]
Live --|실패|--> Restart[컨테이너 재시작]
Ready --|실패|--> RemoveFromLB[Service 에서 제외]
Ready --|성공|--> AddToLB[Service 에 추가]
IMPORTANT
Probe 가 없으면 K8s 가 언제 트래픽 보낼지 모름 → 첫 요청 실패. readiness 는 거의 필수.
Sidecar Pattern
flowchart LR
Main[Main: app] -.공유 volume.-> Log
Main -.공유 network.-> Proxy
Log[Sidecar: log shipper<br/>fluent-bit]
Proxy[Sidecar: envoy<br/>mTLS, retry]
흔한 sidecar:
- Log shipper (fluent-bit, vector)
- Service mesh proxy (envoy, linkerd)
- Secret rotation (vault-agent)
- TLS termination (nginx)
- Metrics adapter (statsd → prometheus)
Init Container
sequenceDiagram
Scheduler->>Pod: start
Pod->>Init1: init-1 실행
Init1-->>Pod: exit 0
Pod->>Init2: init-2 실행
Init2-->>Pod: exit 0
Pod->>Main: main + sidecars 시작
용도:
- DB schema migration
- 설정 파일 생성
- TLS cert pre-fetch
- 데이터 download
Resource: Requests / Limits
flowchart LR
Req[requests<br/>= 최소 보장] --> Schedule[스케줄링 결정 기준]
Lim[limits<br/>= 최대 한도] --> Throttle["CPU: throttle<br/>Memory: OOM kill"]
CAUTION
Memory limit 초과 = OOM kill (즉시). CPU limit 초과 = throttle (느려짐). memory 는 보수적으로.
Pod 의 변경 불가성
Pod spec 의 대부분 필드 = immutable
변경하려면 → 새 Pod 생성, 옛 Pod 삭제
→ 직접 Pod 만들 일 거의 없음. Deployment / StatefulSet / DaemonSet 이 자동 관리.
흔한 함정
WARNING
- Probe 없음 = 트래픽 일부 실패. readiness 필수.
- Memory limit 너무 작음 = OOM kill 반복. Resource 측정 후 결정.
- Sidecar 가 main 보다 늦게 종료 = pre-stop hook + grace period 부족 → log 누락.
- Init container 가 느림 = pod 시작 자체 지연.
Pod 보안 컨텍스트
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 2000
containers:
- name: app
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]
| 설정 | 의미 |
|---|---|
runAsNonRoot | root 로 실행 금지 |
runAsUser | 특정 UID 로 실행 |
readOnlyRootFilesystem | 루트 파일시스템 읽기 전용 |
allowPrivilegeEscalation | 권한 상승 금지 |
capabilities.drop | Linux capability 제거 |
IMPORTANT
CIS Kubernetes Benchmark 기준: runAsNonRoot: true, readOnlyRootFilesystem: true, allowPrivilegeEscalation: false 는 프로덕션 기본 설정.
Pod Disruption Budget
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: web-pdb
spec:
minAvailable: 2
selector:
matchLabels:
app: web
- 노드 드레인, 업그레이드 시 최소 가용 Pod 수 보장.
minAvailable또는maxUnavailable중 하나 선택.- Deployment 와 함께 사용해야 의미 있음.
Grace Period 와 종료 순서
sequenceDiagram
K8s->>Pod: SIGTERM 전송
Pod->>App: SIGTERM
Note over Pod,App: terminationGracePeriodSeconds 대기, 기본 30초
App-->>Pod: 정상 종료
Pod-->>K8s: 종료 완료
terminationGracePeriodSeconds기본값: 30초.- 앱이 SIGTERM 을 받으면 graceful shutdown 처리 후 종료.
- 시간 내 종료 안 되면 SIGKILL 강제 종료.
preStophook 으로 종료 전 작업 가능.
lifecycle:
preStop:
exec:
command: ["/bin/sh", "-c", "sleep 5"]
실무 체크리스트
flowchart TD
Start["Pod 배포 전 확인"] --> R["resources 설정 여부"]
R -->|미설정| FR["requests/limits 추가"]
R -->|설정됨| P["readinessProbe 여부"]
P -->|없음| FP["readinessProbe 추가"]
P -->|있음| S["securityContext 여부"]
S -->|없음| FS["runAsNonRoot 등 추가"]
S -->|있음| OK["배포 OK"]
| 항목 | 이유 |
|---|---|
resources.requests/limits | 스케줄링 + OOM 방지 |
readinessProbe | 트래픽 라우팅 정확성 |
livenessProbe | 데드락 자동 복구 |
securityContext | 최소 권한 원칙 |
PodDisruptionBudget | 롤링 업데이트 안전성 |
멀티 컨테이너 패턴 요약
| 패턴 | 구성 | 용도 |
|---|---|---|
| Sidecar | main + helper | 로그, 프록시, 인증 |
| Ambassador | main + proxy | 외부 서비스 추상화 |
| Adapter | main + transformer | 출력 형식 변환 |
| Init | init 완료 후 종료 + main | 사전 준비 작업 |
Pod QoS Classes
K8s 는 resource 설정에 따라 Pod 에 세 가지 QoS 클래스 를 자동으로 부여한다. 노드 리소스 부족 시 eviction 우선순위에 영향을 준다.
| QoS Class | 조건 | 특징 |
|---|---|---|
| Guaranteed | 모든 컨테이너의 requests == limits | OOM 에서 마지막 희생 |
| Burstable | 일부 컨테이너에 requests < limits | 중간 우선순위 |
| BestEffort | requests / limits 모두 미지정 | 리소스 압박 시 첫 희생 |
flowchart TD
Q{"requests, limits 설정?"}
Q -->|"requests == limits (모든 컨테이너)"| G[Guaranteed]
Q -->|"requests 있지만 limits 다름"| B[Burstable]
Q -->|"모두 미지정"| BE[BestEffort]
G --> E1["OOM 발생 시: 마지막으로 종료"]
B --> E2["OOM 발생 시: 중간 순위"]
BE --> E3["OOM 발생 시: 첫 번째로 종료"]
TIP
운영 환경 목표: Guaranteed 클래스. requests 와 limits 를 동일하게 설정하면 스케줄러 예측이 쉽고 OOM kill 위험이 줄어든다.
관련 위키
이 글의 용어 (5개)
- [Container] cgroups + namespaces: 컨테이너의 두 기둥virtualization
- 정의 컨테이너 = namespaces + cgroups + 파일시스템 (overlay). VM 이 아니라 host 의 프로세스 + 격리. VM 은 hypervisor + 별도 커…
- [Container] Docker: image, layer, registryvirtualization
- 정의 Docker = 컨테이너 빌드 + 실행 + 배포 의 표준 도구. 2013 출시 → 컨테이너 시대 의 시작. 현재는 OCI 표준 으로 진화 ( , , 등 호환). 컨테이너 런…
- [K8s] Deployment: ReplicaSet, rolling update, rollbackkubernetes
- 정의 Deployment = stateless 워크로드를 위한 컨트롤러. 내부적으로 ReplicaSet 관리 + rolling update / rollback. 사용 시나리오 |…
- [K8s] Service: ClusterIP / NodePort / LoadBalancer / ExternalNamekubernetes
- 정의 Service = Pod 집합에 안정 가상 IP + DNS 부여. Pod 가 죽고 다시 만들어져도 Service IP 는 그대로. 4가지 타입 1. ClusterIP (기본…
- [K8s] StatefulSet: 순서 보장, 고유 ID, 영속 스토리지kubernetes
- 정의 StatefulSet = 상태 있는 워크로드를 위한 컨트롤러. Deployment 와의 차이: | 항목 | Deployment | StatefulSet | |---|---|…
이 개념을 다룬 위키 페이지 (26)
- wiki[AWS] EKS: managed Kubernetes
- wiki[Container] OCI Image: spec, manifest, layer 표준
- wiki[Observability] Prometheus: pull 기반 메트릭, PromQL
- wiki[Kubernetes] Admission Controllers
- wiki[Kubernetes] Architecture (Control Plane + Node)
- wiki[K8s] ConfigMap & Secret: 설정과 비밀의 분리
- wiki[K8s] DaemonSet: 모든 노드에 한 pod
- wiki[Kubernetes] Debugging (kubectl debug, Ephemeral Containers, Events)
- wiki[K8s] Deployment: ReplicaSet, rolling update, rollback
- wiki[K8s] HPA / VPA / KEDA: 자동 확장
- wiki[Kubernetes] Init Containers & Sidecar Containers
- wiki[K8s] Job / CronJob: 일회성 + 스케줄 작업
- wiki[Kubernetes] Labels & Selectors
- wiki[K8s] NetworkPolicy: pod 간 네트워크 차단
- wiki[Kubernetes] Persistent Volumes (PV / PVC / StorageClass)
- wiki[K8s] RBAC: Role, ClusterRole, ServiceAccount, RoleBinding
- wiki[Kubernetes] Resource Management (Requests, Limits, QoS)
- wiki[Kubernetes] Scheduling (Taints, Affinity, Topology Spread)
- wiki[K8s] Service: ClusterIP / NodePort / LoadBalancer / ExternalName
- wiki[K8s] StatefulSet: 순서 보장, 고유 ID, 영속 스토리지
- wikiKubernetes
- wiki[Container] cgroups + namespaces: 컨테이너의 두 기둥
- wiki[Container] Image Best Practices: 작게, 안전하게
- wiki[Container] Docker: image, layer, registry
- wikiLXC / LXD: System Containers, Docker 이전의 컨테이너
- wikiVM vs Container: 층 구조, 성능, 격리 완벽 비교
💬 댓글