トラブルシューティング

Google Kubernetes Engine の使用中に問題が発生した場合に役立つトラブルシューティング手順について説明します。

Kubernetes リソースのデバッグ

クラスタに関する問題が発生している場合は、Kubernetes のドキュメントでクラスタのトラブルシューティングをご覧ください。

アプリケーション、ポッド、またはコントローラ オブジェクトに問題がある場合は、アプリケーションのトラブルシューティングをご覧ください。

kubectl コマンドが見つかりません

最初に、次のコマンドを実行して kubectl バイナリをインストールします。

sudo gcloud components update kubectl

$PATH 環境変数を変更するかどうかを確認するメッセージが表示されたら、「yes」を選択します。この変数を変更すると、ファイルの完全なパスを入力せずに kubectl コマンドを使用できます。

または、次の行を ~/.bashrc(macOS では ~/.bash_profile、または使用しているシェルが環境変数を格納する場所)に追加します。

export PATH=$PATH:/usr/local/share/google/google-cloud-sdk/bin/

最後に、次のコマンドを実行して、更新された .bashrc(または .bash_profile)ファイルを読み込みます。

source ~/.bashrc

kubectl コマンドを実行すると「connection refused」(接続は拒否されました)というエラーが表示されます

次のコマンドを使用してクラスタのコンテキストを設定します。

gcloud container clusters get-credentials [CLUSTER_NAME]

CLUSTER_NAME に何を入力すればよいかわからない場合は、次のコマンドを使用してクラスタを一覧表示します。

gcloud container clusters list

kubectl コマンドを実行すると「API バージョンのネゴシエーションができませんでした」というエラーが表示されます

kubectl に認証情報があることを確認します。

gcloud auth application-default login

kubectllogsattachexecport-forward コマンドがハングします

これらのコマンドは、クラスタのマスターがクラスタ内のノードと通信できることを前提にして動作します。ただし、マスターはクラスタのノードと同じ Compute Engine ネットワーク内にはないので、SSH トンネルを利用してセキュアな通信を実現しています。

GKE は SSH 公開鍵ファイルを Compute Engine プロジェクトのメタデータに保存します。Google 提供のイメージを使用するすべての Compute Engine VM はプロジェクトの共通メタデータとインスタンスのメタデータを定期的にチェックし、承認済みユーザーの VM のリストに追加する SSH 認証鍵がないかどうかを確認します。また、GKE はマスターの IP アドレスからクラスタ内の各ノードへの SSH アクセスを許可するファイアウォール ルールを Compute Engine ネットワークに追加します。

上記の kubectl コマンドのいずれかが動作しない場合、マスターがノードへの SSH トンネルを開くことができない可能性があります。次のような問題がないかどうかを確認してください。

  1. クラスタにノードが存在しない。

    クラスタ内のノードの数を減らして 0 にした場合、SSH トンネルは動作しません。

    この問題を修正するには、クラスタのサイズを変更してノードを 1 つ以上配置します。

  2. クラスタ内のポッドが終了状態のまま復帰しないため、存在しなくなったノードをクラスタから削除できない。

    この問題は Kubernetes バージョン 1.1 にのみ影響しますが、クラスタのサイズの変更を繰り返した場合に発生する可能性があります。

    この問題を修正するには、終了状態のまま数分以上経過しているポッドを削除します。これによって古いノードはマスターの API から削除され、新しいノードに置き換えられます。

  3. ネットワークのファイアウォール ルールでマスターへの SSH アクセスを許可していない。

    すべての Compute Engine ネットワークは「default-allow-ssh」というファイアウォール ルールを使用して作成されます。このルールでは有効な秘密鍵を持つすべての IP アドレスからの SSH アクセスが許可されます。また、GKE はクラスタごとに gke-<cluster_name>-<random-characters>-ssh 形式の SSH ルールも挿入します。このルールでは、クラスタのマスター IP からクラスタのノードへの SSH アクセスが個別に許可されます。どちらのルールも存在しない場合、マスターは SSH トンネルを開くことができません。

    この問題を修正するには、マスターの IP アドレスからすべてのクラスタのノード上にあるタグの付いた VM へのアクセスを許可するファイアウォール ルールを再度追加します。

  4. プロジェクトの「ssh-keys」用の共通メタデータ エントリがいっぱいになっている。

    プロジェクトの「ssh-keys」というメタデータ エントリのサイズが 32 KiB の上限に近づいていると、GKE は SSH トンネルを開くための独自の SSH 認証鍵を追加できません。プロジェクトのメタデータを確認するには gcloud compute project-info describe [--project=PROJECT] を実行し、ssh-keys のリストの長さを調べます。

    この問題を修正するには、不要になった SSH 認証鍵を削除します。

  5. クラスタ内の VM でメタデータ フィールドに認証鍵「ssh-keys」を設定している。

    VM のノード エージェントではプロジェクト全体の SSH 認証鍵よりもインスタンスごとの ssh-keys が優先されるため、クラスタのノードで SSH 認証鍵を個別に設定している場合、ノードはプロジェクトのメタデータ内にあるマスターの SSH 認証鍵を無視します。確認するには、gcloud compute instances describe <VM-name> を実行し、メタデータに「ssh-keys」フィールドがあるかどうかを調べます。

    この問題を修正するには、インスタンスのメタデータからインスタンスごとの SSH 認証鍵を削除します。

