소개
Init 컨테이너는 Pod 내의 메인 애플리케이션 컨테이너가 시작되기 전에 실행됩니다. 각 Init 컨테이너는 다음 Init 컨테이너나 일반 컨테이너가 시작되기 전에 성공적으로 완료되어야 합니다. 이를 통해 Init 컨테이너는 파일 준비, 의존성 확인 또는 애플리케이션과 함께 계속 실행될 필요가 없는 간단한 설정 작업을 수행하는 데 유용하게 사용됩니다.
이번 실습에서는 공유 emptyDir 볼륨에 시작 파일을 작성하는 Init 컨테이너를 추가하고, 애플리케이션 컨테이너가 해당 파일을 읽을 수 있는지 확인하며, Init 컨테이너의 완료 상태와 로그를 검사한 뒤, 동일한 패턴을 Deployment 템플릿에 적용해 보겠습니다.
Init 컨테이너를 위한 네임스페이스 준비
이 단계에서는 Init 컨테이너 실습을 위한 깨끗한 네임스페이스를 준비합니다.
/home/labex/project 디렉토리에서 시작합니다. 이 디렉토리에 Pod 및 Deployment 매니페스트를 작성하게 됩니다.
mkdir -p /home/labex/project
cd /home/labex/project
Kubernetes API 서버에 접근 가능한지 확인합니다. VM 이 막 시작되어 노드가 아직 준비되지 않았다면, 몇 초 기다린 후 명령어를 다시 실행하세요.
kubectl get nodes --request-timeout=5s
예상 출력:
NAME STATUS ROLES AGE VERSION
labex-v135 Ready control-plane ... v1.35...
Init 컨테이너는 Pod 내부에서 실행되므로, 워크로드를 생성하기 전에 클러스터 네트워킹 Pod 가 준비 (Ready) 상태가 될 때까지 기다립니다.
kubectl wait --namespace kube-system --for=condition=Ready pod -l k8s-app=calico-node --timeout=120s
예상 출력:
pod/calico-node-... condition met
ckad-prep-init라는 이름의 네임스페이스를 생성합니다:
kubectl create namespace ckad-prep-init
이 네임스페이스를 현재 컨텍스트의 네임스페이스로 설정합니다:
kubectl config set-context --current --namespace=ckad-prep-init
현재 네임스페이스를 확인합니다:
kubectl config view --minify --output 'jsonpath={..namespace}'; echo
예상 출력:
ckad-prep-init
앱 시작 전 공유 데이터 준비
이 단계에서는 Init 컨테이너가 애플리케이션 컨테이너 시작 전에 파일을 준비하는 Pod 를 생성합니다.
emptyDir 볼륨은 Pod 가 노드에 할당될 때 생성되며, 동일한 Pod 내의 컨테이너들이 공유합니다. Init 컨테이너와 앱 컨테이너 모두 이 볼륨을 /work 경로에 마운트합니다. Init 컨테이너는 /work/startup.txt 파일을 작성한 후 종료됩니다. Init 컨테이너가 성공적으로 종료된 후에만 Kubernetes 가 앱 컨테이너를 시작합니다.
init-file-pod.yaml 파일을 생성합니다:
cat > init-file-pod.yaml <<'EOF'
apiVersion: v1
kind: Pod
metadata:
name: init-file-demo
labels:
app: init-file-demo
spec:
terminationGracePeriodSeconds: 0
volumes:
- name: shared-work
emptyDir: {}
initContainers:
- name: prepare-startup-file
image: busybox:1.36
command:
- /bin/sh
- -c
- 'echo init-started; echo prepared-by-init > /work/startup.txt; echo init-finished'
volumeMounts:
- name: shared-work
mountPath: /work
containers:
- name: app
image: busybox:1.36
command:
- /bin/sh
- -c
- 'echo app-started; cat /work/startup.txt; sleep 3600'
volumeMounts:
- name: shared-work
mountPath: /work
EOF
매니페스트를 적용합니다:
kubectl apply -f init-file-pod.yaml
예상 출력:
pod/init-file-demo created
Pod 가 준비 (Ready) 상태가 될 때까지 기다립니다:
kubectl wait --for=condition=Ready pod/init-file-demo --timeout=120s
예상 출력:
pod/init-file-demo condition met
앱 컨테이너 내부에서 파일을 읽어봅니다. 이는 Init 컨테이너가 앱 시작 전에 공유 볼륨에 데이터를 성공적으로 준비했음을 증명합니다.
kubectl exec init-file-demo -c app -- cat /work/startup.txt
예상 출력:
prepared-by-init
Init 컨테이너 상태 및 로그 검사
이 단계에서는 Init 컨테이너가 앱 컨테이너 실행 전에 완료되었다는 증거를 확인합니다.
Init 컨테이너는 .status.initContainerStatuses 아래에 나타나며, 일반 컨테이너는 .status.containerStatuses 아래에 나타납니다. Init 컨테이너는 성공적으로 종료되었으므로 Completed 상태여야 합니다.
kubectl get pod init-file-demo -o 'jsonpath={.status.initContainerStatuses[0].name}{" "}{.status.initContainerStatuses[0].state.terminated.reason}{"\n"}'
예상 출력:
prepare-startup-file Completed
이제 일반 애플리케이션 컨테이너의 상태를 확인합니다. 준비 (Ready) 상태이며 실행 중이어야 합니다.
kubectl get pod init-file-demo -o 'jsonpath={.status.containerStatuses[0].name}{" "}{.status.containerStatuses[0].ready}{" "}{.status.containerStatuses[0].state.running.startedAt}{"\n"}'
예상 출력:
app true ...
Init 컨테이너의 로그를 읽습니다. Init 컨테이너는 이미 종료되었지만, kubectl logs -c를 통해 로그를 확인할 수 있습니다.
kubectl logs init-file-demo -c prepare-startup-file
예상 출력:
init-started
init-finished
앱 컨테이너의 로그를 읽습니다. 앱은 Init 컨테이너가 파일을 작성한 후에 시작되므로, 로그에 준비된 값이 포함되어 있습니다.
kubectl logs init-file-demo -c app
예상 출력:
app-started
prepared-by-init
Deployment 에 Init 컨테이너 추가하기
이 단계에서는 Deployment 템플릿 내에서 동일한 Init 컨테이너 패턴을 사용합니다.
애플리케이션 워크로드의 경우, 일반적으로 독립적인 Pod 를 생성하는 대신 컨트롤러의 Pod 템플릿에 Init 컨테이너를 배치합니다. Deployment 가 Pod 를 생성하면, Kubernetes 는 해당 템플릿에서 생성된 각 Pod 에 대해 Init 컨테이너를 먼저 실행합니다.
init-deployment.yaml 파일을 생성합니다:
cat > init-deployment.yaml <<'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
name: init-web
spec:
replicas: 1
selector:
matchLabels:
app: init-web
template:
metadata:
labels:
app: init-web
spec:
terminationGracePeriodSeconds: 0
volumes:
- name: web-content
emptyDir: {}
initContainers:
- name: render-index
image: busybox:1.36
command:
- /bin/sh
- -c
- 'echo deployment-init > /site/index.txt'
volumeMounts:
- name: web-content
mountPath: /site
containers:
- name: web
image: busybox:1.36
command:
- /bin/sh
- -c
- 'cat /site/index.txt; sleep 3600'
volumeMounts:
- name: web-content
mountPath: /site
EOF
Deployment 를 적용합니다:
kubectl apply -f init-deployment.yaml
예상 출력:
deployment.apps/init-web created
Deployment 가 사용 가능 (Available) 상태가 될 때까지 기다립니다:
kubectl wait --for=condition=Available deployment/init-web --timeout=120s
예상 출력:
deployment.apps/init-web condition met
Deployment 에 의해 생성된 Pod 를 찾습니다:
web_pod="$(kubectl get pods -l app=init-web -o 'jsonpath={.items[0].metadata.name}')"
echo "$web_pod"
예상 출력 (생성된 Pod 이름):
init-web-...
해당 Pod 에서 앱 컨테이너의 로그를 읽습니다:
kubectl logs "$web_pod" -c web
예상 출력:
deployment-init
Deployment 가 생성한 Pod 내부에서 Init 컨테이너의 완료 상태를 확인합니다:
kubectl get pod "$web_pod" -o 'jsonpath={.status.initContainerStatuses[0].name}{" "}{.status.initContainerStatuses[0].state.terminated.reason}{"\n"}'
예상 출력:
render-index Completed
요약
Pod 와 Deployment 템플릿에 Init 컨테이너를 추가하는 방법을 실습했습니다. emptyDir 볼륨을 사용하여 준비된 파일을 앱 컨테이너와 공유하고, 완료된 Init 컨테이너의 상태를 검사하며, Init 및 앱 로그를 읽고, 동일한 패턴이 컨트롤러로 관리되는 애플리케이션 Pod 에서도 작동함을 확인했습니다.


