[K8S] Pause Container

진웅·2025년 11월 12일

K8S Basics

목록 보기
37/40

Kubernetes Pause Container:

개요

  • Pause 컨테이너는 Pod의 네트워크, IPC, UTS 네임스페이스를 공유하며, Pod 내 컨테이너 간 통신을 가능하게 하는 핵심 구성 요소입니다.
  • Kubernetes 1.33에서는 Pause 컨테이너의 기본 이미지와 동작에 큰 변화는 없으나,
    사용자 네임스페이스(User Namespaces)가 기본 활성화(Beta)되어 Pod 보안 격리가 강화되었습니다. 이는 Pause 컨테이너가 네임스페이스 공유 시 더 안전한 컨테이너 격리를 지원합니다.

주요 업데이트 포인트 (v1.33 기준):

  • User Namespaces 기본 활성화: Pod의 spec.securityContext.hostUsers: false 설정으로 사용자 네임스페이스를 활성화할 수 있으며, 이는 컨테이너 런타임(containerd 2.0+ 또는 CRI-O)과 호환되어야 합니다. Pause 컨테이너가 공유하는 네임스페이스에 영향을 주어 보안이 향상됩니다.
  • Endpoints API Deprecation: Pause 컨테이너의 네트워크 공유와 관련된 Service/Endpoints 동작에 영향을 줄 수 있음. Endpoints API가 deprecated되어 EndpointSlices로 마이그레이션 권장(스케일링 및 dual-stack 지원 강화).
  • 기타 관련 변경: gitRepo 볼륨 타입 제거(네트워크 관련 워크플로우에 영향 없음), Job API 확장(멀티 컨테이너 Pod의 성공 정책 정의 가능).
  • 런타임 호환성: containerd 2.0+ 지원 강화로 Pause 컨테이너의 네임스페이스 공유가 더 안정적입니다.

Pause 컨테이너의 역할

Pause 컨테이너는 Pod의 "부모 컨테이너"로 작동하며, 다음과 같은 역할을 합니다:
1. Linux 네임스페이스 생성 및 공유: Network, IPC, UTS 네임스페이스를 생성하고 모든 컨테이너와 공유. 이를 통해 Pod 내 컨테이너들이 동일한 IP를 사용하고 통신할 수 있습니다. v1.33에서 User Namespaces가 기본 Beta로 승격되어 추가 보안 레이어(호스트 사용자 매핑 비활성화)가 적용됩니다.
2. 좀비 프로세스 정리: 멀티 컨테이너 Pod에서 발생할 수 있는 좀비 프로세스를 처리합니다.

Pause 컨테이너는 외부에서 직접 보이지 않으며, 노드의 프로세스 트리를 통해 확인 가능합니다.

Pause 컨테이너 확인 방법 (v1.33 업데이트)

Kind 클러스터를 사용한 예시를 유지하되, v1.33 호환성을 위해 containerd 런타임 설정을 추가합니다. (Kind v0.23+에서 Kubernetes 1.33 지원 확인됨.)

1. Kind 클러스터 생성 (kind-2node.yaml)

kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
  extraPortMappings:
  - containerPort: 30000
    hostPort: 30000
  - containerPort: 30001
    hostPort: 30001
kind create cluster --config kind-2node.yaml --name myk8s --image kindest/node:v1.33.0  # v1.33 이미지 지정

2. 노드에 유틸리티 설치

docker exec -it myk8s-control-plane sh -c 'apt update && apt install tree jq psmisc lsof wget bridge-utils tcpdump htop git nano -y'
docker exec -it myk8s-worker sh -c 'apt update && apt install tree jq psmisc lsof wget bridge-utils tcpdump htop -y'

3. 샘플 애플리케이션 배포 (Helm 사용, kube-ops-view)

helm repo add geek-cookbook https://geek-cookbook.github.io/charts/
helm install kube-ops-view geek-cookbook/kube-ops-view --version 1.2.2 \
  --set service.main.type=NodePort,service.main.ports.http.nodePort=30000 \
  --set env.TZ="Asia/Seoul" --namespace kube-system
  • v1.33 업데이트: EndpointSlices 사용으로 Service 스케일링이 향상됨. 기존 Endpoints 기반 스크립트는 경고 발생.

4. 워커 노드에서 프로세스 확인

docker exec -it myk8s-worker bash
pstree -aln  # 프로세스 트리 확인 (Pause 컨테이너 PID 확인)
  • 추가: User Namespaces 확인을 위해 lsns 명령에 -t user 옵션 추가 가능 (v1.33에서 강화).

5. 네임스페이스 공유 확인

