問題:PodがInit:CrashLoopBackOffで停止する
マニフェストをデプロイしたものの、Podが動作しないことがあります。Kubernetesにおいて、initContainersはゲートキーパーの役割を果たします。メインのアプリケーションコンテナは、すべての初期化コンテナ(init container)が終了コード0で正常に終了するまで起動を試みません。いずれかが失敗して再起動ループに陥ると、PodはInit:CrashLoopBackOff状態のまま動かなくなります。
これはよくあるボトルネックです。メインコンテナがまだ作成されていないため、標準的なログコマンドを実行しても何も得られず、フラストレーションが溜まるだけです。技術的にはまだ始まってさえいないプロセスのデバッグを強いられることになります。
ステップ1:失敗しているコンテナを特定する
Podは多くの場合、複数の初期化コンテナを順番に実行します。最初のステップは、一連の処理のどこで問題が発生しているかを特定することです。describeコマンドを使用して、Podの内部状態を確認します。
kubectl describe pod <pod-name>
Init Containers:セクションまでスクロールしてください。ゼロ以外の終了コードや、特定の例外状態を探します。
Init Containers:
install-assets:
Container ID: containerd://...
Image: node:18-alpine
State: Waiting
Reason: CrashLoopBackOff
Last State: Terminated
Reason: Error
Exit Code: 127
この例では、install-assetsコンテナが失敗しています。終了コード127は、多くの場合、コンテナのシェル内で「command not found(コマンドが見つからない)」エラーが発生していることを示唆しています。
ステップ2:適切なログを抽出する
標準的なkubectl logs <pod-name>は、通常、メインのアプリケーションコンテナを対象とします。しかし、そのコンテナはまだ存在しないため、コマンドは失敗します。実際のエラーを確認するには、-cフラグを使用して初期化コンテナを明示的に指定する必要があります。
kubectl logs <pod-name> -c <init-container-name>
コンテナが高速でクラッシュを繰り返している場合、現在のログは空である可能性があります。その場合は、--previousフラグを使用して、直前の失敗した実行時のログを確認してください。多くの場合、ここに決定的な証拠(smoking gun)が残されています。
kubectl logs <pod-name> -c <init-container-name> --previous
よくある原因と解決策
1. シェルスクリプトとバイナリの不一致
多くの開発者は、初期化タスクにalpineやbusyboxなどの軽量イメージを使用します。スクリプトで#!/bin/bashを使用しているのに、イメージに/bin/shしか含まれていない場合、コンテナは即座にクラッシュします。同様に、スクリプトファイルに実行権限(chmod +x)がない場合も失敗の原因となります。
推奨されるアプローチ: YAML内で堅牢なスクリプトブロックを使用し、エラーを早期に検知できるよう常にset -eを含めるようにします。
command:
- /bin/sh
- -c
- |
set -e
echo "Checking database connectivity..."
# ncがない場合は/dev/tcpを使用する
timeout 5 sh -c 'cat < /dev/null > /dev/tcp/db-service/5432'
2. ConfigMapまたはSecretの欠落
初期化コンテナが、現在のネームスペースに存在しないSecretからデータベースのパスワードを取得しようとすると、Podは失敗します。valueFromの参照先が見つからない場合、Kubernetesはコンテナの起動すら行いません。一方、Secretは存在するもののキーが間違っている場合は、実行中にスクリプトがクラッシュする可能性があります。
解決策: kubectl get secretでSecretを確認し、キーがenvの定義と完全に一致していることを確認してください。
3. リソース枯渇 (OOMKilled)
データベースのマイグレーションやアセットのコンパイルなど、負荷の高い処理を行う初期化コンテナは、メインアプリよりも多くのリソースを必要とすることがあります。メモリ制限を128Miに設定していても、マイグレーションツールがピーク時に256Miを消費する場合、カーネルによってプロセスが強制終了されます。
解決策: describe podの出力でReason: OOMKilledを探してください。初期化コンテナ専用のリソース制限(limits)を引き上げます。
resources:
limits:
memory: "512Mi"
cpu: "500m"
4. RBACおよび権限のエラー
初期化コンテナでcurlを使用してKubernetes APIと通信していますか?その場合、適切なRoleを持つServiceAccountが必要です。権限がない場合、ログに403 Forbiddenエラーが表示されます。PodのserviceAccountNameに、タスクを実行するために必要な権限が付与されているか常に確認してください。
検証:修正の確認
マニフェストを更新して変更を適用した後、状態の遷移を監視します。正常なPodは以下のステージを経て進行します。
Init:0/1(最初の初期化コンテナが起動中)。PodInitializing(すべての初期化コンテナが終了し、メインコンテナをプル中)。Running(成功)。
kubectl get events --sort-by='.lastTimestamp'を使用してイベントログを確認し、根本的なスケジューリングの問題が残っていないか確認してください。
まとめ
- 初期化コンテナは順次実行される: 一つずつ順番に実行されます。一つでも失敗すると、Pod全体が停止します。
- ヘルスチェックがない: 初期化コンテナはlivenessプロブやreadinessプロブをサポートしていません。完全に終了コードのみに依存します。
- べき等性が不可欠: 初期化コンテナは複数回再起動される可能性があるため、スクリプトはデータを壊すことなく繰り返し実行できる(べき等である)必要があります。
- 常に
-cを使用する: 目に見えないものはデバッグできません。特定のコンテナを対象としたロギングは、最も強力なツールです。

