このページでは、Google Kubernetes Engine(GKE)でデプロイされたワークロードのエラーを解決する方法について説明します。
アプリケーションのトラブルシューティングに関する一般的なアドバイスについては、Kubernetes のドキュメントでアプリケーションのトラブルシューティングをご覧ください。
すべてのエラー: Pod のステータスを確認する
ワークロードの Pod に問題がある場合、Kubernetes は Pod のステータスをエラー メッセージとともに更新します。これらのエラーを確認するには、 Google Cloud コンソールまたは kubectl
コマンドライン ツールを使用して Pod のステータスを確認します。
コンソール
次の手順を行います。
Google Cloud コンソールで、[ワークロード] ページに移動します。
調査するワークロードを選択します。[概要] タブにワークロードのステータスが表示されます。
[マネージド Pod] セクションで、エラー ステータス メッセージをクリックします。
kubectl
クラスタで実行しているすべての Pod を表示するには、次のコマンドを実行します。
kubectl get pods
出力は次のようになります。
NAME READY STATUS RESTARTS AGE
POD_NAME 0/1 CrashLoopBackOff 23 8d
発生する可能性のあるエラーは Status
列に示されます。
特定の Pod に関する詳細情報を取得するには、次のコマンドを実行します。
kubectl describe pod POD_NAME
POD_NAME
を調査する Pod の名前に置き換えます。
出力の Events
フィールドに、エラーの詳細が表示されます。
詳細については、コンテナログを表示します。
kubectl logs POD_NAME
これらのログは、コンテナ内のコマンドまたはコードが Pod のクラッシュの原因であるかどうかを特定する際に役立ちます。
エラーを特定したら、次のセクションに進み、問題を解決してください。
エラー: CrashLoopBackOff
ステータスが CrashLoopBackOff
の場合、特定のエラーがあるわけではなく、コンテナが再起動後に繰り返しクラッシュしていることを示します。コンテナが起動直後にクラッシュまたは終了した場合(CrashLoop
)、Kubernetes はコンテナの再起動を試みます。再起動が失敗するたびに、次の試行までの遅延(BackOff
)は指数関数的に増加し(10 秒、20 秒、40 秒など)、最大で 5 分になります。
以降のセクションでは、コンテナがクラッシュする原因を特定する方法について説明します。
クラッシュループしている Pod のインタラクティブ ハンドブックを使用する
Google Cloud コンソールのインタラクティブ ハンドブックを使用して、CrashLoopBackOff
ステータスの原因のトラブルシューティングを開始します。
クラッシュループしている Pod のインタラクティブ ハンドブックに移動します。
[クラスタ] プルダウン リストで、トラブルシューティングするクラスタを選択します。クラスタが見つからない場合は、
(フィルタ)フィールドにクラスタの名前を入力します。[Namespace] プルダウン リストで、トラブルシューティングする Namespace を選択します。Namespace が見つからない場合は、
(フィルタ)フィールドに Namespace を入力します。各セクションを確認して、原因を特定します。
- アプリケーション エラーの特定
- メモリ不足問題の調査
- ノードの中断を調査する
- livenessProbe 失敗の調査
- 変更イベントの相関
省略可: 今後
CrashLoopBackOff
エラーが発生した場合に通知を受け取るには、[今後の対応のヒント] セクションで [アラートを作成する] を選択します。
ログを検査する
コンテナはさまざまな理由でクラッシュすることがあり、Pod のログを調べると根本原因のトラブルシューティングに役立ちます。
ログを確認するには、 Google Cloud コンソールまたは kubectl
コマンドライン ツールを使用します。
コンソール
次の手順を行います。
Google Cloud コンソールの [ワークロード] ページに移動します。
調査するワークロードを選択します。[概要] タブにワークロードのステータスが表示されます。
[マネージド Pod] セクションで、問題のある Pod をクリックします。
Pod のメニューで、[ログ] タブをクリックします。
kubectl
クラスタで実行されているすべての Pod を表示します。
kubectl get pods
上記のコマンドの出力で、
Status
列にCrashLoopBackOff
エラーがある Pod を探します。Pod のログを取得します。
kubectl logs POD_NAME
POD_NAME
は、問題のある Pod の名前に置き換えます。また、
-p
フラグを使用して、Pod の以前のコンテナ インスタンス(存在する場合)のログを取得することもできます。
クラッシュしたコンテナの終了コードを確認する
コンテナがクラッシュした理由を詳しく把握するには、終了コードを確認します。
Pod の説明を取得します。
kubectl describe pod POD_NAME
POD_NAME
は、問題のある Pod の名前に置き換えます。containers: CONTAINER_NAME: last state: exit code
フィールドの値を確認します。- 終了コードが 1 の場合、コンテナがクラッシュした理由はアプリケーションのクラッシュです。
- 終了コードが 0 の場合は、アプリの実行時間を確認します。コンテナは、アプリケーションのメインプロセスが終了したときに終了します。アプリの実行が非常に速く終了する場合、コンテナが再起動を続行している可能性があります。このエラーが発生した場合は、
restartPolicy
フィールドをOnFailure
に設定することをおすすめします。この変更を行うと、終了コードが 0 でない場合のみ、アプリが再起動されます。
実行中のコンテナに接続する
コンテナから bash コマンドを実行してネットワークをテストしたり、アプリケーションで使用されているファイルやデータベースにアクセスできるかどうかを確認するには、Pod へのシェルを開始します。
kubectl exec -it POD_NAME -- /bin/bash
Pod 内にコンテナが複数ある場合は、-c CONTAINER_NAME
を追加します。
エラー: ImagePullBackOff と ErrImagePull
ステータスが ImagePullBackOff
または ErrImagePull
の場合、コンテナが使用するイメージをイメージ レジストリから読み込めないことを示します。
この問題は、 Google Cloud コンソールまたは kubectl
コマンドライン ツールを使用して確認できます。
コンソール
次の手順を行います。
Google Cloud コンソールで、[ワークロード] ページに移動します。
調査するワークロードを選択します。[概要] タブにワークロードのステータスが表示されます。
[マネージド Pod] セクションで、問題のある Pod をクリックします。
Pod のメニューで、[イベント] タブをクリックします。
kubectl
Pod のコンテナ イメージに関する詳細情報を表示するには、次のコマンドを実行します。
kubectl describe pod POD_NAME
問題: イメージが見つからない
イメージが見つからない場合は、次の手順を完了します。
- イメージの名前が正しいことを確認します。
- イメージのタグが正しいことを確認します(
:latest
またはタグなしを試して最新のイメージを pull します)。 - イメージにレジストリ フルパスがある場合は、使用している Docker レジストリにそのパスが存在することを確認します。イメージ名のみを指定した場合は、Docker Hub レジストリを確認してください。
GKE Standard クラスタで、Docker イメージを手動で pull してみます。
SSH でノードに接続します。
たとえば、SSH を使用して VM に接続するには、次のコマンドを実行します。
gcloud compute ssh VM_NAME --zone=ZONE_NAME
次のように置き換えます。
VM_NAME
: VM の名前。ZONE_NAME
: Compute Engine ゾーン。
/home/[USER]/.docker/config.json
に構成ファイルを生成します。docker-credential-gcr configure-docker
/home/[USER]/.docker/config.json
の構成ファイルのcredHelpers
フィールドにイメージのレジストリが含まれていることを確認します。たとえば、次のファイルには、asia.gcr.io
、eu.gcr.io
、gcr.io
、marketplace.gcr.io
、us.gcr.io
でホストされているイメージの認証情報が含まれています。{ "auths": {}, "credHelpers": { "asia.gcr.io": "gcr", "eu.gcr.io": "gcr", "gcr.io": "gcr", "marketplace.gcr.io": "gcr", "us.gcr.io": "gcr" } }
イメージを pull してみます。
docker pull IMAGE_NAME
イメージを手動で pull すると機能する場合は、Pod で
ImagePullSecrets
を指定する必要があります。Pod がイメージ pull Secret を参照できるのは、それぞれの Namespace 内だけです。このため、このプロセスを Namespace ごとに 1 回行う必要があります。
エラー: Permission denied
「permission denied」または「no pull access」というエラーが発生した場合は、ログインしていることと、イメージへのアクセス権があることを確認してください。イメージをホストするレジストリに応じて、次のいずれかの方法を試してください。
Artifact Registry
イメージが Artifact Registry にある場合、ノードプールのサービス アカウントには、イメージを含むリポジトリへの読み取りアクセス権が必要です。
サービス アカウントに artifactregistry.reader
ロールを付与します。
gcloud artifacts repositories add-iam-policy-binding REPOSITORY_NAME \
--location=REPOSITORY_LOCATION \
--member=serviceAccount:SERVICE_ACCOUNT_EMAIL \
--role="roles/artifactregistry.reader"
次のように置き換えます。
REPOSITORY_NAME
: Artifact Registry リポジトリの名前。REPOSITORY_LOCATION
: Artifact Registry リポジトリのリージョン。SERVICE_ACCOUNT_EMAIL
: ノードプールに関連付けられた IAM サービス アカウントのメールアドレス。
Container Registry
イメージが Container Registry にある場合、ノードプールのサービス アカウントには、イメージを含む Cloud Storage バケットに対する読み取りアクセス権が必要です。
サービス アカウントに roles/storage.objectViewer
ロールを付与して、バケットから読み取れるようにします。
gcloud storage buckets add-iam-policy-binding gs://BUCKET_NAME \
--member=serviceAccount:SERVICE_ACCOUNT_EMAIL \
--role=roles/storage.objectViewer
次のように置き換えます。
SERVICE_ACCOUNT_EMAIL
: ノードプールに関連付けられたサービス アカウントのメールアドレス。gcloud iam service-accounts list
を使用すると、プロジェクトのサービス アカウントを一覧取得できます。BUCKET_NAME
: イメージを含む Cloud Storage バケットの名前。gcloud storage ls
を使用すると、プロジェクト内のバケットを一覧取得できます。
レジストリ管理者が、Container Registry ではなく gcr.io
ドメインのイメージを保存するように Artifact Registry で gcr.io リポジトリを設定している場合は、Container Registry ではなく、Artifact Registry に対する読み取りアクセス権をユーザーに付与する必要があります。
非公開レジストリ
イメージが非公開レジストリにある場合、イメージにアクセスするための鍵が必要になることがあります。詳細については、Kubernetes ドキュメントの非公開レジストリの使用をご覧ください。
エラー 401 Unauthorized: Cannot pull images from private container registry repository
非公開の Container Registry リポジトリからイメージを pull すると、次のようなエラーが発生する可能性があります。
gcr.io/PROJECT_ID/IMAGE:TAG: rpc error: code = Unknown desc = failed to pull and
unpack image gcr.io/PROJECT_ID/IMAGE:TAG: failed to resolve reference
gcr.io/PROJECT_ID/IMAGE]:TAG: unexpected status code [manifests 1.0]: 401 Unauthorized
Warning Failed 3m39s (x4 over 5m12s) kubelet Error: ErrImagePull
Warning Failed 3m9s (x6 over 5m12s) kubelet Error: ImagePullBackOff
Normal BackOff 2s (x18 over 5m12s) kubelet Back-off pulling image
エラーを解決するには、次の操作を行います。
Pod を実行しているノードを特定します。
kubectl describe pod POD_NAME | grep "Node:"
前の手順で特定したノードにストレージ スコープがあることを確認します。
gcloud compute instances describe NODE_NAME \ --zone=COMPUTE_ZONE --format="flattened(serviceAccounts[].scopes)"
ノードのアクセス スコープには、次のいずれかのスコープが含まれている必要があります。
serviceAccounts[0].scopes[0]: https://www.googleapis.com/auth/devstorage.read_only serviceAccounts[0].scopes[0]: https://www.googleapis.com/auth/cloud-platform
これらのスコープのいずれかがノードに含まれていない場合は、ノードプールを再作成します。
ノードが属するノードプールを十分なスコープで再作成します。既存のノードは変更できません。正しいスコープでノードを再作成する必要があります。
推奨:
gke-default
スコープで新しいノードプールを作成します。gcloud container node-pools create NODE_POOL_NAME \ --cluster=CLUSTER_NAME \ --zone=COMPUTE_ZONE \ --scopes="gke-default"
ストレージ スコープのみを持つ新しいノードプールを作成します。
gcloud container node-pools create NODE_POOL_NAME \ --cluster=CLUSTER_NAME \ --zone=COMPUTE_ZONE \ --scopes="https://www.googleapis.com/auth/devstorage.read_only"
エラー: Pod unschedulable
ステータスが PodUnschedulable
の場合、リソースが不足しているか、なんらかの構成エラーのために Pod をスケジュールできないことを示します。
コントロール プレーンの指標を構成している場合は、スケジューラの指標と API サーバーの指標でエラーの詳細を確認できます。
スケジュール不可の Pod のインタラクティブ ハンドブックを使用する
Google Cloud コンソールのインタラクティブ ハンドブックを使用して、PodUnschedulable
エラーをトラブルシューティングできます。
スケジュール不可の Pod のインタラクティブ ハンドブックに移動します。
[クラスタ] プルダウン リストで、トラブルシューティングするクラスタを選択します。クラスタが見つからない場合は、
(フィルタ)フィールドにクラスタの名前を入力します。[Namespace] プルダウン リストで、トラブルシューティングする Namespace を選択します。Namespace が見つからない場合は、
(フィルタ)フィールドに Namespace を入力します。原因を特定するには、ハンドブックの各セクションを確認します。
- CPU とメモリの調査
- ノードあたりの最大 Pod 数の調査
- オートスケーラーの動作の調査
- その他の障害モードの調査
- 変更イベントの相関
省略可: 今後
PodUnschedulable
エラーが発生した場合に通知を受け取るには、[今後の対応のヒント] セクションで [アラートを作成する] を選択します。
エラー: Insufficient resources
CPU、メモリ、またはその他のリソースが不足していることを示すエラーが発生する場合があります。たとえば、No nodes are available that match all of the predicates:
Insufficient cpu (2)
は、2 つのノードで、Pod のリクエストに対して十分な CPU がないことを示します。
Pod のリソース リクエストが有効なノードプールの単一ノードの上限を超えた場合、GKE は Pod をスケジュールしません。また、新しいノードを追加するためのスケールアップもトリガーしません。GKE が Pod をスケジュールするには、Pod 用にリクエストするリソースを減らすか、十分なリソースを持つ新しいノードプールを作成する必要があります。
また、ノードの自動プロビジョニングを有効にして、スケジュールされていない Pod が実行可能なノードを含むノードプールを自動的に作成することもできます。
デフォルトの CPU リクエストは 100m、または CPU の 10%(あるいは 1 コア)です。リクエストするリソースの数を変更するには、spec: containers: resources: requests
の Pod 仕様に値を指定します。
エラー: MatchNodeSelector
MatchNodeSelector
は、Pod のラベルセレクタに一致するノードがないことを示します。
これを確認するには、Pod 仕様の nodeSelector
フィールド(spec: nodeSelector
の下)に指定されているラベルを確認します。
クラスタ内のノードがどのようにラベルされているか確認するには、次のコマンドを実行します。
kubectl get nodes --show-labels
ノードにラベルを付けるには、次のコマンドを実行します。
kubectl label nodes NODE_NAME LABEL_KEY=LABEL_VALUE
次のように置き換えます。
NODE_NAME
: ラベルを追加するノード。LABEL_KEY
: ラベルのキー。LABEL_VALUE
: ラベルの値。
詳細については、Kubernetes のドキュメントでノードに Pod を割り当てるをご覧ください。
エラー: PodToleratesNodeTaints
PodToleratesNodeTaints
は、Pod に既存の node taint に対応する toleration がないため、Pod をノードにスケジュールできないことを示します。
これが該当することを確認するには、次のコマンドを実行します。
kubectl describe nodes NODE_NAME
出力で、Taints
フィールドを確認すると、Key-Value のペアとスケジューリングの結果が一覧表示されています。
リストされた結果が NoSchedule
の場合、そのノードは一致する容認がなければ、Pod をスケジュールできません。
この問題を解決する方法の 1 つは、taint を削除することです。たとえば、NoSchedule taint を削除するには、次のコマンドを実行します。
kubectl taint nodes NODE_NAME key:NoSchedule-
エラー: PodFitsHostPorts
PodFitsHostPorts
エラーは、ノードがすでに占有されているポートを使用しようとしていることを意味します。
この問題を解決するには、Kubernetes のベスト プラクティスに沿って、hostPort
ではなく NodePort
を使用することを検討してください。
hostPort
を使用する必要がある場合は、Pod のマニフェストを調べて、同じノード上のすべての Pod に hostPort
に一意の値が定義されていることを確認します。
エラー: Does not have minimum availability
ノードに十分なリソースがあるのに Does not have minimum availability
というメッセージが表示される場合は、Pod のステータスを確認します。ステータスが SchedulingDisabled
または Cordoned
の場合、ノードは新しい Pod をスケジュールできません。ノードのステータスを確認するには、 Google Cloud コンソールまたは kubectl
コマンドライン ツールを使用します。
コンソール
次の手順を行います。
Google Cloud コンソールで、[Google Kubernetes Engine] ページに移動します。
調査するクラスタを選択します。[ノード] タブに、ノードとそのステータスが表示されます。
ノードでスケジューリングを可能にするには、次の操作を行います。
リストで、調査するノードをクリックします。
[ノードの詳細] セクションで、[閉鎖解除] をクリックします。
kubectl
ノードのステータスを取得するには、次のコマンドを実行します。
kubectl get nodes
ノードでスケジューリングを可能にするには、次のコマンドを実行します。
kubectl uncordon NODE_NAME
エラー: Maximum Pods per node limit reached
クラスタ内のすべてのノードがノードあたりの最大 Pod 数の上限に達すると、Pod はスケジュール不可の状態で停止します。Pod の [イベント] タブに、Too many pods
というフレーズを含むメッセージが表示されます。
このエラーを解決するには、次の操作を行います。
Google Cloud コンソールで、GKE クラスタの詳細に移動し、[ノード] タブで
Maximum pods per node
構成を確認します。ノードのリストを取得します。
kubectl get nodes
ノードごとに、そのノードで実行されている Pod の数を確認します。
kubectl get pods -o wide | grep NODE_NAME | wc -l
上限に達している場合は、新しいノードプールを追加するか、既存のノードプールにノードを追加します。
問題: クラスタ オートスケーラーが有効な状態でノードプールの最大サイズに達した
ノードプールがクラスタ オートスケーラーの構成に従って最大サイズに達した場合、GKE は、このノードプールでスケジュールされている Pod のスケールアップをトリガーしません。このノードプールで Pod をスケジュールする場合は、クラスタ オートスケーラーの構成を変更します。
問題: クラスタ オートスケーラーが無効な状態でノードプールの最大サイズに達した
クラスタ オートスケーラーが無効になっている状態でノードプールが最大ノード数に達した場合、GKE はノードプールで Pod をスケジュールできません。ノードプールのサイズを増やすか、GKE でクラスタ オートスケーラーを有効にして、クラスタのサイズを自動的に変更します。
エラー: Unbound PersistentVolumeClaims
Unbound PersistentVolumeClaims
は、Pod がバインドされていない PersistentVolumeClaim を参照していることを示します。このエラーは、PersistentVolume がプロビジョニングに失敗した場合に発生することがあります。プロビジョニングが失敗したことを確認するには、PersistentVolumeClaim のイベントを取得して失敗の有無を調べます。
イベントを取得するには、次のコマンドを実行します。
kubectl describe pvc STATEFULSET_NAME-PVC_NAME-0
次のように置き換えます。
STATEFULSET_NAME
: StatefulSet オブジェクトの名前。PVC_NAME
: PersistentVolumeClaim オブジェクトの名前。
PersistentVolume および PersistentVolumeClaim とのバインディングを手動で事前プロビジョニングする際に構成エラーがあった場合にも、このエラーが発生することがあります。
このエラーを解決するには、ボリュームの事前プロビジョニングをもう一度試します。
エラー: Insufficient quota
GKE がクラスタをスケールアップするのに十分な Compute Engine 割り当てがプロジェクトにあることを確認します。GKE が Pod をスケジュールするためにクラスタにノードを追加しようとしたときに、スケールアップがプロジェクトの使用可能な割り当てを超えると、scale.up.error.quota.exceeded
エラー メッセージが表示されます。
詳細については、ScaleUp エラーをご覧ください。
問題: 非推奨の API
クラスタのマイナー バージョンと一緒に削除される非推奨の API を使用していないことを確認します。詳細については、GKE のサポートの終了をご覧ください。
エラー: リクエストされた Pod ポートに空きポートがない
次のようなエラーが表示された場合は、同じノードに複数の Pod があり、hostPort
フィールドに同じ値が定義されている可能性があります。
0/1 nodes are available: 1 node(s) didn't have free ports for the requested pod ports. preemption: 0/1 nodes are available: 1 No preemption victims found for incoming pod.
Pod を hostPort
にバインドすると、GKE が Pod をスケジュールできる場所が制限されます。これは、各 hostIP
、hostPort
、protocol
の組み合わせが一意である必要があるためです。
この問題を解決するには、Kubernetes のベスト プラクティスに沿って、hostPort
ではなく NodePort
を使用することを検討してください。
hostPort
を使用する必要がある場合は、Pod のマニフェストを調べて、同じノード上のすべての Pod に hostPort
に一意の値が定義されていることを確認します。
次のステップ
さらにサポートが必要な場合は、Cloud カスタマーケアにお問い合わせください。