デプロイされたワークロードに関する問題のトラブルシューティング


このページでは、Google Kubernetes Engine(GKE)でデプロイされたワークロードのエラーを解決する方法について説明します。

アプリケーションのトラブルシューティングに関する一般的なアドバイスについては、Kubernetes のドキュメントでアプリケーションのトラブルシューティングをご覧ください。

すべてのエラー: Pod のステータスを確認する

ワークロードの Pod に問題がある場合、Kubernetes は Pod のステータスをエラー メッセージとともに更新します。これらのエラーを確認するには、Google Cloud コンソールまたは kubectl コマンドライン ツールを使用して Pod のステータスを確認します。

コンソール

次の操作を行います。

  1. Google Cloud コンソールの [ワークロード] ページに移動します。

    [ワークロード] に移動

  2. 調査するワークロードを選択します。[概要] タブにワークロードのステータスが表示されます。

  3. [マネージド 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 ステータスの原因のトラブルシューティングを開始します。

  1. クラッシュループしている Pod のインタラクティブ ハンドブックに移動します。

    ハンドブックに移動

  2. [クラスタ] プルダウン リストで、トラブルシューティングするクラスタを選択します。クラスタが見つからない場合は、フィルタ)フィールドにクラスタの名前を入力します。

  3. [Namespace] プルダウン リストで、トラブルシューティングする Namespace を選択します。Namespace が見つからない場合は、フィルタ)フィールドに Namespace を入力します。

  4. 各セクションを確認して、原因を特定します。

    1. アプリケーション エラーの特定
    2. メモリ不足問題の調査
    3. ノードの中断を調査する
    4. livenessProbe 失敗の調査
    5. 変更イベントの相関
  5. 省略可: 今後 CrashLoopBackOff エラーが発生した場合に通知を受け取るには、[今後の対応のヒント] セクションで [アラートを作成する] を選択します。

ログを検査する

コンテナはさまざまな理由でクラッシュすることがあり、Pod のログを調べると根本原因のトラブルシューティングに役立ちます。

ログを確認するには、Google Cloud コンソールまたは kubectl コマンドライン ツールを使用します。

コンソール

次の操作を行います。

  1. Google Cloud コンソールの [ワークロード] ページに移動します。

    [ワークロード] に移動

  2. 調査するワークロードを選択します。[概要] タブにワークロードのステータスが表示されます。

  3. [マネージド Pod] セクションで、問題のある Pod をクリックします。

  4. Pod のメニューで、[ログ] タブをクリックします。

kubectl

  1. クラスタで実行されているすべての Pod を表示します。

    kubectl get pods
    
  2. 上記のコマンドの出力で、Status 列に CrashLoopBackOff エラーがある Pod を探します。

  3. Pod のログを取得します。

    kubectl logs POD_NAME
    

    POD_NAME は、問題のある Pod の名前に置き換えます。

    また、-p フラグを使用して、Pod の以前のコンテナ インスタンス(存在する場合)のログを取得することもできます。

クラッシュしたコンテナの終了コードを確認する

コンテナがクラッシュした理由を詳しく把握するには、終了コードを確認します。

  1. Pod の説明を取得します。

    kubectl describe pod POD_NAME
    

    POD_NAME は、問題のある Pod の名前に置き換えます。

  2. 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 コマンドライン ツールで確認できます。

コンソール

次の操作を行います。

  1. Google Cloud コンソールの [ワークロード] ページに移動します。

    [ワークロード] に移動

  2. 調査するワークロードを選択します。[概要] タブにワークロードのステータスが表示されます。

  3. [マネージド Pod] セクションで、問題のある Pod をクリックします。

  4. Pod のメニューで、[イベント] タブをクリックします。

kubectl

Pod のコンテナ イメージに関する詳細情報を表示するには、次のコマンドを実行します。

kubectl describe pod POD_NAME

問題: イメージが見つからない