これらの機能はクラスタの正常な動作に必須ではないことに注意してください。クラスタのネットワークを外部アクセスから完全に遮断した場合、これらのような機能が動作しなくなることに注意してください。

クラスタからの指標が Stackdriver に表示されません

プロジェクトで Stackdriver Monitoring APIStackdriver Logging API が有効になっていること、プロジェクトを Stackdriver で表示できることを確認します。

問題が解決しない場合は、次の原因が考えられます。

  1. クラスタでモニタリングを有効にしてあることを確認します。

    Developers Console や gcloud コマンドライン ツールを使用して作成したクラスタでは、デフォルトでモニタリングが有効になりますが、これを確認するには、次のコマンドを実行するか、Developers Console でクラスタをクリックしてその詳細を表示します。

    gcloud container clusters describe cluster-name

    gcloud コマンドライン ツールの出力では "monitoringService" が "monitoring.googleapis.com" と表示され、Developers Console では Cloud Monitoring が有効になっているはずです。

    モニタリングが有効になっていない場合は、次のコマンドを実行して有効にします。

    gcloud container clusters update cluster-name --monitoring-service=monitoring.googleapis.com
  2. クラスタを作成してから、またはモニタリングを有効にしてからどれくらいの時間が経過していますか?

    新しいクラスタの指標が Stackdriver Monitoring に表示されるまでに最長で 1 時間かかります。

  3. heapster がクラスタの "kube-system" 名前空間で実行されていますか?

    クラスタのリソースが不足しているため、ポッドがワークロードのスケジュールに失敗している可能性があります。kubectl get pods --namespace=kube-system を呼び出し、heapster という名前のポッドを調べて、heapster が実行されているかどうかを確認してください。

  4. クラスタのマスターはノードと通信できますか?

    Stackdriver Monitoring はこの通信に依存します。kubectl logs [POD-NAME] を実行すれば、通信できるかどうかを確認できます。このコマンドがエラーを返す場合、SSH トンネルが問題の原因である可能性があります。こちらのセクションをご覧ください。

Stackdriver Logging エージェントに関する問題が発生している場合は、エージェントのトラブルシューティング ドキュメントをご覧ください。

詳細については、Stackdriver のドキュメントをご覧ください。

エラー 404: gcloud container コマンドを呼び出したときにリソースが「見つかりませんでした」

gcloud コマンドライン ツールに対して再度認証を実行します。

gcloud auth login

エラー 400/403: アカウントに編集権限がありません

Compute Engine または Kubernetes Engine のサービス アカウント(あるいはその両方)が削除または編集されています。

Compute Engine または Kubernetes Engine API を有効にすると、サービス アカウントが作成され、プロジェクトにおける編集権限が与えられます。いずれかの時点で権限を編集するか、アカウントを完全に削除するか、あるいは API を無効にした場合、クラスタの作成とすべての管理機能が失敗します。

Google Kubernetes Engine サービス アカウントの名前は次のとおりです。

service-[PROJECT_NUMBER]@container-engine-robot.iam.gserviceaccount.com

[PROJECT_NUMBER]プロジェクト番号です。