pstree -aclnpsS  # 네임스페이스 정보 포함 프로세스 트리
lsns -p 1        # 루트 PID 네임스페이스
lsns -p <pause-pid>  # Pause PID (예: 1239)
lsns -p <app-pid>    # 애플리케이션 PID (예: 1308)
  • v1.33: User Namespaces가 활성화된 Pod에서 user 타입 네임스페이스가 추가로 공유됨.

멀티 컨테이너 Pod에서의 동작

멀티 컨테이너 Pod(예: nginx + netshoot)에서 Pause 컨테이너의 공유 IP/네임스페이스를 확인합니다. v1.33에서 In-Place Pod Resize(베타) 지원으로 리소스 조정 시 Pause가 안정적으로 유지됩니다.

Pod YAML (myweb2, User Namespaces 추가)

apiVersion: v1
kind: Pod
metadata:
  name: myweb2
spec:
  securityContext:  # v1.33: User Namespaces 활성화
    hostUsers: false
  containers:
  - name: myweb2-nginx
    image: nginx
    ports:
    - containerPort: 80
      protocol: TCP
  - name: myweb2-netshoot
    image: nicolaka/netshoot
    command: ["/bin/bash"]
    args: ["-c", "while true; do sleep 5; curl localhost; done"]
  terminationGracePeriodSeconds: 0

배포 및 검사

kubectl apply -f myweb2.yaml
kubectl describe pod myweb2  # 하나의 IP 확인 (Pause 보이지 않음)

IP 공유 확인

kubectl exec myweb2 -c myweb2-nginx -- apt update && apt install -y net-tools
kubectl exec myweb2 -c myweb2-netshoot -- ifconfig
kubectl exec myweb2 -c myweb2-nginx -- ifconfig  # 동일 IP 출력

Netshoot 컨테이너 접근 및 테스트

kubectl exec myweb2 -c myweb2-netshoot -it -- zsh
curl localhost  # nginx 응답 확인
ps -ef          # 프로세스 목록

노드에서 네임스페이스 확인 (PID 추출)

docker exec -it myk8s-worker bash
NGINXPID=$(ps -ef | grep 'nginx -g' | grep -v grep | awk '{print $2}'); echo $NGINXPID
NETSHPID=$(ps -ef | grep 'curl' | grep -v grep | awk '{print $2}'); echo $NETSHPID
lsns -p $NGINXPID  # 공유 네임스페이스
lsns -p $NETSHPID  # 공유 네임스페이스 (User 포함)
  • 통신 성공 이유: 공유 네임스페이스로 인한 localhost 접근 가능. v1.33에서 Network Policy Logging(알파)으로 트래픽 로깅 강화.

정리 및 주의사항

  • Pause 컨테이너는 Pod 격리와 공유를 위한 필수 요소로, v1.33에서 보안(사용자 네임스페이스)과 스케일링(EndpointSlices)이 강화되었습니다.
  • 업그레이드 시: Endpoints API 사용 스크립트를 EndpointSlices로 마이그레이션하세요. User Namespaces 활성화 시 런타임 호환성 확인 (containerd 2.0+).
  • 클린업:
    kind delete cluster --name myk8s

자세한 내용은 Kubernetes 1.33 릴리스 노트를 참조하세요.

Kubernetes Pause 컨테이너 완벽 가이드

📋 목차

  1. 개요
  2. Pause 컨테이너의 역할
  3. Kubernetes v1.33의 주요 변경사항
  4. Pause 컨테이너 확인 방법
  5. 멀티 컨테이너 Pod 예제
  6. Private Registry 사용 시 주의사항
  7. 베스트 프랙티스
  8. 트러블슈팅
  9. 요약

개요

Pause 컨테이너는 Kubernetes Pod가 실행될 때 가장 먼저 생성되어 Pod의 네트워크 네임스페이스를 관리하는 특수한 인프라 컨테이너입니다. 모든 Pod에는 눈에 보이지 않지만 항상 Pause 컨테이너가 실행되고 있으며, 이는 Pod 내 모든 컨테이너들의 부모 역할을 수행합니다.

Pod 구조도

┌─────────────────────────────────────────────────────────────┐
│                         Pod                                 │
│  ┌─────────────────────┐  ┌───────────────────────────────┐ │
│  │   Pause 컨테이너     │  │      애플리케이션 컨테이너       │ │
│  │   (PID 1)           │  │                               │ │
│  │                     │  │  ┌─────────────────────────────┐ │ │
│  │  • 네트워크 네임스페이스 │  │  │       컨테이너 1            │ │ │
│  │  • IPC 네임스페이스    │  │  │   (Nginx, App 등)         │ │ │
│  │  • UTS 네임스페이스    │  │  └─────────────────────────────┘ │ │
│  │                     │  │  ┌─────────────────────────────┐ │ │
│  │                     │  │  │       컨테이너 2            │ │ │
│  │                     │  │  │   (Sidecar 등)             │ │ │
│  │                     │  │  └─────────────────────────────┘ │ │
│  └─────────────────────┘  └───────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘

Pause 컨테이너의 중요성

graph LR
    A[Pod 생성] --> B[Pause 컨테이너 먼저 생성]
    B --> C[네트워크 네임스페이스 설정]
    C --> D[애플리케이션 컨테이너 생성]
    D --> E[네트워크 네임스페이스 공유]
    E --> F[컨테이너 간 통신 가능]
    
    B --> G[PID 1 역할 수행]
    G --> H[좀비 프로세스 제거]

Pause 컨테이너의 역할

1. Linux Namespace 생성 및 공유

Pause 컨테이너는 Pod가 생성될 때 가장 먼저 실행되어 다음 네임스페이스들을 생성합니다:

  • Network Namespace: Pod의 IP 주소와 네트워크 인터페이스를 관리
  • IPC Namespace: 프로세스 간 통신을 위한 공유 메모리 영역
  • UTS Namespace: 호스트명과 도메인명 정보

이러한 네임스페이스들은 Pod 내 모든 컨테이너가 공유하게 되어, 같은 Pod 내의 컨테이너들이 localhost를 통해 서로 통신할 수 있게 됩니다.

네임스페이스 공유 구조도

┌─────────────────────────────────────────────────────────────┐
│                        Pod                                  │
│                                                             │
│  ┌─────────────────────┐                                    │
│  │   Pause 컨테이너     │                                    │
│  │                     │                                    │
│  │  Network Namespace  ├────────────────────────────────────┤
│  │  IPC Namespace      │                                    │
│  │  UTS Namespace      │                                    │
│  └─────────────────────┘                                    │
│           ↑                                                 │
│           │                                                 │
│           │ 공유                                             │
│           ↓                                                 │
│  ┌─────────────────────┐  ┌───────────────────────────────┐ │
│  │   컨테이너 1         │  │         컨테이너 2              │ │
│  │                     │  │                               │ │
│  │  Network Namespace  │  │  Network Namespace             │ │
│  │  IPC Namespace      │  │  IPC Namespace                 │ │
│  │  UTS Namespace      │  │  UTS Namespace                 │ │
│  └─────────────────────┘  └───────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘

2. 좀비 프로세스(Zombie Process) 제거

v1.7+ 버전 (PID 네임스페이스 공유 활성화 시):

  • Pause 컨테이너는 Pod의 PID 1로 동작
  • 고아 프로세스(orphan process)들을 회수(reap)하여 좀비 프로세스 발생 방지
  • v1.8부터는 기본적으로 비활성화되어 있으며, kubelet 플래그로 제어 가능

좀비 프로세스 처리 과정

sequenceDiagram
    participant P as Pause 컨테이너 (PID 1)
    participant C as 컨테이너 프로세스
    participant K as Kubelet
    
    C->>P: 자식 프로세스 생성
    P->>C: PID 할당
    C->>P: 프로세스 종료 시 신호 전송
    P->>P: 고아 프로세스 회수
    P->>K: 상태 보고

3. 네트워크 상태 유지

Pod 내의 애플리케이션 컨테이너가 재시작되더라도 Pause 컨테이너는 계속 실행되면서 네트워크 네임스페이스를 유지합니다. 이를 통해 Pod의 IP 주소가 변경되지 않고 네트워크 설정이 보존됩니다.

컨테이너 재시작 시 네트워크 유지 과정

시간 축 →
┌─────────────────────────────────────────────────────────────┐
│                        Pod                                  │
│                                                             │
│  ┌─────────────────────┐                                    │
│  │   Pause 컨테이너     │─────────────────────────────────────│
│  │   (지속 실행)        │                                    │
│  └─────────────────────┘                                    │
│           ↑                                                 │
│           │                                                 │
│           │ 공유                                             │
│           ↓                                                 │
│  ┌─────────────────────┐  ┌───────────────────────────────┐ │
│  │   컨테이너 1         │  │         컨테이너 2              │ │
│  │                     │  │                               │ │
│  │  ────▶ 재시작 ◀────── │  │  ────────▶ 계속 실행 ◀───────── │ │
│  │                     │  │                               │ │
│  └─────────────────────┘  └───────────────────────────────┘ │
│                                                             │
│  ┌─────────────────────────────────────────────────────────┐ │
│  │               네트워크 네임스페이스 (변경 없음)           │ │
│  └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘

Kubernetes v1.33의 주요 변경사항

Container Lifecycle 개선

v1.33에서는 컨테이너 라이프사이클과 관련된 중요한 업데이트가 포함되었습니다:

1. Zero-Duration Sleep Action (Beta, 기본 활성화)

  • PodLifecycleSleepActionAllowZero 기능이 베타로 승격되어 기본 활성화
  • PreStop/PostStart 훅에서 0초 대기 시간 설정 가능
  • No-op preStop 훅 정의가 필요한 경우 유용
apiVersion: v1
kind: Pod
metadata:
  name: example-pod
spec:
  containers:
  - name: app
    image: nginx
    lifecycle:
      preStop:
        sleep:
          seconds: 0  # v1.33부터 0초 설정 가능

2. Custom Stop Signals (Alpha)

  • ContainerStopSignals 기능 게이트 추가 (Alpha)
  • Pod 스펙에서 직접 커스텀 종료 시그널 지정 가능
  • 컨테이너 이미지 재빌드 없이 종료 시그널 변경 가능
apiVersion: v1
kind: Pod
metadata:
  name: custom-signal-pod
spec:
  os:
    name: linux
  containers:
  - name: app
    image: nginx:latest
    lifecycle:
      stopSignal: SIGUSR1  # 커스텀 종료 시그널

참고:

  • kube-apiserver와 kubelet 모두에서 ContainerStopSignals 기능 게이트 활성화 필요
  • containerd와 CRI-O의 구현은 진행 중
  • Windows 노드에서는 SIGTERM과 SIGKILL만 지원

Containerd 2.1 업데이트

  • Kubernetes v1.33은 containerd 2.1을 기본으로 사용
  • CRI v1alpha2 API 지원 종료
  • 기존 클러스터는 노드 업그레이드 시 containerd 2.1로 자동 업그레이드

Kubernetes 버전별 변경사항

Kubernetes 버전Pause 버전주요 변경사항
v1.333.10containerd 2.1 기본 사용, Zero-duration sleep 지원
v1.303.9Sleep action 기본 활성화
v1.293.9PreStop/PostStart Sleep action 도입
v1.263.9-
v1.253.8-3.9registry.k8s.io로 레지스트리 변경
v1.233.6-
v1.8+3.1+PID 네임스페이스 공유 기본 비활성화
v1.73.1좀비 프로세스 제거 기능 추가

Pause 컨테이너 확인 방법

1. 노드에서 프로세스 확인

# 노드 접속
docker exec -it <node-name> bash

# 프로세스 트리 확인
pstree -aln

# Pause 컨테이너 확인 (containerd 사용 시)
crictl ps | grep pause

프로세스 트리 예시

systemd─┬─containerd─┬─containerd-shim─┬─pause
        │            │                  └─{pause}
        │            └─containerd-shim─┬─nginx
        │            │                  ├─nginx
        │            │                  └─{nginx}
        │            └─containerd-shim─┬─sidecar
        │                               └─{sidecar}

2. 네임스페이스 확인

# 프로세스 네임스페이스 확인
pstree -aclnpsS

# 특정 PID의 네임스페이스 확인
lsns -p <PID>

# Pause 컨테이너 PID 찾기
PAUSEPID=$(ps -ef | grep '/pause' | grep -v grep | awk '{print $2}')
lsns -p $PAUSEPID

네임스페이스 공유 확인 예시

# Pause 컨테이너 네임스페이스
        NS TYPE   NPROCS   PID USER COMMAND
4026531837 time       146     1 root /sbin/init
4026531836 cgroup     146     1 root /sbin/init
4026532621 mnt           1  1234 root /pause
4026532620 uts           2  1234 root /pause
4026532619 ipc           2  1234 root /pause
4026532618 pid           1  1234 root /pause
4026532617 net           2  1234 root /pause

# Nginx 컨테이너 네임스페이스
        NS TYPE   NPROCS   PID USER COMMAND
4026531837 time       146     1 root /sbin/init
4026531836 cgroup     146     1 root /sbin/init
4026532623 mnt           1  5678 root nginx: master process
4026532620 uts           2  1234 root /pause        # 공유됨
4026532619 ipc           2  1234 root /pause        # 공유됨
4026532622 pid           1  5678 root nginx: master process
4026532617 net           2  1234 root /pause        # 공유됨

3. 컨테이너 이미지 확인

# containerd 사용 시
crictl images | grep pause

# 출력 예시:
# registry.k8s.io/pause    3.10    <image-id>    <size>

Pause 컨테이너 이미지 설정

기본 이미지 위치

  • Kubernetes v1.25+: registry.k8s.io/pause:3.10
  • 이전 버전: k8s.gcr.io/pause:3.x

containerd 설정 변경

containerd v1.x:

# /etc/containerd/config.toml
[plugins."io.containerd.grpc.v1.cri"]
  sandbox_image = "registry.k8s.io/pause:3.10"

containerd v2.x:

# /etc/containerd/config.toml
version = 3

[plugins.'io.containerd.cri.v1.images']
  [plugins.'io.containerd.cri.v1.images'.pinned_images]
    sandbox = 'your-registry.com/pause:3.10'

kubelet 설정 변경

# kubelet 설정 파일 수정
vi /etc/systemd/system/kubelet.service.d/10-kubeadm.conf

# --pod-infra-container-image 플래그 추가
--pod-infra-container-image=your-registry.com/pause:3.10

# systemd 재로드 및 kubelet 재시작
systemctl daemon-reload
systemctl restart kubelet

멀티 컨테이너 Pod 예제

Pod 생성

apiVersion: v1
kind: Pod
metadata:
  name: multi-container-pod
spec:
  containers:
  - name: nginx
    image: nginx
    ports:
    - containerPort: 80
      protocol: TCP
  - name: netshoot
    image: nicolaka/netshoot
    command: ["/bin/bash"]
    args: ["-c", "while true; do sleep 5; curl localhost; done"]
  terminationGracePeriodSeconds: 0

멀티 컨테이너 Pod 구조도

┌─────────────────────────────────────────────────────────────┐
│                      Pod                                    │
│                      IP: 10.244.1.5                        │
│                                                             │
│  ┌─────────────────────┐                                    │
│  │   Pause 컨테이너     │                                    │
│  │   (PID 1)           │                                    │
│  │                     │                                    │
│  │  Network Namespace  ├────────────────────────────────────┤
│  │  IPC Namespace      │                                    │
│  │  UTS Namespace      │                                    │
│  └─────────────────────┘                                    │
│           ↑                                                 │
│           │ 공유                                             │
│           ↓                                                 │
│  ┌─────────────────────┐  ┌───────────────────────────────┐ │
│  │   Nginx 컨테이너     │  │      Netshoot 컨테이너         │ │
│  │                     │  │                               │ │
│  │  Network Namespace  │  │  Network Namespace             │ │
│  │  IPC Namespace      │  │  IPC Namespace                 │ │
│  │  UTS Namespace      │  │  UTS Namespace                 │ │
│  │                     │  │                               │ │
│  │  Port: 80           │  │  curl localhost:80             │ │
│  └─────────────────────┘  └───────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘

동작 확인

# Pod 정보 확인 (IP는 1개만 할당됨)
kubectl describe pod multi-container-pod

# 각 컨테이너의 네트워크 인터페이스 확인
kubectl exec multi-container-pod -c nginx -- ip addr
kubectl exec multi-container-pod -c netshoot -- ip addr

# 두 컨테이너가 동일한 네트워크 네임스페이스 공유 확인
# 노드에서 실행
docker exec -it <worker-node> bash

NGINX_PID=$(ps -ef | grep 'nginx -g' | grep -v grep | awk '{print $2}')
NETSHOOT_PID=$(ps -ef | grep 'curl' | grep -v grep | awk '{print $2}')

# 네임스페이스 비교
lsns -p $NGINX_PID
lsns -p $NETSHOOT_PID
# -> Network, IPC, UTS 네임스페이스가 동일함을 확인 가능

Private Registry 사용 시 주의사항

문제 상황

인터넷 접근이 제한된 환경이나 Private Registry를 사용하는 경우, Pause 이미지를 가져오지 못해 Pod 생성이 실패할 수 있습니다.

Private Registry 설정 흐름도

graph LR
    A[Pod 생성 요청] --> B[Kubelet]
    B --> C[Pause 이미지 Pull 시도]
    C --> D{Public Registry 접근 가능?}
    D -->|Yes| E[이미지 Pull 성공]
    D -->|No| F[Private Registry 설정 확인]
    F --> G{Private Registry에 이미지 존재?}
    G -->|Yes| H[인증 정보 확인]
    H --> I[이미지 Pull 성공]
    G -->|No| J[이미지 미러링 필요]
    J --> K[Public Registry에서 Pull]
    K --> L[Private Registry로 Push]
    L --> M[containerd 설정 업데이트]
    M --> N[서비스 재시작]
    N --> I
    E --> O[Pod 생성 성공]
    I --> O

해결 방법

1. 이미지 미러링

# Public Registry에서 Pull
crictl pull registry.k8s.io/pause:3.10

# Private Registry로 Tag
crictl tag registry.k8s.io/pause:3.10 private-registry.com/pause:3.10

# Private Registry로 Push
crictl push private-registry.com/pause:3.10

2. containerd 설정 업데이트

[plugins."io.containerd.grpc.v1.cri"]
  sandbox_image = "private-registry.com/pause:3.10"

