はじめに
Init コンテナは、Pod 内のメインアプリケーションコンテナが起動する前に実行されるコンテナです。各 Init コンテナは、Kubernetes が次の 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 という理由(reason)が表示されるはずです。
kubectl get pod init-file-demo -o 'jsonpath={.status.initContainerStatuses[0].name}{" "}{.status.initContainerStatuses[0].state.terminated.reason}{"\n"}'
期待される出力:
prepare-startup-file Completed
次に、通常のアプリケーションコンテナのステータスを確認します。準備が完了し、実行中であるはずです。
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 が利用可能になるまで待ちます。
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 コンテナの完了ステータスの確認、ログの読み取りを行い、コントローラー管理下のアプリケーション Pod でも同じパターンが機能することを確認しました。


