본문으로 건너뛰기
김신건의 로그

[K8s] Pod: 컨테이너의 최소 단위, sidecar, lifecycle

· 수정 · 📖 약 2분 · 798자/단어 #kubernetes #pod #container #k8s
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컨테이너 실패
UnknownAPI 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

  1. Probe 없음 = 트래픽 일부 실패. readiness 필수.
  2. Memory limit 너무 작음 = OOM kill 반복. Resource 측정 후 결정.
  3. Sidecar 가 main 보다 늦게 종료 = pre-stop hook + grace period 부족 → log 누락.
  4. Init container 가 느림 = pod 시작 자체 지연.

Pod 보안 컨텍스트

spec:
  securityContext:
    runAsNonRoot: true
    runAsUser: 1000
    fsGroup: 2000
  containers:
    - name: app
      securityContext:
        allowPrivilegeEscalation: false
        readOnlyRootFilesystem: true
        capabilities:
          drop: ["ALL"]
설정의미
runAsNonRootroot 로 실행 금지
runAsUser특정 UID 로 실행
readOnlyRootFilesystem루트 파일시스템 읽기 전용
allowPrivilegeEscalation권한 상승 금지
capabilities.dropLinux 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 강제 종료.
  • preStop hook 으로 종료 전 작업 가능.
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롤링 업데이트 안전성

멀티 컨테이너 패턴 요약

패턴구성용도
Sidecarmain + helper로그, 프록시, 인증
Ambassadormain + proxy외부 서비스 추상화
Adaptermain + transformer출력 형식 변환
Initinit 완료 후 종료 + main사전 준비 작업

Pod QoS Classes

K8s 는 resource 설정에 따라 Pod 에 세 가지 QoS 클래스 를 자동으로 부여한다. 노드 리소스 부족 시 eviction 우선순위에 영향을 준다.

QoS Class조건특징
Guaranteed모든 컨테이너의 requests == limitsOOM 에서 마지막 희생
Burstable일부 컨테이너에 requests < limits중간 우선순위
BestEffortrequests / 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 | |---|---|…

💬 댓글

사이트 검색 / 명령어

검색

스크롤 = 확대/축소 · 드래그 = 이동 · 0 = 원래 크기 · ESC = 닫기