3. 서비스 재시작

systemctl restart containerd
systemctl restart kubelet

베스트 프랙티스

1. 이미지 사전 Pull

클러스터 노드를 설정할 때 Pause 이미지를 미리 Pull하여 Pod 생성 지연을 방지합니다.

# 클러스터 초기화 전 실행
crictl pull registry.k8s.io/pause:3.10

2. Private Registry 사용

프로덕션 환경에서는 인터넷 의존성을 제거하기 위해 Pause 이미지를 Private Registry에 미러링합니다.

3. 네트워크 정책 설정

방화벽이나 네트워크 정책을 설정할 때 registry.k8s.io 접근을 허용하거나, Private Registry를 사용하도록 구성합니다.

4. 버전 관리

Kubernetes 업그레이드 시 Pause 컨테이너 버전도 함께 업데이트되는지 확인합니다.

# kubeadm으로 확인
kubeadm config images list

# containerd 설정 확인
crictl info | grep sandboxImage

트러블슈팅

문제 1: Pause 이미지 Pull 실패

증상:

Failed to create pod sandbox: rpc error: code = Unknown desc = failed to pull image "registry.k8s.io/pause:3.10"

해결:
1. 네트워크 연결 확인
2. containerd 설정에서 sandbox_image 경로 확인
3. Private Registry 사용 시 이미지가 존재하는지 확인
4. imagePullSecrets 설정 (인증 필요한 경우)

문제 2: Pause 컨테이너 버전 불일치

증상:

kubeadm config images list  # pause:3.10 표시
crictl ps | grep pause      # pause:3.9 실행 중

해결:
1. 기존 Pod 삭제 및 재생성
2. containerd 재시작
3. kubelet 재시작
4. 노드 재부팅 (필요시)

문제 3: Pod IP가 변경됨

증상:
애플리케이션 컨테이너 재시작 후 Pod IP가 변경됨

원인:
Pause 컨테이너가 종료되어 네트워크 네임스페이스가 재생성됨

해결:
1. Pause 컨테이너 로그 확인
2. kubelet 로그에서 Pod sandbox 재생성 이벤트 확인
3. 노드 리소스 상태 확인 (메모리, CPU)


요약

Kubernetes v1.33에서 Pause 컨테이너는 기존 역할을 유지하면서 다음과 같은 개선이 이루어졌습니다:

  • Zero-duration sleep 지원: PreStop/PostStart 훅에서 0초 대기 설정 가능 (기본 활성화)
  • 커스텀 종료 시그널: Pod 스펙에서 직접 종료 시그널 지정 가능 (Alpha)
  • containerd 2.1: 최신 컨테이너 런타임 지원

Pause 컨테이너는 여전히 Pod의 네트워크 네임스페이스 관리와 좀비 프로세스 제거라는 핵심 역할을 수행하며, Kubernetes의 Pod 추상화를 구현하는 핵심 컴포넌트입니다.

Pause 컨테이너의 핵심 가치

┌─────────────────────────────────────────────────────────────┐
│                   Pause 컨테이너의 핵심 가치                  │
│                                                             │
│  ┌─────────────────────────────────────────────────────────┐ │
│  │  1. 네트워크 추상화                                    │ │
│  │     - Pod 내 모든 컨테이너가 동일한 IP 주소 공유       │ │
│  │     - 컨테이너 재시작 시에도 네트워크 연결 유지        │ │
│  │                                                         │ │
│  │  2. 리소스 관리                                        │ │
│  │     - 좀비 프로세스 제거                                │ │
│  │     - 네임스페이스 공유로 리소스 효율화                │ │
│  │                                                         │ │
│  │  3. Pod 생명주기 관리                                  │ │
│  │     - Pod의 안정적인 실행 보장                          │ │
│  │     - 컨테이너 간 격리 및 통신 지원                     │ │
│  └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘

참고 자료

--

네, 알겠습니다. 요청하신 내용을 바탕으로 Pause 컨테이너의 역할을 도식화하여 설명해 드리겠습니다.

아래 다이어그램은 Pod가 생성되고, 그 안에 Pause 컨테이너와 애플리케이션 컨테이너들이 어떻게 네임스페이스를 공유하며 통신 가능한 상태가 되는지 단계별로 보여줍니다.

Draw.io 다이어그램: Pause 컨테이너와 네임스페이스 공유

