失敗する Pod をデバッグする:describe、logs、exec、port-forward
Pod が Pending のまま、クラッシュする、応答しない原因を突き止めるための、繰り返し使えるチェックリスト。
遅かれ早かれ、Pod が起動しない、再起動を繰り返す、または動作しているのに応答しないという事態に遭遇します。解決策は、ほとんどの場合、いくつかの kubectl コマンドを正しい順序で使えば見えてきます。このガイドでは、その順序を示します。ステータスを読む、イベントを尋ねる、ログを読む、コンテナの中に入る、そしてネットワークパスをたどる、です。
まずステータスを読む
まずステータスの列から始めます。
kubectl get pods -o wide
最も一般的な状態と、最初に見る場所は次のとおりです。
- Pending。 Pod がノードに割り当てられていません。通常、CPU やメモリが足りない、クォータを使い果たした、ボリュームをバインドできないなどです。
describeがどれかを教えてくれます。 - ContainerCreating。 ノードがコンテナを準備しています。このままの状態が続く場合は、ボリュームの欠落や、イメージの pull の遅さを確認してください。
- ErrImagePull / ImagePullBackOff。 イメージを pull できません。ほとんどは、名前やタグのタイプミス、またはプライベートレジストリの認証情報の欠落が原因です。
- CrashLoopBackOff。 コンテナが起動し、終了し、増加する遅延とともに繰り返し再起動されます。アプリケーションが失敗しているので、そのログを読みます。
- CreateContainerConfigError。 Pod が、存在しない ConfigMap、Secret、またはキーを参照しています。
- Running だが
READY 0/1。 コンテナは起動していますが、readiness probe に失敗しています。 - OOMKilled(
describeに表示)。コンテナがメモリ制限を超えました。
Kubernetes に理由を尋ねる:describe とイベント
kubectl describe pod POD_NAME
下部の Events セクションまでスクロールします。タイムラインのように読めます。Scheduled、Pulling、Failed、BackOff です。0/3 nodes are available: insufficient cpu や Failed to pull image "ngnix:1.25" のようなメッセージは、たいてい問題を直接指しています。その上では、各コンテナの State と Last State で、終了コードと理由を確認します。namespace 全体で何が起きていたかのビューは次のとおりです。
kubectl get events --sort-by=.metadata.creationTimestamp
コンテナの出力を読む
kubectl logs POD_NAME
kubectl logs POD_NAME -c CONTAINER_NAME
kubectl logs POD_NAME --all-containers
kubectl logs POD_NAME --previous
kubectl logs POD_NAME -f --since=10m --tail=100
Pod に複数のコンテナがある場合は -c、ストリーミングには -f、出力を制限するには --since と --tail、そして最後にクラッシュしたインスタンスのログを読むには --previous を使います。クラッシュループではこれが必要です。試すには、意図的に失敗するコンテナを持つ Deployment を作成します。
kubectl create deployment crashy --image=busybox:1.36 -- \
sh -c 'echo starting; echo "fatal: DB_URL is not set" >&2; exit 1'
kubectl get pods -l app=crashy
kubectl logs deployment/crashy --previous
ステータスは CrashLoopBackOff になり、ログが理由を示します。kubectl delete deployment crashy で片付けます。
ログは Pod に属していることに注意してください。Pod が削除されたり置き換えられたりすると、そのログも一緒にクリーンアップされます。履歴が必要な場合は、Fluentd や Fluent Bit のようなログコレクターが、ログを耐久性のある場所に送る必要があります。
中に入る:exec、port-forward、cp
kubectl exec -it POD_NAME -- sh
kubectl exec POD_NAME -- env
kubectl port-forward pod/POD_NAME 8080:80
curl http://localhost:8080
kubectl cp POD_NAME:/path/to/file ./file
exec はコンテナ内でコマンドを実行し、port-forward はローカルポートを Pod のポートに接続し(svc/NAME でも動作します)、cp はファイルをコピーして出し入れします。多くの本番用イメージは最小限で、シェルも curl もありません。その場合、kubectl debug -it POD_NAME --image=busybox:1.36 --target=CONTAINER_NAME で、Pod の namespace を共有する一時的なデバッグ用コンテナをアタッチできます。
稼働中のコンテナ内で行った変更、たとえば設定ファイルの編集は、Pod が置き換えられるとすぐに失われます。exec は調査に使い、修正はイメージ、マニフェスト、または ConfigMap に対して行ってください。
リクエストの経路を逆にたどる
Pod は正常に見えるのにアプリケーションに到達できない場合は、内側から外側へと経路をたどります。
- Pod は実行中で
READYですか。まず Pod を直します。 - Service のセレクターは Pod のラベルと一致していますか。
kubectl get pods --show-labelsとkubectl describe service NAMEが一致しているはずです。 - Service にエンドポイントがありますか。
kubectl get endpointslices -l kubernetes.io/service-name=NAMEは、Pod の IP を一覧表示するはずです。空のリストは、セレクターの不一致か、準備完了の Pod がないことを意味します。 - ポートは一致していますか。Service の
targetPortは、コンテナが実際にリッスンしているポートである必要があります。 - 別の Pod から動作しますか。
kubectl run tmp --rm -it --image=busybox:1.36 --restart=Never -- wget -qO- http://NAME。これは DNS と Service をテストし、クラスターの外にあるものを除外します。 - NetworkPolicy がブロックしている可能性はありますか。
kubectl get networkpolicyで一覧表示します。 - 最後に、その前段にある Ingress や外部ロードバランサーを確認します。
各ステップが問題を 1 つの層に絞り込むため、推測するより速くなります。
人気のガイド
-
Kubernetes とは何か、そしてそれが解決する問題 コンテナだけではスケールしなくなる理由と、Kubernetes がマシンの集まりを 1 つのプラットフォームに変える方法。 -
Kubernetes クラスターの仕組み:コントロールプレーンとノード クラスターを動かすコンポーネントと、kubectl apply から実行中のコンテナまでの間に何が起きるか。 -
Deployment:スケーリング、自己修復、ローリングアップデート Pod のレプリカを実行し、ダウンタイムなしで更新し、リリースがうまくいかなかったときにロールバックします。 -
Service:短命な Pod のための安定したネットワーキング Pod に安定したアドレスを与え、クラスターの内外に公開し、誰が誰と通信できるかを制限します。