この問題を解決するには、Kubernetes Engine API を再度有効にする必要があります。これにより、サービス アカウントと権限が正しく復元されます。

  1. [API とサービス] ページにアクセスします。
  2. プロジェクトを選択します。
  3. [API とサービスの有効化] をクリックします。
  4. GKE を検索して、検索結果から API を選択します。
  5. [有効にする] をクリックします。API を以前に有効にしている場合は、まずそれを無効にしてから再度有効にする必要があります。API と関連サービスが有効になるには、数分かかることがあります。

あるいは、gcloud コマンドライン ツールを使用します。

gcloud services enable container.googleapis.com

1.8.x 以前の自動ファイアウォール ルールを 1.9.x 以降で複製する

クラスタで Kubernetes バージョン 1.9.x を実行している場合、自動ファイアウォール ルールが変更されたため、GKE クラスタ内のワークロードが、同じネットワーク上にあるがそのクラスタの外にある他の Compute Engine VM と通信を開始できなくなりました。

次の手順を行って、1.8.x 以前のクラスタの自動ファイアウォール ルールの動作を再現できます。

最初に、クラスタのネットワークを見つけます。

gcloud container clusters describe [CLUSTER_NAME] --format=get"(network)"

次に、コンテナに使用する、クラスタの IPv4 CIDR を取得します。

gcloud container clusters describe [CLUSTER_NAME] --format=get"(clusterIpv4Cidr)"

最後に、ネットワークのファイアウォール ルールを作成します。その CIDR をソース範囲とし、すべてのプロトコルを許可します。

gcloud compute firewall-rules create "[CLUSTER_NAME]-to-all-vms-on-network" --network="[NETWORK]" --source-ranges="[CLUSTER_IPV4_CIDR]" --allow=tcp,udp,icmp,esp,ah,sctp

GCP プロジェクトに対するデフォルトのサービス アカウントを復元する

GKE のデフォルトのサービス アカウント、container-engine-robot が、プロジェクトから誤ってバインド解除されることがあります。GKE サービス エージェントは、サービス アカウントにクラスタ リソースを管理する権限を与える IAM 役割です。この役割バインディングをサービス アカウントから削除すると、デフォルト サービス アカウントはプロジェクトからバインド解除され、アプリケーションのデプロイや他のクラスタ操作の実行をユーザーができなくなる可能性があります。

サービス アカウントがプロジェクトから削除されているか確認するには、gcloud projects get-iam-policy [PROJECT_ID] を実行するか、または Google Cloud Platform Console の [IAM と管理] メニューにアクセスします。そのコマンドまたはダッシュボードでサービス アカウントの中に container-engine-robot が表示されない場合、サービス アカウントはバインド解除されています。

GKE サービス エージェントの役割バインディングを削除した場合は、次のコマンドを実行して役割バインディングを復元します。

PROJECT_ID=$(gcloud config get-value project)
PROJECT_NUMBER=$(gcloud projects describe "${PROJECT_ID}" --format "value(projectNumber)")
gcloud projects add-iam-policy-binding "${PROJECT_ID}" \
  --member "serviceAccount:service-${PROJECT_NUMBER}@container-engine-robot.iam.gserviceaccount.com" \
  --role roles/container.serviceAgent

役割バインディングが付与されたことを確認するには、次のコマンドを実行します。

gcloud projects get-iam-policy $PROJECT_ID

サービス アカウント名が container.serviceAgent 役割とともに表示される場合、役割バインディングは付与されています。例:

- members:
  - serviceAccount:service-1234567890@container-engine-robot.iam.gserviceaccount.com
  role: roles/container.serviceAgent

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

ワークロードのポッドに問題がある場合、GKE がエラーを返します。ポッドのステータスを調べるには、kubectl コマンドライン ツールか Google Cloud Platform Console を使用します。

kubectl

クラスタで実行しているすべてのポッドを表示するには、次のコマンドを実行します。

kubectl get pods

出力:

NAME            READY   STATUS              RESTARTS    AGE
[POD_NAME]      0/1     CrashLoopBackOff    23          8d

特定のポッドに関する詳細情報を取得するには、次のコマンドを実行します。

kubectl describe pod [POD_NAME]

Console