<mxfile host="app.diagrams.net" modified="2024-05-23T01:00:00.000Z" agent="5.0" etag="pause-container-diagram" version="21.2.3" type="device">
  <diagram name="페이지-1" id="pause-container-page-1">
    <mxGraphModel dx="1422" dy="794" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1169" pageHeight="827" math="0" shadow="0">
      <root>
        <mxCell id="0" />
        <mxCell id="1" parent="0" />
        
        <!-- Step 1: Pod -->
        <mxCell id="pod" value="Pod (논리적 호스트)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=16;fontStyle=1" vertex="1" parent="1">
          <mxGeometry x="40" y="40" width="720" height="440" as="geometry" />
        </mxCell>
        
        <!-- Shared Namespace Layer -->
        <mxCell id="namespace-layer" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;dashed=1;dashPattern=8 8;" vertex="1" parent="pod">
          <mxGeometry x="20" y="80" width="680" height="340" as="geometry" />
        </mxCell>
        <mxCell id="ns-label" value="공유 네임스페이스 (Network, IPC, UTS)" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=14;fontStyle=1" vertex="1" parent="pod">
          <mxGeometry x="200" y="90" width="320" height="30" as="geometry" />
        </mxCell>

        <!-- Step 2: Pause Container -->
        <mxCell id="pause-container" value="Pause 컨테이너&#xa;(PID 1, &quot;부모&quot; 역할)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontSize=14;fontStyle=1" vertex="1" parent="pod">
          <mxGeometry x="40" y="140" width="180" height="80" as="geometry" />
        </mxCell>
        
        <!-- Arrows from Pause to Namespaces -->
        <mxCell id="arrow1" value="네트워크 네임스페이스 생성" style="endArrow=classic;html=1;rounded=0;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;fontSize=12;strokeColor=#82b366;" edge="1" parent="pod" source="pause-container" target="namespace-layer">
          <mxGeometry width="50" height="50" relative="1" as="geometry">
            <mxPoint x="250" y="200" as="sourcePoint" />
            <mxPoint x="300" y="150" as="targetPoint" />
            <Array as="points">
              <mxPoint x="260" y="180" />
            </Array>
          </mxGeometry>
        </mxCell>
        <mxCell id="arrow2" value="IPC 네임스페이스 생성" style="endArrow=classic;html=1;rounded=0;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;fontSize=12;strokeColor=#82b366;" edge="1" parent="pod" source="pause-container" target="namespace-layer">
          <mxGeometry width="50" height="50" relative="1" as="geometry">
            <mxPoint x="250" y="200" as="sourcePoint" />
            <mxPoint x="300" y="200" as="targetPoint" />
            <Array as="points">
              <mxPoint x="260" y="200" />
            </Array>
          </mxGeometry>
        </mxCell>
        <mxCell id="arrow3" value="UTS 네임스페이스 생성" style="endArrow=classic;html=1;rounded=0;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;fontSize=12;strokeColor=#82b366;" edge="1" parent="pod" source="pause-container" target="namespace-layer">
          <mxGeometry width="50" height="50" relative="1" as="geometry">
            <mxPoint x="250" y="200" as="sourcePoint" />
            <mxPoint x="300" y="250" as="targetPoint" />
            <Array as="points">
              <mxPoint x="260" y="220" />
            </Array>
          </mxGeometry>
        </mxCell>

        <!-- Step 3: Application Containers -->
        <mxCell id="app-container-1" value="애플리케이션 컨테이너 1&#xa;(예: Nginx)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;fontSize=14;" vertex="1" parent="pod">
          <mxGeometry x="420" y="140" width="180" height="80" as="geometry" />
        </mxCell>
        <mxCell id="app-container-2" value="애플리케이션 컨테이너 2&#xa;(예: Sidecar)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;fontSize=14;" vertex="1" parent="pod">
          <mxGeometry x="420" y="280" width="180" height="80" as="geometry" />
        </mxCell>

        <!-- Arrows from Apps to Namespaces (Joining) -->
        <mxCell id="join-arrow-1" value="네임스페이스 참여" style="endArrow=classic;html=1;rounded=0;exitX=0;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;fontSize=12;strokeColor=#b85450;dashed=1;" edge="1" parent="pod" source="app-container-1" target="namespace-layer">
          <mxGeometry width="50" height="50" relative="1" as="geometry">
            <mxPoint x="550" y="200" as="sourcePoint" />
            <mxPoint x="600" y="150" as="targetPoint" />
            <Array as="points">
              <mxPoint x="380" y="180" />
            </Array>
          </mxGeometry>
        </mxCell>
        <mxCell id="join-arrow-2" value="네임스페이스 참여" style="endArrow=classic;html=1;rounded=0;exitX=0;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;fontSize=12;strokeColor=#b85450;dashed=1;" edge="1" parent="pod" source="app-container-2" target="namespace-layer">
          <mxGeometry width="50" height="50" relative="1" as="geometry">
            <mxPoint x="550" y="200" as="sourcePoint" />
            <mxPoint x="600" y="250" as="targetPoint" />
            <Array as="points">
              <mxPoint x="380" y="320" />
            </Array>
          </mxGeometry>
        </mxCell>

        <!-- Step 4: Communication -->
        <mxCell id="comm-arrow" value="통신 (curl localhost:80)" style="endArrow=classic;html=1;rounded=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontSize=12;fontStyle=1;strokeColor=#4a86e8;strokeWidth=2;" edge="1" parent="pod" source="app-container-2" target="app-container-1">
          <mxGeometry width="50" height="50" relative="1" as="geometry">
            <mxPoint x="510" y="280" as="sourcePoint" />
            <mxPoint x="510" y="220" as="targetPoint" />
          </mxGeometry>
        </mxCell>

        <!-- Step Labels -->
        <mxCell id="step1" value="1. Pod 생성" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=12;fontStyle=1" vertex="1" parent="1">
          <mxGeometry x="50" y="20" width="100" height="30" as="geometry" />
        </mxCell>
        <mxCell id="step2" value="2. Pause 컨테이너가&#xa;네임스페이스 생성" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=12;fontStyle=1" vertex="1" parent="1">
          <mxGeometry x="50" y="240" width="150" height="30" as="geometry" />
        </mxCell>
        <mxCell id="step3" value="3. 애플리케이션 컨테이너들이&#xa;네임스페이스를 참여(공유)" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=12;fontStyle=1" vertex="1" parent="1">
          <mxGeometry x="620" y="240" width="200" height="30" as="geometry" />
        </mxCell>
        <mxCell id="step4" value="4. 결과: 동일한 네임스페이스를&#xa;공유하므로 컨테이너 간 통신 가능" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=12;fontStyle=1" vertex="1" parent="1">
          <mxGeometry x="240" y="500" width="320" height="30" as="geometry" />
        </mxCell>

      </root>
    </mxGraphModel>
  </diagram>
