Init コンテナの追加

KubernetesBeginner
オンラインで実践に進む

はじめに

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 でも同じパターンが機能することを確認しました。