次の手順を行います。

  1. GCP Console で GKE の [ワークロード] ダッシュボードに移動します。

    GKE の [ワークロード] ダッシュボードに移動

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

  3. [管理対象ポッド] セクションで、エラー ステータス メッセージをクリックします。

以下のセクションでは、ワークロードによって返される一般的なエラーとその解決方法について説明します。

CrashLoopBackOff

CrashLoopBackOff は、コンテナが再起動後に繰り返しクラッシュしていることを示します。コンテナはさまざまな理由でクラッシュすることがあり、ポッドのログを調べると根本原因のトラブルシューティングに役立ちます。

デフォルトでは、クラッシュしたコンテナは 5 分間までの指数的遅延で再起動します。この動作設定を変更するには、Deployment のポッド仕様の spec: restartPolicy の下の restartPolicy フィールドを設定します。このフィールドのデフォルト値は Always です。

kubectl コマンドライン ツールか GCP Console を使用して、ポッドのコンテナがクラッシュしている理由を調べることができます。

kubectl

クラスタで実行しているすべてのポッドを表示するには、次のコマンドを実行します。

kubectl get pods

CrashLoopBackOff エラーがあるポッドを探します。

ポッドのログを取得するには、次のコマンドを実行します。

kubectl logs [POD_NAME]

[POD_NAME] は問題のあるポッドの名前です。

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

Console

次の手順を行います。

  1. GCP Console で GKE の [ワークロード] ダッシュボードに移動します。

    GKE の [ワークロード] ダッシュボードに移動

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

  3. [管理対象ポッド] セクションで、問題のあるポッドをクリックします。

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

クラッシュしたコンテナの終了コードを調べる

終了コードは、kubectl describe pod [POD_NAME] の出力の containers: [CONTAINER_NAME]: last state: exit code フィールドにあります。

  • 終了コードが 1 の場合、コンテナがクラッシュした理由はアプリケーションがクラッシュしたからです。
  • 終了コードが 0 の場合は、アプリの実行時間を確認してください。コンテナは、アプリケーションのメインプロセスが終了したときに終了します。アプリの実行が非常に速く終了する場合、コンテナは再起動を続行している可能性があります。

実行中のコンテナに接続する

ポッドへのシェルを開きます。

kubectl exec -it [POD_NAME] -- /bin/bash

ポッド内にコンテナが複数ある場合は、-c [CONTAINER_NAME] を追加します。

これで、そのコンテナから bash コマンドを実行できます。ネットワークのテストや、アプリケーションで使用されているファイルやデータベースにアクセスできるかどうかを調べることができます。

ImagePullBackOff と ErrImagePull

ImagePullBackOffErrImagePull は、コンテナが使用するイメージをイメージ レジストリからロードできないことを示します。

この問題は、GCP Console または kubectl コマンドライン ツールを使用して確認できます。

kubectl

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

kubectl describe pod [POD_NAME]

Console

次の手順を行います。

  1. GCP Console で GKE の [ワークロード] ダッシュボードに移動します。

    GKE の [ワークロード] ダッシュボードに移動

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

  3. [管理対象ポッド] セクションで、問題のあるポッドをクリックします。

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

イメージが見つからない場合

イメージが見つからない場合:

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

    • ノードに SSH 接続します。
      たとえば、us-central1-a ゾーンの example-instance に SSH 接続するには、次のコマンドを実行します。

      gcloud compute ssh example-instance --zone us-central1-a
    • docker pull [IMAGE_NAME] を実行します。
      このオプションが機能すると、ポッドで ImagePullSecret の指定が必要になる場合があります。ポッドがイメージ pull シークレットを参照できるのはそれぞれの名前空間内だけであるため、このプロセスを名前空間ごとに 1 回行う必要があります。

「permission denied」または「no pull access」というエラーが発生した場合は、ログインしていることと、イメージへのアクセス権があることを確認してください。

非公開レジストリを使用している場合は、イメージを読み取るためのキーが必要な場合があります。

PodUnschedulable

PodUnschedulable は、リソースが不足しているかなんらかの構成エラーのためにポッドをスケジュールできないことを示します。

リソースの不足

CPU、メモリ、またはその他のリソースが不足していることを示すエラーが発生する場合があります。たとえば、「No nodes are available that match all of the predicates: Insufficient cpu (2)」は、2 つのノードで、ポッドのリクエストを満たせる十分な CPU がないことを示します。