イメージが見つからない場合は、次の手順を完了します。

  1. イメージの名前が正しいことを確認します。
  2. イメージのタグが正しいことを確認します(:latest またはタグなしを試して最新のイメージを pull します)。
  3. イメージにレジストリ フルパスがある場合は、使用している Docker レジストリにそのパスが存在することを確認します。イメージ名のみを指定した場合は、Docker Hub レジストリを確認してください。
  4. GKE Standard クラスタで、Docker イメージを手動で pull してみます。

    1. SSH でノードに接続します。

      たとえば、SSH を使用して VM に接続するには、次のコマンドを実行します。

      gcloud compute ssh VM_NAME --zone=ZONE_NAME
      

      次のように置き換えます。

    2. /home/[USER]/.docker/config.json に構成ファイルを生成します。

      docker-credential-gcr configure-docker
      

      /home/[USER]/.docker/config.json の構成ファイルの credHelpers フィールドにイメージのレジストリが含まれていることを確認します。たとえば、次のファイルには、asia.gcr.ioeu.gcr.iogcr.iomarketplace.gcr.ious.gcr.io でホストされているイメージの認証情報が含まれています。

      {
      "auths": {},
      "credHelpers": {
        "asia.gcr.io": "gcr",
        "eu.gcr.io": "gcr",
        "gcr.io": "gcr",
        "marketplace.gcr.io": "gcr",
        "us.gcr.io": "gcr"
      }
      }
      
    3. イメージを 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

エラーを解決するには、次の操作を行います。

  1. Pod を実行しているノードを特定します。

    kubectl describe pod POD_NAME | grep "Node:"
    
  2. 前の手順で特定したノードにストレージ スコープがあることを確認します。

    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
    

    これらのスコープのいずれかがノードに含まれていない場合は、ノードプールを再作成します。

  3. ノードが属するノードプールを十分なスコープで再作成します。既存のノードは変更できません。正しいスコープでノードを再作成する必要があります。

    • 推奨: 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 エラーをトラブルシューティングできます。

  1. スケジュール不可の Pod のインタラクティブ ハンドブックに移動します。

    ハンドブックに移動

  2. [クラスタ] プルダウン リストで、トラブルシューティングするクラスタを選択します。クラスタが見つからない場合は、フィルタ)フィールドにクラスタの名前を入力します。

  3. [Namespace] プルダウン リストで、トラブルシューティングする Namespace を選択します。Namespace が見つからない場合は、フィルタ)フィールドに Namespace を入力します。

  4. 原因を特定するには、ハンドブックの各セクションを確認します。

    1. CPU とメモリの調査
    2. ノードあたりの最大 Pod 数の調査
    3. オートスケーラーの動作の調査
    4. その他の障害モードの調査
    5. 変更イベントの相関
  5. 省略可: 今後 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 は、ノードが利用しようとしているポートがすでに使用中であることを示します。

この問題を解決するには、spec: containers: ports: hostPort の下にある Pod 仕様の hostPort の値を確認します。この値を別のポートに変更することが必要になる場合があります。

エラー: Does not have minimum availability

ノードに十分なリソースがあるのに Does not have minimum availability というメッセージが表示される場合は、Pod のステータスを確認します。ステータスが SchedulingDisabled または Cordoned の場合、ノードは新しい Pod をスケジュールできません。ノードのステータスを確認するには、Google Cloud コンソールまたは kubectl コマンドライン ツールを使用します。

コンソール

次の操作を行います。

  1. Google Cloud コンソールで Google Kubernetes Engine のページに移動します。

    Google Kubernetes Engine に移動

  2. 調査するクラスタを選択します。[ノード] タブに、ノードとそのステータスが表示されます。

ノードでスケジューリングを可能にするには、次の操作を行います。

  1. リストで、調査するノードをクリックします。

  2. [ノードの詳細] セクションで、[閉鎖解除] をクリックします。

kubectl

ノードのステータスを取得するには、次のコマンドを実行します。

kubectl get nodes

ノードでスケジューリングを可能にするには、次のコマンドを実行します。

kubectl uncordon NODE_NAME

エラー: Maximum Pods per node limit reached

クラスタ内のすべてのノードがノードあたりの最大 Pod 数の上限に達すると、Pod はスケジュール不可の状態で停止します。Pod の [イベント] タブに、Too many pods というフレーズを含むメッセージが表示されます。

このエラーを解決するには、次の操作を行います。

  1. Google Cloud コンソールで GKE クラスタの詳細に移動し、[ノード] タブで Maximum pods per node 構成を確認します。

  2. ノードのリストを取得します。

    kubectl get nodes
    
  3. ノードごとに、そのノードで実行されている Pod の数を確認します。

    kubectl get pods -o wide | grep NODE_NAME | wc -l
    
  4. 上限に達している場合は、新しいノードプールを追加するか、既存のノードプールにノードを追加します。

問題: クラスタ オートスケーラーが有効な状態でノードプールの最大サイズに達した

ノードプールがクラスタ オートスケーラーの構成に従って最大サイズに達した場合、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 のサポートの終了をご覧ください。

次のステップ

さらにサポートが必要な場合は、Cloud カスタマーケアにお問い合わせください。