</mxfile>

다이어그램 단계별 설명

위 다이어그램은 Pause 컨테이너의 핵심적인 역할을 4단계로 나누어 보여줍니다.

1단계: Pod 생성

  • 먼저 Pod라는 가상의 경계(논리적 호스트)가 생성됩니다.
  • 이 시점에는 아직 내부에 아무것도 없습니다.

2단계: Pause 컨테이너 생성 및 네임스페이스 설정

  • Pod가 생성되면 가장 먼저 초록색 Pause 컨테이너가 실행됩니다.
  • 이 Pause 컨테이너는 Pod를 위한 네트워크(Network), IPC, UTS 네임스페이스를 생성하고 소유합니다.
  • 다이어그램에서는 Pause 컨테이너가 노란색 배경의 '공유 네임스페이스' 영역을 만들어내는 것으로 표현했습니다.
  • 이때 Pod에 할당된 단 하나의 IP 주소는 이 네트워크 네임스페이스에 귀속됩니다.

3단계: 애플리케이션 컨테이너 생성 및 네임스페이스 참여

  • 이후 사용자가 정의한 빨간색 애플리케이션 컨테이너들(Nginx, Sidecar 등)이 생성됩니다.
  • 이 컨테이너들은 자신만의 네임스페이스를 만드는 대신, 이미 Pause 컨테이너가 만들어놓은 네임스페이스에 '참여'합니다.
  • 다이어그램의 점선 화살표는 애플리케이션 컨테이너가 기존 네임스페이스에 합류하는 과정을 의미합니다.

4단계: 결과 - 컨테이너 간 통신

  • 모든 컨테이너가 동일한 네트워크 네임스페이스를 공유하게 됩니다.
  • 따라서 마치 하나의 컴퓨터 안에서 여러 프로세스가 실행되는 것처럼, 컨테이너들은 서로 localhost를 통해 통신할 수 있습니다.
  • 다이어그램의 파란색 굵은 화살표는 Sidecar 컨테이너가 curl localhost:80 명령으로 Nginx 컨테이너와 통신하는 모습을 보여줍니다.

핵심 요약

  • Pause 컨테이너 = Pod의 '인프라' 또는 '주춧돌'
  • 먼저 생성되어 네임스페이스를 '소유'합니다.
  • 다른 컨테이너들은 나중에 생성되어 네임스페이스를 '참여/공유'합니다.
  • 이 구조 덕분에 Pod는 하나의 IP 주소를 가지며, 내부 컨테이너들은 localhost로 통신할 수 있게 됩니다.

이 도식화를 통해 Pause 컨테이너가 왜 '보이지 않지만 항상 존재하며' Pod의 정체성을 유지하는 데 필수적인지 쉽게 이해하실 수 있을 것입니다.

profile
bytebliss

0개의 댓글