デフォルトの CPU リクエストは 100m、または CPU の 10%(あるいは 1 コア)です。それよりも多くのリソース、あるいは少ないリソースをリクエストする場合は、ポッド仕様の spec: containers: resources: requests で値を指定します。

MatchNodeSelector

MatchNodeSelector は、ポッドのラベルセレクタに一致するノードがないことを示します。

これを確認するには、ポッド仕様の nodeSelector フィールド(spec: nodeSelector の下)に指定されているラベルを確認します。

クラスタ内のノードにどのようなラベルが付けられているかを確認するには、次のコマンドを実行します。

kubectl get nodes --show-labels

ノードにラベルを付けるには:

kubectl label nodes [NODE_NAME] [LABEL_KEY]=[LABEL_VALUE]

詳細については、ノードにポッドを割り当てるを参照してください。

PodToleratesNodeTaints

PodToleratesNodeTaints は、ノード taint を許容しているノードが現在ないため、ポッドをノードにスケジュールできないことを示します。

これが該当することを確認するには、次のコマンドを実行します。

kubectl describe nodes [NODE_NAME]

出力で、Taints フィールドを確認すると、Key-Value のペアとスケジューリングの結果が一覧表示されています。

リストされた結果が NoSchedule の場合、そのノードは、一致する容認がなければ、ポッドをスケジュールできません。

この問題を解決する方法の 1 つは、taint を削除することです。たとえば、NoSchedule taint を削除するには、次のコマンドを実行します。

kubectl taint nodes [NODE_NAME] key:NoSchedule-

PodFitsHostPorts

PodFitsHostPorts は、ノードが利用しようとしているポートがすでに使用中であることを示します。

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

Does not have minimum availability

ノードに十分なリソースがあるのに Does not have minimum availability というメッセージが表示される場合は、ポッドのステータスを確認します。ステータスが SchedulingDisabled または Cordoned の場合、ノードは新しいポッドをスケジュールできません。ノードのステータスを確認するには、次のようにします。

kubectl

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

kubectl get nodes

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

kubectl uncordon [NODE_NAME]

Console

次の手順を行います。

  1. GCP Console で GKE の [ワークロード] ダッシュボードに移動します。

    GKE の [クラスタ] ダッシュボードに移動

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

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

  1. リストで、目的のノードをクリックします。

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

接続に関する問題

ネットワークの概要で説明したように、トラブルシューティングを効果的に行うには、ポッドがネットワークの名前空間からノードのルート名前空間までどのように接続されているかを理解することが重要です。以下の説明では、特に明記しない限り、クラスタは Calico CNI ではなく GKE のネイティブ CNI を使用するものとします。つまり、ネットワーク ポリシーは適用されていません。

一部のノードのポッドが使用できない

一部のノードのポッドがネットワークに接続できない場合は、Linux ブリッジが起動していることを確認してください。

ip address show cbr0

停止している場合は、起動します。

sudo ip link set cbr0 up

ノードが、cbr0 に接続されたポッドの MAC アドレスを学習していることを確認します。

arp -an

一部のノードのポッドの接続状態が悪い

一部のノードのポッドの接続状態が悪い場合は、まず、ツールボックス コンテナで tcpdump を実行して、パケットが失われていないか確認します。

sudo toolbox bash

まだインストールしていない場合は、ツールボックスに tcpdump をインストールします。

apt install -y tcpdump

cbr0 に対して tcpdump を実行します。

tcpdump -ni cbr0 host [HOSTNAME] and port [PORT_NUMBER] and [tcp|udp|icmp]

大きなパケットがブリッジのダウンストリームでドロップされているように見える場合(たとえば、TCP handshake は完了しているが SSL hello は受信されていない)、Linux ブリッジの MTU が 1,460 以下に正しく設定されていることを確認します。

ip address show cbr0

オーバーレイを使用する場合は(Weave や Flannel など)、オーバーレイのカプセル化オーバーヘッドに対応するために、この MTU をさらに小さくする必要があります。

断続的に接続が失敗する

ポッドとの接続は iptables によって転送されます。フローは conntrack テーブルのエントリとしてトラッキングされ、ノードあたりのワークロードが多いと、conntrack テーブルが枯渇して失敗となることがあります。これは、ノードのシリアル コンソールに、たとえば次のように記録されます。

nf_conntrack: table full, dropping packet

断続的な失敗の原因が conntrack の枯渇であると判断できる場合は、クラスタのサイズを大きくする(つまり、ノードあたりのワークロード数とフロー数を減らす)か、conntrack テーブルの容量を増やす方法について GCP サポートにお問い合わせください。

コンテナが "bind:Address already in use" と報告される

アプリケーションがバインドしようとしているポートがすでに予約されているため、ポッド内のコンテナを起動できないことが、コンテナログで示されています。コンテナはクラッシュ ループしています。たとえば、Stackdriver Logging では次のように表示されます。

resource.type="container"
textPayload:"bind: Address already in use"
resource.labels.container_name="redis"

2018-10-16 07:06:47.000 CEST 16 Oct 05:06:47.533 # Creating Server TCP listening socket *:60250: bind: Address already in use
2018-10-16 07:07:35.000 CEST 16 Oct 05:07:35.753 # Creating Server TCP listening socket *:60250: bind: Address already in use

Docker がクラッシュすると、実行中のコンテナが処理されずに最新状態でなくなることがあります。プロセスはまだポッドに割り当てられたネットワーク名前空間で実行されており、そのポートをリッスンしています。Docker と kubelet は古いコンテナを認識せず、新しいプロセスで新しいコンテナを起動しようとします。しかし、ポートにバインドしようとすると、すでにポッドに関連付けられているネットワーク名前空間にポートが追加されるため、バインドできません。

この問題を診断するには、ポッドの UUID(フィールド .metadata.uuid)が必要です。

kubectl get pod -o custom-columns="name:.metadata.name,UUID:.metadata.uid" ubuntu-6948dd5657-4gsgg

name                      UUID
ubuntu-6948dd5657-4gsgg   db9ed086-edba-11e8-bdd6-42010a800164

ノードからの次のコマンドの出力も取得します。

  • docker ps -a
  • ps -eo pid,ppid,stat,wchan:20,netns,comm,args:50,cgroup --cumulative -H | grep [Pod UUID]

このポッドから実行されているプロセスを確認します。cgroup 名前空間の UUID にポッドの UUID が含まれるため、ps の出力でポッドの UUID を grep で検索します。引数にコンテナ ID が含まれる docker-containerd-shim プロセスも表示されるように、前の行も grep 検索に含めます。出力を見やすくするために、その他の cgroup 列は切り捨てます。

# ps -eo pid,ppid,stat,wchan:20,netns,comm,args:50,cgroup --cumulative -H | grep -B 1 db9ed086-edba-11e8-bdd6-42010a800164 | sed s/'blkio:.*'/''/
1283089     959 Sl   futex_wait_queue_me  4026531993       docker-co       docker-containerd-shim 276e173b0846e24b704d4 12:
1283107 1283089 Ss   sys_pause            4026532393         pause           /pause                                     12:
1283150     959 Sl   futex_wait_queue_me  4026531993       docker-co       docker-containerd-shim ab4c7762f5abf40951770 12:
1283169 1283150 Ss   do_wait              4026532393         sh              /bin/sh -c echo hello && sleep 6000000     12:
1283185 1283169 S    hrtimer_nanosleep    4026532393           sleep           sleep 6000000                            12:
1283244     959 Sl   futex_wait_queue_me  4026531993       docker-co       docker-containerd-shim 44e76e50e5ef4156fd5d3 12:
1283263 1283244 Ss   sigsuspend           4026532393         nginx           nginx: master process nginx -g daemon off; 12:
1283282 1283263 S    ep_poll              4026532393           nginx           nginx: worker process

このリストからコンテナ ID を確認でき、これは docker ps にも表示されます。

この例では、次のようになります。

  • docker-containerd-shim 276e173b0846e24b704d4 は pause を実行中
  • docker-containerd-shim ab4c7762f5abf40951770 は sh で sleep を実行中(sleep-ctr)
  • docker-containerd-shim 44e76e50e5ef4156fd5d3 は nginx を実行中(echoserver-ctr)

docker ps の出力で確認します。

# docker ps --no-trunc | egrep '276e173b0846e24b704d4|ab4c7762f5abf40951770|44e76e50e5ef4156fd5d3'
44e76e50e5ef4156fd5d383744fa6a5f14460582d0b16855177cbed89a3cbd1f   gcr.io/google_containers/echoserver@sha256:3e7b182372b398d97b747bbe6cb7595e5ffaaae9a62506c725656966d36643cc                   "nginx -g 'daemon off;'"                                                                                                                                                                                                                                                                                                                                                                     14 hours ago        Up 14 hours                             k8s_echoserver-cnt_ubuntu-6948dd5657-4gsgg_default_db9ed086-edba-11e8-bdd6-42010a800164_0
ab4c7762f5abf40951770d3e247fa2559a2d1f8c8834e5412bdcec7df37f8475   ubuntu@sha256:acd85db6e4b18aafa7fcde5480872909bd8e6d5fbd4e5e790ecc09acc06a8b78                                                "/bin/sh -c 'echo hello && sleep 6000000'"                                                                                                                                                                                                                                                                                                                                                   14 hours ago        Up 14 hours                             k8s_sleep-cnt_ubuntu-6948dd5657-4gsgg_default_db9ed086-edba-11e8-bdd6-42010a800164_0
276e173b0846e24b704d41cf4fbb950bfa5d0f59c304827349f4cf5091be3327   k8s.gcr.io/pause-amd64:3.1

通常は、ps で表示されるすべてのコンテナ ID が、docker ps で表示されます。表示されない ID がある場合、それは古くなったコンテナです。おそらく、使用中であると報告されている TCP ポートをリッスンしている docker-containerd-shim process の子プロセスが見つかります。

これを確認するには、コンテナのネットワーク名前空間で netstat を実行します。ポッドのコンテナ プロセスの pid を取得します(docker-containerd-shim ではありません)。

上記の例では、次のようになります。

  • 1283107 - pause
  • 1283169 - sh
  • 1283185 - sleep
  • 1283263 - nginx master
  • 1283282 - nginx worker
# nsenter -t 1283107 --net netstat -anp
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN      1283263/nginx: mast
Active UNIX domain sockets (servers and established)
Proto RefCnt Flags       Type       State         I-Node   PID/Program name     Path
unix  3      [ ]         STREAM     CONNECTED     3097406  1283263/nginx: mast
unix  3      [ ]         STREAM     CONNECTED     3097405  1283263/nginx: mast

gke-zonal-110-default-pool-fe00befa-n2hx ~ # nsenter -t 1283169 --net netstat -anp
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN      1283263/nginx: mast
Active UNIX domain sockets (servers and established)
Proto RefCnt Flags       Type       State         I-Node   PID/Program name     Path
unix  3      [ ]         STREAM     CONNECTED     3097406  1283263/nginx: mast
unix  3      [ ]         STREAM     CONNECTED     3097405  1283263/nginx: mast

ip netns を使用して netstat を実行することもできますが、Docker がリンクを行っていないため、プロセスのネットワーク名前空間を手動でリンクする必要があります。

# ln -s /proc/1283169/ns/net /var/run/netns/1283169
gke-zonal-110-default-pool-fe00befa-n2hx ~ # ip netns list
1283169 (id: 2)
gke-zonal-110-default-pool-fe00befa-n2hx ~ # ip netns exec 1283169 netstat -anp
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN      1283263/nginx: mast
Active UNIX domain sockets (servers and established)
Proto RefCnt Flags       Type       State         I-Node   PID/Program name     Path
unix  3      [ ]         STREAM     CONNECTED     3097406  1283263/nginx: mast
unix  3      [ ]         STREAM     CONNECTED     3097405  1283263/nginx: mast
gke-zonal-110-default-pool-fe00befa-n2hx ~ # rm /var/run/netns/1283169

緩和策:

短期的な緩和策としては、上記の説明に従って古くなったプロセスを識別し、kill [PID] を使用してこれらのプロセスを強制終了します。

長期的な緩和策としては、Docker がクラッシュした原因を識別し、修正します。考えられる原因は次のとおりです。

  • ゾンビプロセスが蓄積して、PID 名前空間が不足した
  • Docker のバグ
  • リソース不足 / OOM
このページは役立ちましたか?評価をお願いいたします。

フィードバックを送信...

Kubernetes Engine のドキュメント