これは、このセクションの複数ページの印刷可能なビューです。 印刷するには、ここをクリックしてください.

このページの通常のビューに戻る.

アプリケーションのトラブルシューティング

コンテナ化されたアプリケーションの一般的な問題をデバッグします。

このドキュメントには、コンテナ化されたアプリケーションの問題を解決するための、一連のリソースが記載されています。Kubernetesリソース(Pod、Service、StatefulSetなど)に関する一般的な問題や、コンテナ終了メッセージを理解するためのアドバイス、実行中のコンテナをデバッグする方法などが網羅されています。

1 - Podのデバッグ

このガイドは、Kubernetesにデプロイされ、正しく動作しないアプリケーションをユーザーがデバッグするためのものです。 これは、自分のクラスターをデバッグしたい人のためのガイドでは ありません。 そのためには、debug-clusterを確認する必要があります。

問題の診断

トラブルシューティングの最初のステップは切り分けです。何が問題なのでしょうか? Podなのか、レプリケーションコントローラーなのか、それともサービスなのか?

Podのデバッグ

デバッグの第一歩は、Podを見てみることです。 以下のコマンドで、Podの現在の状態や最近のイベントを確認します。

kubectl describe pods ${POD_NAME}

Pod内のコンテナの状態を見てください。 すべてRunningですか? 最近、再起動がありましたか? Podの状態に応じてデバッグを続けます。

PodがPendingのまま

PodがPendingで止まっている場合、それはノードにスケジュールできないことを意味します。 一般に、これはある種のリソースが不十分で、スケジューリングできないことが原因です。 上のkubectl describe ...コマンドの出力を見てください。

なぜあなたのPodをスケジュールできないのか、スケジューラーからのメッセージがあるはずです。 理由は以下の通りです。

  • リソースが不足しています。 クラスターのCPUまたはメモリーを使い果たしている可能性があります。Podを削除するか、リソースの要求値を調整するか、クラスターに新しいノードを追加する必要があります。詳しくはCompute Resources documentを参照してください。

  • あなたが使用しているのはhostPortです。 PodをhostPortにバインドすると、そのPodがスケジュールできる場所が限定されます。ほとんどの場合、hostPortは不要なので、Serviceオブジェクトを使ってPodを公開するようにしてください。もしhostPort が必要な場合は、Kubernetesクラスターのノード数だけPodをスケジュールすることができます。

Podがwaitingのまま

PodがWaiting状態で止まっている場合、ワーカーノードにスケジュールされていますが、そのノード上で実行することができません。この場合も、kubectl describe ...の情報が参考になるはずです。Waiting状態のPodの最も一般的な原因は、コンテナイメージのプルに失敗することです。

確認すべきことは3つあります。

  • イメージの名前が正しいかどうか確認してください。
  • イメージをレジストリにプッシュしましたか?
  • あなたのマシンで手動でdocker pull <image>を実行し、イメージをプルできるかどうか確認してください。

Podがクラッシュするなどの不健全な状態

Podがスケジュールされると、実行中のPodのデバッグで説明されている方法がデバッグに利用できるようになります。

Podが期待する通りに動きません

Podが期待した動作をしない場合、ポッドの記述(ローカルマシンの mypod.yaml ファイルなど)に誤りがあり、Pod作成時にその誤りが黙って無視された可能性があります。Pod記述のセクションのネストが正しくないか、キー名が間違って入力されていることがよくあり、そのようなとき、そのキーは無視されます。たとえば、commandのスペルをcommndと間違えた場合、Podは作成されますが、あなたが意図したコマンドラインは使用されません。

まずPodを削除して、--validate オプションを付けて再度作成してみてください。 例えば、kubectl apply --validate -f mypod.yamlと実行します。 commandのスペルをcommndに間違えると、以下のようなエラーになります。

I0805 10:43:25.129850   46757 schema.go:126] unknown field: commnd
I0805 10:43:25.129973   46757 schema.go:129] this may be a false alarm, see https://github.com/kubernetes/kubernetes/issues/6842
pods/mypod

次に確認することは、apiserver上のPodが、作成しようとしたPod(例えば、ローカルマシンのyamlファイル)と一致しているかどうかです。 例えば、kubectl get pods/mypod -o yaml > mypod-on-apiserver.yaml を実行して、元のポッドの説明であるmypod.yamlとapiserverから戻ってきたmypod-on-apiserver.yamlを手動で比較してみてください。 通常、"apiserver" バージョンには、元のバージョンにはない行がいくつかあります。これは予想されることです。 しかし、もし元のバージョンにある行がapiserverバージョンにない場合、これはあなたのPod specに問題があることを示している可能性があります。

レプリケーションコントローラーのデバッグ

レプリケーションコントローラーはかなり単純なものです。 彼らはPodを作ることができるか、できないか、どちらかです。 もしPodを作成できないのであれば、上記の説明を参照して、Podをデバッグしてください。 また、kubectl describe rc ${CONTROLLER_NAME}を使用すると、レプリケーションコントローラーに関連するイベントを確認することができます。

Serviceのデバッグ

Serviceは、Podの集合全体でロードバランシングを提供します。 Serviceが正しく動作しない原因には、いくつかの一般的な問題があります。

以下の手順は、Serviceの問題をデバッグするのに役立つはずです。

まず、Serviceに対応するEndpointが存在することを確認します。 全てのServiceオブジェクトに対して、apiserverは endpoints リソースを利用できるようにします。 このリソースは次のようにして見ることができます。

kubectl get endpoints ${SERVICE_NAME}

EndpointがServiceのメンバーとして想定されるPod数と一致していることを確認してください。 例えば、3つのレプリカを持つnginxコンテナ用のServiceであれば、ServiceのEndpointには3つの異なるIPアドレスが表示されるはずです。

Serviceに対応するEndpointがありません

Endpointが見つからない場合は、Serviceが使用しているラベルを使用してPodをリストアップしてみてください。 ラベルがあるところにServiceがあると想像してください。

...
spec:
  - selector:
     name: nginx
     type: frontend

セレクタに一致するPodを一覧表示するには、次のコマンドを使用します。

kubectl get pods --selector=name=nginx,type=frontend

リストがServiceを提供する予定のPodと一致することを確認します。 PodのcontainerPortがServiceのtargetPortと一致することを確認します。

ネットワークトラフィックが転送されません

詳しくはServiceのデバッグを参照してください。

次の項目

上記のいずれの方法でも問題が解決しない場合は、以下の手順に従ってください。 Serviceのデバッグに関するドキュメントで、Serviceが実行されていること、Endpointsがあること、Podsが実際にサービスを提供していること、DNSが機能していること、IPtablesルールがインストールされていること、kube-proxyが誤作動を起こしていないようなことを確認してください。

トラブルシューティングドキュメントに詳細が記載されています。

2 - Serviceのデバッグ

新規にKubernetesをインストールした環境でかなり頻繁に発生する問題は、Serviceが適切に機能しないというものです。Deployment(または他のワークロードコントローラー)を通じてPodを実行し、サービスを作成したにもかかわらず、アクセスしようとしても応答がありません。何が問題になっているのかを理解するのに、このドキュメントがきっと役立つでしょう。

Pod内でコマンドを実行する

ここでの多くのステップでは、クラスターで実行されているPodが見ているものを確認する必要があります。これを行う最も簡単な方法は、インタラクティブなalpineのPodを実行することです。

kubectl run -it --rm --restart=Never alpine --image=alpine sh

使用したい実行中のPodがすでにある場合は、以下のようにしてそのPod内でコマンドを実行できます。

kubectl exec <POD-NAME> -c <CONTAINER-NAME> -- <COMMAND>

セットアップ

このドキュメントのウォークスルーのために、いくつかのPodを実行しましょう。おそらくあなた自身のServiceをデバッグしているため、あなた自身の詳細に置き換えることもできますし、これに沿って2番目のデータポイントを取得することもできます。

kubectl create deployment hostnames --image=registry.k8s.io/serve_hostname
deployment.apps/hostnames created

kubectlコマンドは作成、変更されたリソースのタイプと名前を出力するため、この後のコマンドで使用することもできます。

Deploymentを3つのレプリカにスケールさせてみましょう。

kubectl scale deployment hostnames --replicas=3
deployment.apps/hostnames scaled

これは、次のYAMLでDeploymentを開始した場合と同じです。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: hostnames
  labels:
    app: hostnames
spec:
  selector:
    matchLabels:
      app: hostnames
  replicas: 3
  template:
    metadata:
      labels:
        app: hostnames
    spec:
      containers:
      - name: hostnames
        image: registry.k8s.io/serve_hostname

"app"ラベルはkubectl create deploymentによって、Deploymentの名前に自動的にセットされます。

Podが実行されていることを確認できます。

kubectl get pods -l app=hostnames
NAME                        READY     STATUS    RESTARTS   AGE
hostnames-632524106-bbpiw   1/1       Running   0          2m
hostnames-632524106-ly40y   1/1       Running   0          2m
hostnames-632524106-tlaok   1/1       Running   0          2m

Podが機能していることも確認できます。Pod IP アドレスリストを取得し、直接テストできます。

kubectl get pods -l app=hostnames \
    -o go-template='{{range .items}}{{.status.podIP}}{{"\n"}}{{end}}'
10.244.0.5
10.244.0.6
10.244.0.7

このウォークスルーに使用されるサンプルコンテナは、ポート9376でHTTPを介して独自のホスト名を提供するだけですが、独自のアプリをデバッグする場合は、Podがリッスンしているポート番号を使用する必要があります。

Pod内から実行します。

for ep in 10.244.0.5:9376 10.244.0.6:9376 10.244.0.7:9376; do
    wget -qO- $ep
done

次のように表示されます。

hostnames-632524106-bbpiw
hostnames-632524106-ly40y
hostnames-632524106-tlaok

この時点で期待通りの応答が得られない場合、Podが正常でないか、想定しているポートでリッスンしていない可能性があります。なにが起きているかを確認するためにkubectl logsが役立ちます。Podに直接に入りデバッグする場合はkubectl execが必要になります。

これまでにすべての計画が完了していると想定すると、Serviceが機能しない理由を調査することができます。

Serviceは存在するか?

賢明な読者は、Serviceをまだ実際に作成していないことにお気付きかと思いますが、これは意図的です。これは時々忘れられるステップであり、最初に確認すべきことです。

存在しないServiceにアクセスしようとするとどうなるでしょうか?このServiceを名前で利用する別のPodがあると仮定すると、次のような結果が得られます。

wget -O- hostnames
Resolving hostnames (hostnames)... failed: Name or service not known.
wget: unable to resolve host address 'hostnames'

最初に確認するのは、そのServiceが実際に存在するかどうかです。

kubectl get svc hostnames
No resources found.
Error from server (NotFound): services "hostnames" not found

Serviceを作成しましょう。前と同様に、これはウォークスルー用です。ご自身のServiceの詳細を使用することもできます。

kubectl expose deployment hostnames --port=80 --target-port=9376
service/hostnames exposed

そして、念のため内容を確認します。

kubectl get svc hostnames
NAME        TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
hostnames   ClusterIP   10.0.1.175   <none>        80/TCP    5s

これで、Serviceが存在することがわかりました。

前と同様に、これは次のようなYAMLでServiceを開始した場合と同じです。

apiVersion: v1
kind: Service
metadata:
  name: hostnames
spec:
  selector:
    app: hostnames
  ports:
  - name: default
    protocol: TCP
    port: 80
    targetPort: 9376

構成の全範囲をハイライトするため、ここで作成したServiceはPodとは異なるポート番号を使用します。多くの実際のServiceでは、これらのポートは同じになる場合があります。

サービスはDNS名によって機能しているか?

クライアントがサービスを使用する最も一般的な方法の1つは、DNS名を使用することです。同じNamespaceのPodから次のコマンドを実行してください。

nslookup hostnames
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local

Name:      hostnames
Address 1: 10.0.1.175 hostnames.default.svc.cluster.local

これが失敗した場合、おそらくPodとServiceが異なるNamespaceにあるため、ネームスペースで修飾された名前を試してください。(Podの中からもう一度)

nslookup hostnames.default
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local

Name:      hostnames.default
Address 1: 10.0.1.175 hostnames.default.svc.cluster.local

これが機能する場合、クロスネームスペース名を使用するようにアプリケーションを調整するか、同じNamespaceでアプリとServiceを実行する必要があります。これでも失敗する場合は、完全修飾名を試してください。

nslookup hostnames.default.svc.cluster.local
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local

Name:      hostnames.default.svc.cluster.local
Address 1: 10.0.1.175 hostnames.default.svc.cluster.local

ここでのサフィックス"default.svc.cluster.local"に注意してください。"default"は、操作しているNamespaceです。"svc"は、これがServiceであることを示します。"cluster.local"はクラスタードメインであり、あなたのクラスターでは異なる場合があります。

クラスター内のノードからも試すこともできます。

nslookup hostnames.default.svc.cluster.local 10.0.0.10
Server:         10.0.0.10
Address:        10.0.0.10#53

Name:   hostnames.default.svc.cluster.local
Address: 10.0.1.175

完全修飾名では検索できるのに、相対名ではできない場合、Podの/etc/resolv.confファイルが正しいことを確認する必要があります。Pod内から実行します。

cat /etc/resolv.conf

次のように表示されます。

nameserver 10.0.0.10
search default.svc.cluster.local svc.cluster.local cluster.local example.com
options ndots:5

nameserver行はクラスターのDNS Serviceを示さなければなりません。これは、--cluster-dnsフラグでkubeletに渡されます。

search行には、Service名を見つけるための適切なサフィックスを含める必要があります。この場合、ローカルのNamespaceServiceを見つけるためのサフィックス(default.svc.cluster.local)、すべてのNamespacesServiceを見つけるためのサフィックス(svc.cluster.local)、およびクラスターのサフィックス(cluster.local)です。インストール方法によっては、その後に追加のレコードがある場合があります(合計6つまで)。クラスターのサフィックスは、--cluster-domainフラグを使用してkubeletに渡されます。このドキュメントではそれが"cluster.local"であると仮定していますが、あなたのクラスターでは異なる場合があります。その場合は、上記のすべてのコマンドでクラスターのサフィックスを変更する必要があります。

options行では、DNSクライアントライブラリーが検索パスをまったく考慮しないようにndotsを十分に高く設定する必要があります。Kubernetesはデフォルトでこれを5に設定します。これは、生成されるすべてのDNS名をカバーするのに十分な大きさです。

DNS名で機能するServiceはあるか?

上記がまだ失敗する場合、DNSルックアップがServiceに対して機能していません。一歩離れて、他の何が機能していないかを確認しましょう。KubernetesマスターのServiceは常に機能するはずです。Pod内から実行します。

nslookup kubernetes.default
Server:    10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local

Name:      kubernetes.default
Address 1: 10.0.0.1 kubernetes.default.svc.cluster.local

これが失敗する場合は、このドキュメントのkube-proxyセクションを参照するか、このドキュメントの先頭に戻って最初からやり直してください。ただし、あなた自身のServiceをデバッグするのではなく、DNSサービスをデバッグします。

ServiceはIPでは機能するか?

DNSサービスが正しく動作できると仮定すると、次にテストするのはIPによってServiceが動作しているかどうかです。上述のkubectl getで確認できるIPに、クラスター内のPodからアクセスします。

for i in $(seq 1 3); do
    wget -qO- 10.0.1.175:80
done

次のように表示されます。

hostnames-0uton
hostnames-bvc05
hostnames-yp2kp

Serviceが機能している場合は、正しい応答が得られるはずです。そうでない場合、おかしい可能性のあるものがいくつかあるため、続けましょう。

Serviceは正しく定義されているか?

馬鹿げているように聞こえるかもしれませんが、Serviceが正しく定義されPodのポートとマッチすることを二度、三度と確認すべきです。Serviceを読み返して確認しましょう。

kubectl get service hostnames -o json
{
    "kind": "Service",
    "apiVersion": "v1",
    "metadata": {
        "name": "hostnames",
        "namespace": "default",
        "uid": "428c8b6c-24bc-11e5-936d-42010af0a9bc",
        "resourceVersion": "347189",
        "creationTimestamp": "2015-07-07T15:24:29Z",
        "labels": {
            "app": "hostnames"
        }
    },
    "spec": {
        "ports": [
            {
                "name": "default",
                "protocol": "TCP",
                "port": 80,
                "targetPort": 9376,
                "nodePort": 0
            }
        ],
        "selector": {
            "app": "hostnames"
        },
        "clusterIP": "10.0.1.175",
        "type": "ClusterIP",
        "sessionAffinity": "None"
    },
    "status": {
        "loadBalancer": {}
    }
}
  • アクセスしようとしているServiceポートはspec.ports[]のリストのなかに定義されていますか?
  • targetPortはPodに対して適切ですか(いくつかのPodはServiceとは異なるポートを使用します)?
  • targetPortを数値で定義しようとしている場合、それは数値(9376)、文字列"9376"のどちらですか?
  • targetPortを名前で定義しようとしている場合、Podは同じ名前でポートを公開していますか?
  • ポートのprotocolはPodに適切ですか?

ServiceにEndpointsがあるか?

ここまで来たということは、Serviceは正しく定義され、DNSによって名前解決できることが確認できているでしょう。ここでは、実行したPodがServiceによって実際に選択されていることを確認しましょう。

以前に、Podが実行されていることを確認しました。再確認しましょう。

kubectl get pods -l app=hostnames
NAME                        READY     STATUS    RESTARTS   AGE
hostnames-632524106-bbpiw   1/1       Running   0          1h
hostnames-632524106-ly40y   1/1       Running   0          1h
hostnames-632524106-tlaok   1/1       Running   0          1h

-l app=hostnames引数はラベルセレクターで、ちょうど私たちのServiceに定義されているものと同じです。

"AGE"列は、これらのPodが約1時間前のものであることを示しており、それらが正常に実行され、クラッシュしていないことを意味します。

"RESTARTS"列は、これらのポッドが頻繁にクラッシュしたり、再起動されていないことを示しています。頻繁に再起動すると、断続的な接続性の問題が発生する可能性があります。再起動回数が多い場合は、ポッドをデバッグするを参照してください。

Kubernetesシステム内には、すべてのServiceのセレクターを評価し、結果をEndpointsオブジェクトに保存するコントロールループがあります。

kubectl get endpoints hostnames

NAME        ENDPOINTS
hostnames   10.244.0.5:9376,10.244.0.6:9376,10.244.0.7:9376

これにより、EndpointsコントローラーがServiceの正しいPodを見つけていることを確認できます。ENDPOINTS列が<none>の場合、Serviceのspec.selectorフィールドが実際にPodのmetadata.labels値を選択していることを確認する必要があります。よくある間違いは、タイプミスやその他のエラー、たとえばDeployment作成にもkubectl runが使われた1.18以前のバージョンのように、Serviceがapp=hostnamesを選択しているのにDeploymentがrun=hostnamesを指定していることです。

Podは機能しているか?

この時点で、Serviceが存在し、Podを選択していることがわかります。このウォークスルーの最初に、Pod自体を確認しました。Podが実際に機能していることを確認しましょう。Serviceメカニズムをバイパスして、上記EndpointsにリストされているPodに直接アクセスすることができます。

Pod内から実行します。

for ep in 10.244.0.5:9376 10.244.0.6:9376 10.244.0.7:9376; do
    wget -qO- $ep
done

次のように表示されます。

hostnames-632524106-bbpiw
hostnames-632524106-ly40y
hostnames-632524106-tlaok

Endpointsリスト内の各Podは、それぞれの自身のホスト名を返すはずです。そうならない(または、あなた自身のPodの正しい振る舞いにならない)場合は、そこで何が起こっているのかを調査する必要があります。

kube-proxyは機能しているか?

ここに到達したのなら、Serviceは実行され、Endpointsがあり、Podが実際にサービスを提供しています。この時点で、Serviceのプロキシメカニズム全体が疑わしいです。ひとつひとつ確認しましょう。

Serviceのデフォルト実装、およびほとんどのクラスターで使用されるものは、kube-proxyです。kube-proxyはそれぞれのノードで実行され、Serviceの抽象化を提供するための小さなメカニズムセットの1つを構成するプログラムです。クラスターがkube-proxyを使用しない場合、以下のセクションは適用されず、使用しているServiceの実装を調査する必要があります。

kube-proxyは実行されているか?

kube-proxyがノード上で実行されていることを確認しましょう。ノードで実行されていれば、以下のような結果が得られるはずです。

ps auxw | grep kube-proxy
 root  4194  0.4  0.1 101864 17696 ?    Sl Jul04  25:43 /usr/local/bin/kube-proxy --master=https://kubernetes-master --kubeconfig=/var/lib/kube-proxy/kubeconfig --v=2

次に、マスターとの接続など、明らかな失敗をしていないことを確認します。これを行うには、ログを確認する必要があります。ログへのアクセス方法は、ノードのOSに依存します。一部のOSでは/var/log/kube-proxy.logのようなファイルですが、他のOSではjournalctlを使用してログにアクセスします。次のように表示されます。

I1027 22:14:53.995134    5063 server.go:200] Running in resource-only container "/kube-proxy"
I1027 22:14:53.998163    5063 server.go:247] Using iptables Proxier.
I1027 22:14:53.999055    5063 server.go:255] Tearing down userspace rules. Errors here are acceptable.
I1027 22:14:54.038140    5063 proxier.go:352] Setting endpoints for "kube-system/kube-dns:dns-tcp" to [10.244.1.3:53]
I1027 22:14:54.038164    5063 proxier.go:352] Setting endpoints for "kube-system/kube-dns:dns" to [10.244.1.3:53]
I1027 22:14:54.038209    5063 proxier.go:352] Setting endpoints for "default/kubernetes:https" to [10.240.0.2:443]
I1027 22:14:54.038238    5063 proxier.go:429] Not syncing iptables until Services and Endpoints have been received from master
I1027 22:14:54.040048    5063 proxier.go:294] Adding new service "default/kubernetes:https" at 10.0.0.1:443/TCP
I1027 22:14:54.040154    5063 proxier.go:294] Adding new service "kube-system/kube-dns:dns" at 10.0.0.10:53/UDP
I1027 22:14:54.040223    5063 proxier.go:294] Adding new service "kube-system/kube-dns:dns-tcp" at 10.0.0.10:53/TCP

マスターに接続できないことに関するエラーメッセージが表示された場合、ノードの設定とインストール手順をダブルチェックする必要があります。

kube-proxyが正しく実行できない理由の可能性の1つは、必須のconntrackバイナリが見つからないことです。これは、例えばKubernetesをスクラッチからインストールするなど、クラスターのインストール方法に依存して、一部のLinuxシステムで発生する場合があります。これが該当する場合は、conntrackパッケージを手動でインストール(例: Ubuntuではsudo apt install conntrack)する必要があり、その後に再試行する必要があります。

kube-proxyは、いくつかのモードのいずれかで実行できます。上記のログのUsing iptables Proxierという行は、kube-proxyが「iptables」モードで実行されていることを示しています。最も一般的な他のモードは「ipvs」です。古い「ユーザースペース」モードは、主にこれらに置き換えられました。

Iptables mode

「iptables」モードでは、ノードに次のようなものが表示されます。

iptables-save | grep hostnames
-A KUBE-SEP-57KPRZ3JQVENLNBR -s 10.244.3.6/32 -m comment --comment "default/hostnames:" -j MARK --set-xmark 0x00004000/0x00004000
-A KUBE-SEP-57KPRZ3JQVENLNBR -p tcp -m comment --comment "default/hostnames:" -m tcp -j DNAT --to-destination 10.244.3.6:9376
-A KUBE-SEP-WNBA2IHDGP2BOBGZ -s 10.244.1.7/32 -m comment --comment "default/hostnames:" -j MARK --set-xmark 0x00004000/0x00004000
-A KUBE-SEP-WNBA2IHDGP2BOBGZ -p tcp -m comment --comment "default/hostnames:" -m tcp -j DNAT --to-destination 10.244.1.7:9376
-A KUBE-SEP-X3P2623AGDH6CDF3 -s 10.244.2.3/32 -m comment --comment "default/hostnames:" -j MARK --set-xmark 0x00004000/0x00004000
-A KUBE-SEP-X3P2623AGDH6CDF3 -p tcp -m comment --comment "default/hostnames:" -m tcp -j DNAT --to-destination 10.244.2.3:9376
-A KUBE-SERVICES -d 10.0.1.175/32 -p tcp -m comment --comment "default/hostnames: cluster IP" -m tcp --dport 80 -j KUBE-SVC-NWV5X2332I4OT4T3
-A KUBE-SVC-NWV5X2332I4OT4T3 -m comment --comment "default/hostnames:" -m statistic --mode random --probability 0.33332999982 -j KUBE-SEP-WNBA2IHDGP2BOBGZ
-A KUBE-SVC-NWV5X2332I4OT4T3 -m comment --comment "default/hostnames:" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-X3P2623AGDH6CDF3
-A KUBE-SVC-NWV5X2332I4OT4T3 -m comment --comment "default/hostnames:" -j KUBE-SEP-57KPRZ3JQVENLNBR

各サービスのポートごとに、KUBE-SERVICESに1つのルールと1つのKUBE-SVC- <hash>チェーンが必要です。Podエンドポイントごとに、そのKUBE-SVC- <hash>に少数のルールがあり、少数のルールが含まれる1つのKUBE-SEP- <hash>チェーンがあるはずです。正確なルールは、正確な構成(NodePortとLoadBalancerを含む)に基づいて異なります。

IPVS mode

「ipvs」モードでは、ノードに次のようなものが表示されます。

ipvsadm -ln
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
...
TCP  10.0.1.175:80 rr
  -> 10.244.0.5:9376               Masq    1      0          0
  -> 10.244.0.6:9376               Masq    1      0          0
  -> 10.244.0.7:9376               Masq    1      0          0
...

各Serviceの各ポートに加えて、NodePort、External IP、およびLoad Balancer IPに対して、kube-proxyは仮想サーバーを作成します。Pod endpointごとに、対応する実サーバーが作成されます。この例では、サービスhostnames(10.0.1.175:80)は3つのendpoints(10.244.0.5:937610.244.0.6:937610.244.0.7:9376)を持っています。

IPVSプロキシは、各Serviceアドレス(Cluster IP、External IP、NodePort IP、Load Balancer IPなど)毎の仮想サーバーと、Serviceのエンドポイントが存在する場合に対応する実サーバーを作成します。この例では、hostnames Service(10.0.1.175:80)は3つのエンドポイント(10.244.0.5:937610.244.0.6:937610.244.0.7:9376)を持ち、上と似た結果が得られるはずです。

Userspace mode

まれに、「userspace」モードを使用している場合があります。

ノードから実行します。

iptables-save | grep hostnames
-A KUBE-PORTALS-CONTAINER -d 10.0.1.175/32 -p tcp -m comment --comment "default/hostnames:default" -m tcp --dport 80 -j REDIRECT --to-ports 48577
-A KUBE-PORTALS-HOST -d 10.0.1.175/32 -p tcp -m comment --comment "default/hostnames:default" -m tcp --dport 80 -j DNAT --to-destination 10.240.115.247:48577

サービスの各ポートには2つのルールが必要です(この例では1つだけ)-「KUBE-PORTALS-CONTAINER」と「KUBE-PORTALS-HOST」です。

「userspace」モードを使用する必要はほとんどないので、ここでこれ以上時間を費やすことはありません。

kube-proxyはプロキシしているか?

上記のいずれかが発生したと想定して、いずれかのノードからIPでサービスにアクセスをしています。

curl 10.0.1.175:80
hostnames-632524106-bbpiw

もしこれが失敗し、あなたがuserspaceプロキシを使用している場合、プロキシへの直接アクセスを試してみてください。もしiptablesプロキシを使用している場合、このセクションはスキップしてください。

上記のiptables-saveの出力を振り返り、kube-proxyがServiceに使用しているポート番号を抽出します。上記の例では"48577"です。このポートに接続してください。

curl localhost:48577
hostnames-632524106-tlaok

もしまだ失敗する場合は、kube-proxyログで次のような特定の行を探してください。

Setting endpoints for default/hostnames:default to [10.244.0.5:9376 10.244.0.6:9376 10.244.0.7:9376]

これらが表示されない場合は、-vフラグを4に設定してkube-proxyを再起動してから、再度ログを確認してください。

エッジケース: PodがService IP経由で自身に到達できない

これはありそうに聞こえないかもしれませんが、実際には起こり、動作するはずです。これはネットワークが"hairpin"トラフィック用に適切に設定されていない場合、通常はkube-proxyiptablesモードで実行され、Podがブリッジネットワークに接続されている場合に発生します。Kubelethairpin-modeフラグを公開します。これにより、Serviceのエンドポイントが自身のServiceのVIPにアクセスしようとした場合に、自身への負荷分散を可能にします。hairpin-modeフラグはhairpin-vethまたはpromiscuous-bridgeに設定する必要があります。

この問題をトラブルシューティングする一般的な手順は次のとおりです。

  • hairpin-modehairpin-vethまたはpromiscuous-bridgeに設定されていることを確認します。次のような表示がされるはずです。この例では、hairpin-modepromiscuous-bridgeに設定されています。
ps auxw | grep kubelet
root      3392  1.1  0.8 186804 65208 ?        Sl   00:51  11:11 /usr/local/bin/kubelet --enable-debugging-handlers=true --config=/etc/kubernetes/manifests --allow-privileged=True --v=4 --cluster-dns=10.0.0.10 --cluster-domain=cluster.local --configure-cbr0=true --cgroup-root=/ --system-cgroups=/system --hairpin-mode=promiscuous-bridge --runtime-cgroups=/docker-daemon --kubelet-cgroups=/kubelet --babysit-daemons=true --max-pods=110 --serialize-image-pulls=false --outofdisk-transition-frequency=0
  • 実際に使われているhairpin-modeを確認します。これを行うには、kubeletログを確認する必要があります。ログへのアクセス方法は、ノードのOSによって異なります。一部のOSでは/var/log/kubelet.logなどのファイルですが、他のOSではjournalctlを使用してログにアクセスします。互換性のために、実際に使われているhairpin-mode--hairpin-modeフラグと一致しない場合があることに注意してください。kubelet.logにキーワードhairpinを含むログ行があるかどうかを確認してください。実際に使われているhairpin-modeを示す以下のようなログ行があるはずです。
I0629 00:51:43.648698    3252 kubelet.go:380] Hairpin mode set to "promiscuous-bridge"
  • 実際に使われているhairpin-modehairpin-vethの場合、Kubeletにノードの/sysで操作する権限があることを確認します。すべてが正常に機能している場合、次のようなものが表示されます。
for intf in /sys/devices/virtual/net/cbr0/brif/*; do cat $intf/hairpin_mode; done
1
1
1
1

実際に使われているhairpin-modepromiscuous-bridgeの場合、Kubeletにノード上のLinuxブリッジを操作する権限があることを確認してください。cbr0ブリッジが使用され適切に構成されている場合、以下が表示されます。

ifconfig cbr0 |grep PROMISC
UP BROADCAST RUNNING PROMISC MULTICAST  MTU:1460  Metric:1
  • 上記のいずれも解決しない場合、助けを求めてください。

助けを求める

ここまでたどり着いたということは、とてもおかしなことが起こっています。Serviceは実行中で、Endpointsがあり、Podは実際にサービスを提供しています。DNSは動作していて、kube-proxyも誤動作していないようです。それでも、あなたのServiceは機能していません。おそらく私たちにお知らせ頂いた方がよいでしょう。調査をお手伝いします!

SlackForumまたはGitHubでお問い合わせください。

次の項目

詳細については、トラブルシューティングドキュメントをご覧ください。

3 - Pod障害の原因を特定する

このページでは、コンテナ終了メッセージの読み書き方法を説明します。

終了メッセージは、致命的なイベントに関する情報を、ダッシュボードや監視ソフトウェアなどのツールで簡単に取得して表示できる場所にコンテナが書き込むための手段を提供します。 ほとんどの場合、終了メッセージに入力した情報も一般的なKubernetesログに書き込まれるはずです。

始める前に

Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:

バージョンを確認するには次のコマンドを実行してください: kubectl version.

終了メッセージの書き込みと読み取り

この課題では、1つのコンテナを実行するPodを作成します。 設定ファイルには、コンテナの開始時に実行されるコマンドを指定します。

apiVersion: v1
kind: Pod
metadata:
  name: termination-demo
spec:
  containers:
  - name: termination-demo-container
    image: debian
    command: ["/bin/sh"]
    args: ["-c", "sleep 10 && echo Sleep expired > /dev/termination-log"]
  1. YAML設定ファイルに基づいてPodを作成します:

     kubectl apply -f https://k8s.io/examples/debug/termination.yaml
    

    YAMLファイルのcommandフィールドとargsフィールドで、コンテナが10秒間スリープしてから/dev/termination-logファイルに「Sleep expired」と書いているのがわかります。コンテナが「Sleep expired」メッセージを書き込んだ後、コンテナは終了します。

  2. Podに関する情報を表示します:

     kubectl get pod termination-demo
    

    Podが実行されなくなるまで、上記のコマンドを繰り返します。

  3. Podに関する詳細情報を表示します:

     kubectl get pod termination-demo --output=yaml
    

    出力には「Sleep expired」メッセージが含まれています:

     apiVersion: v1
     kind: Pod
     ...
         lastState:
           terminated:
             containerID: ...
             exitCode: 0
             finishedAt: ...
             message: |
               Sleep expired
             ...
    
  4. Goテンプレートを使用して、終了メッセージのみが含まれるように出力をフィルタリングします:

     kubectl get pod termination-demo -o go-template="{{range .status.containerStatuses}}{{.lastState.terminated.message}}{{end}}"
    

終了メッセージのカスタマイズ

Kubernetesは、コンテナのterminationMessagePathフィールドで指定されている終了メッセージファイルから終了メッセージを取得します。デフォルト値は/dev/termination-logです。このフィールドをカスタマイズすることで、Kubernetesに別のファイルを使うように指示できます。Kubernetesは指定されたファイルの内容を使用して、成功と失敗の両方についてコンテナのステータスメッセージを入力します。

終了メッセージはアサーションエラーメッセージのように、最終状態を簡潔に示します。kubeletは4096バイトより長いメッセージは切り詰めます。全コンテナの合計メッセージの長さの上限は12キビバイトです。デフォルトの終了メッセージのパスは/dev/termination-logです。Pod起動後に終了メッセージのパスを設定することはできません。

次の例では、コンテナはKubernetesが取得するために終了メッセージを/tmp/my-logに書き込みます:

apiVersion: v1
kind: Pod
metadata:
  name: msg-path-demo
spec:
  containers:
  - name: msg-path-demo-container
    image: debian
    terminationMessagePath: "/tmp/my-log"

さらに、ユーザーは追加のカスタマイズをするためにContainerのterminationMessagePolicyフィールドを設定できます。このフィールドのデフォルト値はFileです。これは、終了メッセージが終了メッセージファイルからのみ取得されることを意味します。terminationMessagePolicyFallbackToLogsOnErrorに設定することで、終了メッセージファイルが空でコンテナがエラーで終了した場合に、コンテナログ出力の最後のチャンクを使用するようにKubernetesに指示できます。ログ出力は、2048バイトまたは80行のどちらか小さい方に制限されています。

次の項目

4 - StatefulSetのデバッグ

このタスクでは、StatefulSetをデバッグする方法を説明します。

始める前に

  • Kubernetesクラスターが必要です。また、kubectlコマンドラインツールがクラスターと通信するように設定されている必要があります。
  • 調べたいStatefulSetを実行しておきましょう。

StatefulSetのデバッグ

StatefulSetに属し、ラベルapp=myappが設定されているすべてのPodを一覧表示するには、以下のコマンドを利用できます。

kubectl get pods -l app=myapp

Podが長期間UnknownまたはTerminatingの状態になっていることがわかった場合は、それらを処理する方法についてStatefulSetの削除タスクを参照してください。 Podのデバッグガイドを使用して、StatefulSet内の個々のPodをデバッグできます。

次の項目

Initコンテナのデバッグの詳細

5 - Initコンテナのデバッグ

このページでは、Initコンテナの実行に関連する問題を調査する方法を説明します。以下のコマンドラインの例では、Podを<pod-name>、Initコンテナを<init-container-1>および<init-container-2>として参照しています。

始める前に

Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:

バージョンを確認するには次のコマンドを実行してください: kubectl version.

Initコンテナのステータスを確認する

Podのステータスを表示します:

kubectl get pod <pod-name>

たとえば、Init:1/2というステータスは、2つのInitコンテナのうちの1つが正常に完了したことを示します。

NAME         READY     STATUS     RESTARTS   AGE
<pod-name>   0/1       Init:1/2   0          7s

ステータス値とその意味の例については、Podのステータスを理解するを参照してください。

Initコンテナの詳細を取得する

Initコンテナの実行に関する詳細情報を表示します:

kubectl describe pod <pod-name>

たとえば、2つのInitコンテナを持つPodでは、次のように表示されます:

Init Containers:
  <init-container-1>:
    Container ID:    ...
    ...
    State:           Terminated
      Reason:        Completed
      Exit Code:     0
      Started:       ...
      Finished:      ...
    Ready:           True
    Restart Count:   0
    ...
  <init-container-2>:
    Container ID:    ...
    ...
    State:           Waiting
      Reason:        CrashLoopBackOff
    Last State:      Terminated
      Reason:        Error
      Exit Code:     1
      Started:       ...
      Finished:      ...
    Ready:           False
    Restart Count:   3
    ...

また、Pod Specのstatus.initContainerStatusesフィールドを読むことでプログラムでInitコンテナのステータスにアクセスすることもできます。:

kubectl get pod nginx --template '{{.status.initContainerStatuses}}'

このコマンドは生のJSONで上記と同じ情報を返します。

Initコンテナのログにアクセスする

ログにアクセスするには、Initコンテナ名とPod名を渡します。

kubectl logs <pod-name> -c <init-container-2>

シェルスクリプトを実行するInitコンテナは、実行時にコマンドを出力します。たとえば、スクリプトの始めにset -xを実行することでBashで同じことができます。

Podのステータスを理解する

Init:で始まるPodステータスはInitコンテナの実行ステータスを要約します。以下の表は、Initコンテナのデバッグ中に表示される可能性のあるステータス値の例をいくつか示しています。

ステータス 意味
Init:N/M PodはM個のInitコンテナを持ち、これまでにN個完了しました。
Init:Error Initコンテナが実行に失敗しました。
Init:CrashLoopBackOff Initコンテナが繰り返し失敗しました。
Pending PodはまだInitコンテナの実行を開始していません。
PodInitializing or Running PodはすでにInitコンテナの実行を終了しています。

6 - 実行中のPodのデバッグ

このページでは、ノード上で動作している(またはクラッシュしている)Podをデバッグする方法について説明します。

始める前に

  • あなたのPodは既にスケジュールされ、実行されているはずです。Podがまだ実行されていない場合は、アプリケーションのトラブルシューティングから始めてください。

  • いくつかの高度なデバッグ手順では、Podがどのノードで動作しているかを知り、そのノードでコマンドを実行するためのシェルアクセス権を持っていることが必要です。kubectlを使用する標準的なデバッグ手順の実行には、そのようなアクセスは必要ではありません。

kubectl describe podを使ってpodの詳細を取得

この例では、先ほどの例と同様に、Deploymentを使用して2つのpodを作成します。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 2
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        resources:
          limits:
            memory: "128Mi"
            cpu: "500m"
        ports:
        - containerPort: 80

以下のコマンドを実行して、Deploymentを作成します:

kubectl apply -f https://k8s.io/examples/application/nginx-with-request.yaml
deployment.apps/nginx-deployment created

以下のコマンドでPodの状態を確認します:

kubectl get pods
NAME                                READY     STATUS    RESTARTS   AGE
nginx-deployment-1006230814-6winp   1/1       Running   0          11s
nginx-deployment-1006230814-fmgu3   1/1       Running   0          11s

kubectl describe podを使うと、これらのPodについてより多くの情報を得ることができます。 例えば:

kubectl describe pod nginx-deployment-1006230814-6winp
Name:		nginx-deployment-1006230814-6winp
Namespace:	default
Node:		kubernetes-node-wul5/10.240.0.9
Start Time:	Thu, 24 Mar 2016 01:39:49 +0000
Labels:		app=nginx,pod-template-hash=1006230814
Annotations:    kubernetes.io/created-by={"kind":"SerializedReference","apiVersion":"v1","reference":{"kind":"ReplicaSet","namespace":"default","name":"nginx-deployment-1956810328","uid":"14e607e7-8ba1-11e7-b5cb-fa16" ...
Status:		Running
IP:		10.244.0.6
Controllers:	ReplicaSet/nginx-deployment-1006230814
Containers:
  nginx:
    Container ID:	docker://90315cc9f513c724e9957a4788d3e625a078de84750f244a40f97ae355eb1149
    Image:		nginx
    Image ID:		docker://6f62f48c4e55d700cf3eb1b5e33fa051802986b77b874cc351cce539e5163707
    Port:		80/TCP
    QoS Tier:
      cpu:	Guaranteed
      memory:	Guaranteed
    Limits:
      cpu:	500m
      memory:	128Mi
    Requests:
      memory:		128Mi
      cpu:		500m
    State:		Running
      Started:		Thu, 24 Mar 2016 01:39:51 +0000
    Ready:		True
    Restart Count:	0
    Environment:        <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-5kdvl (ro)
Conditions:
  Type          Status
  Initialized   True
  Ready         True
  PodScheduled  True
Volumes:
  default-token-4bcbi:
    Type:	Secret (a volume populated by a Secret)
    SecretName:	default-token-4bcbi
    Optional:   false
QoS Class:      Guaranteed
Node-Selectors: <none>
Tolerations:    <none>
Events:
  FirstSeen	LastSeen	Count	From					SubobjectPath		Type		Reason		Message
  ---------	--------	-----	----					-------------		--------	------		-------
  54s		54s		1	{default-scheduler }						Normal		Scheduled	Successfully assigned nginx-deployment-1006230814-6winp to kubernetes-node-wul5
  54s		54s		1	{kubelet kubernetes-node-wul5}	spec.containers{nginx}	Normal		Pulling		pulling image "nginx"
  53s		53s		1	{kubelet kubernetes-node-wul5}	spec.containers{nginx}	Normal		Pulled		Successfully pulled image "nginx"
  53s		53s		1	{kubelet kubernetes-node-wul5}	spec.containers{nginx}	Normal		Created		Created container with docker id 90315cc9f513
  53s		53s		1	{kubelet kubernetes-node-wul5}	spec.containers{nginx}	Normal		Started		Started container with docker id 90315cc9f513

ここでは、コンテナ(複数可)とPodに関する構成情報(ラベル、リソース要件など)や、コンテナ(複数可)とPodに関するステータス情報(状態、準備状況、再起動回数、イベントなど)を確認できます。

コンテナの状態は、Waiting(待機中)、Running(実行中)、Terminated(終了)のいずれかです。状態に応じて、追加の情報が提供されます。ここでは、Running状態のコンテナについて、コンテナがいつ開始されたかが表示されています。

Readyは、コンテナが最後のReadiness Probeに合格したかどうかを示す。(この場合、コンテナにはReadiness Probeが設定されていません。Readiness Probeが設定されていない場合、コンテナは準備が完了した状態であるとみなされます)。

Restart Countは、コンテナが何回再起動されたかを示します。この情報は、再起動ポリシーが「always」に設定されているコンテナのクラッシュループを検出するのに役立ちます。

現在、Podに関連する条件は、二値のReady条件のみです。これは、Podがリクエストに対応可能であり、マッチングするすべてのサービスのロードバランシングプールに追加されるべきであることを示します。

最後に、Podに関連する最近のイベントのログが表示されます。このシステムでは、複数の同一イベントを圧縮して、最初に見られた時刻と最後に見られた時刻、そして見られた回数を示します。"From"はイベントを記録しているコンポーネントを示し、"SubobjectPath"はどのオブジェクト(例: Pod内のコンテナ)が参照されているかを示し、"Reason"と "Message"は何が起こったかを示しています。

例: Pending Podsのデバッグ

イベントを使って検出できる一般的なシナリオは、どのノードにも収まらないPodを作成した場合です。例えば、Podがどのノードでも空いている以上のリソースを要求したり、どのノードにもマッチしないラベルセレクターを指定したりする場合です。例えば、各(仮想)マシンが1つのCPUを持つ4ノードのクラスター上で、(2つではなく)5つのレプリカを持ち、500ではなく600ミリコアを要求する前のDeploymentを作成したとします。この場合、Podの1つがスケジュールできなくなります。(なお、各ノードではfluentdやskydnsなどのクラスターアドオンPodが動作しているため、もし1000ミリコアを要求した場合、どのPodもスケジュールできなくなります)

kubectl get pods
NAME                                READY     STATUS    RESTARTS   AGE
nginx-deployment-1006230814-6winp   1/1       Running   0          7m
nginx-deployment-1006230814-fmgu3   1/1       Running   0          7m
nginx-deployment-1370807587-6ekbw   1/1       Running   0          1m
nginx-deployment-1370807587-fg172   0/1       Pending   0          1m
nginx-deployment-1370807587-fz9sd   0/1       Pending   0          1m

nginx-deployment-1370807587-fz9sdのPodが実行されていない理由を調べるには、保留中のPodに対してkubectl describe podを使用し、そのイベントを見てみましょう

kubectl describe pod nginx-deployment-1370807587-fz9sd
  Name:		nginx-deployment-1370807587-fz9sd
  Namespace:	default
  Node:		/
  Labels:		app=nginx,pod-template-hash=1370807587
  Status:		Pending
  IP:
  Controllers:	ReplicaSet/nginx-deployment-1370807587
  Containers:
    nginx:
      Image:	nginx
      Port:	80/TCP
      QoS Tier:
        memory:	Guaranteed
        cpu:	Guaranteed
      Limits:
        cpu:	1
        memory:	128Mi
      Requests:
        cpu:	1
        memory:	128Mi
      Environment Variables:
  Volumes:
    default-token-4bcbi:
      Type:	Secret (a volume populated by a Secret)
      SecretName:	default-token-4bcbi
  Events:
    FirstSeen	LastSeen	Count	From			        SubobjectPath	Type		Reason			    Message
    ---------	--------	-----	----			        -------------	--------	------			    -------
    1m		    48s		    7	    {default-scheduler }			        Warning		FailedScheduling	pod (nginx-deployment-1370807587-fz9sd) failed to fit in any node
  fit failure on node (kubernetes-node-6ta5): Node didn't have enough resource: CPU, requested: 1000, used: 1420, capacity: 2000
  fit failure on node (kubernetes-node-wul5): Node didn't have enough resource: CPU, requested: 1000, used: 1100, capacity: 2000

ここでは、理由 FailedScheduling (およびその他の理由)でPodのスケジュールに失敗したという、スケジューラーによって生成されたイベントを見ることができます。このメッセージは、どのノードでもPodに十分なリソースがなかったことを示しています。

この状況を修正するには、kubectl scaleを使用して、4つ以下のレプリカを指定するようにDeploymentを更新します。(あるいは、1つのPodを保留にしたままにしておいても害はありません。)

kubectl describe podの最後に出てきたようなイベントは、etcdに永続化され、クラスターで何が起こっているかについての高レベルの情報を提供します。

すべてのイベントをリストアップするには、次のようにします:

kubectl get events

しかし、イベントは名前空間に所属することを忘れてはいけません。つまり、名前空間で管理されているオブジェクトのイベントに興味がある場合(例: 名前空間 my-namespaceのPods で何が起こったか)、コマンドに名前空間を明示的に指定する必要があります。

kubectl get events --namespace=my-namespace

すべての名前空間からのイベントを見るには、--all-namespaces 引数を使用できます。

kubectl describe podに加えて、(kubectl get pod で提供される以上の)Podに関する追加情報を得るためのもう一つの方法は、-o yaml出力形式フラグを kubectl get podに渡すことです。これにより、kubectl describe podよりもさらに多くの情報、つまりシステムが持っているPodに関するすべての情報をYAML形式で得ることができます。ここでは、アノテーション(Kubernetesのシステムコンポーネントが内部的に使用している、ラベル制限のないキーバリューのメタデータ)、再起動ポリシー、ポート、ボリュームなどが表示されます。

kubectl get pod nginx-deployment-1006230814-6winp -o yaml
apiVersion: v1
kind: Pod
metadata:
  annotations:
    kubernetes.io/created-by: |
      {"kind":"SerializedReference","apiVersion":"v1","reference":{"kind":"ReplicaSet","namespace":"default","name":"nginx-deployment-1006230814","uid":"4c84c175-f161-11e5-9a78-42010af00005","apiVersion":"extensions","resourceVersion":"133434"}}      
  creationTimestamp: 2016-03-24T01:39:50Z
  generateName: nginx-deployment-1006230814-
  labels:
    app: nginx
    pod-template-hash: "1006230814"
  name: nginx-deployment-1006230814-6winp
  namespace: default
  resourceVersion: "133447"
  uid: 4c879808-f161-11e5-9a78-42010af00005
spec:
  containers:
  - image: nginx
    imagePullPolicy: Always
    name: nginx
    ports:
    - containerPort: 80
      protocol: TCP
    resources:
      limits:
        cpu: 500m
        memory: 128Mi
      requests:
        cpu: 500m
        memory: 128Mi
    terminationMessagePath: /dev/termination-log
    volumeMounts:
    - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
      name: default-token-4bcbi
      readOnly: true
  dnsPolicy: ClusterFirst
  nodeName: kubernetes-node-wul5
  restartPolicy: Always
  securityContext: {}
  serviceAccount: default
  serviceAccountName: default
  terminationGracePeriodSeconds: 30
  volumes:
  - name: default-token-4bcbi
    secret:
      secretName: default-token-4bcbi
status:
  conditions:
  - lastProbeTime: null
    lastTransitionTime: 2016-03-24T01:39:51Z
    status: "True"
    type: Ready
  containerStatuses:
  - containerID: docker://90315cc9f513c724e9957a4788d3e625a078de84750f244a40f97ae355eb1149
    image: nginx
    imageID: docker://6f62f48c4e55d700cf3eb1b5e33fa051802986b77b874cc351cce539e5163707
    lastState: {}
    name: nginx
    ready: true
    restartCount: 0
    state:
      running:
        startedAt: 2016-03-24T01:39:51Z
  hostIP: 10.240.0.9
  phase: Running
  podIP: 10.244.0.6
  startTime: 2016-03-24T01:39:49Z

例: ダウン/到達不可能なノードのデバッグ

例えば、ノード上で動作しているPodのおかしな挙動に気付いたり、Podがノード上でスケジュールされない原因を探ったりと、デバッグ時にノードのステータスを見ることが有用な場合があります。Podと同様に、kubectl describe nodekubectl get node -o yamlを使ってノードの詳細情報を取得することができます。例えば、ノードがダウンした場合(ネットワークから切断された、またはkubeletが死んで再起動しないなど)に表示される内容は以下の通りです。ノードがNotReadyであることを示すイベントに注目してください。また、Podが実行されなくなっていることにも注目してください(NotReady状態が5分続くと、Podは退避されます)。

kubectl get nodes
NAME                     STATUS       ROLES     AGE     VERSION
kubernetes-node-861h     NotReady     <none>    1h      v1.13.0
kubernetes-node-bols     Ready        <none>    1h      v1.13.0
kubernetes-node-st6x     Ready        <none>    1h      v1.13.0
kubernetes-node-unaj     Ready        <none>    1h      v1.13.0
kubectl describe node kubernetes-node-861h
Name:			kubernetes-node-861h
Role
Labels:		 kubernetes.io/arch=amd64
           kubernetes.io/os=linux
           kubernetes.io/hostname=kubernetes-node-861h
Annotations:        node.alpha.kubernetes.io/ttl=0
                    volumes.kubernetes.io/controller-managed-attach-detach=true
Taints:             <none>
CreationTimestamp:	Mon, 04 Sep 2017 17:13:23 +0800
Phase:
Conditions:
  Type		Status		LastHeartbeatTime			LastTransitionTime			Reason					Message
  ----    ------    -----------------     ------------------      ------          -------
  OutOfDisk             Unknown         Fri, 08 Sep 2017 16:04:28 +0800         Fri, 08 Sep 2017 16:20:58 +0800         NodeStatusUnknown       Kubelet stopped posting node status.
  MemoryPressure        Unknown         Fri, 08 Sep 2017 16:04:28 +0800         Fri, 08 Sep 2017 16:20:58 +0800         NodeStatusUnknown       Kubelet stopped posting node status.
  DiskPressure          Unknown         Fri, 08 Sep 2017 16:04:28 +0800         Fri, 08 Sep 2017 16:20:58 +0800         NodeStatusUnknown       Kubelet stopped posting node status.
  Ready                 Unknown         Fri, 08 Sep 2017 16:04:28 +0800         Fri, 08 Sep 2017 16:20:58 +0800         NodeStatusUnknown       Kubelet stopped posting node status.
Addresses:	10.240.115.55,104.197.0.26
Capacity:
 cpu:           2
 hugePages:     0
 memory:        4046788Ki
 pods:          110
Allocatable:
 cpu:           1500m
 hugePages:     0
 memory:        1479263Ki
 pods:          110
System Info:
 Machine ID:                    8e025a21a4254e11b028584d9d8b12c4
 System UUID:                   349075D1-D169-4F25-9F2A-E886850C47E3
 Boot ID:                       5cd18b37-c5bd-4658-94e0-e436d3f110e0
 Kernel Version:                4.4.0-31-generic
 OS Image:                      Debian GNU/Linux 8 (jessie)
 Operating System:              linux
 Architecture:                  amd64
 Container Runtime Version:     docker://1.12.5
 Kubelet Version:               v1.6.9+a3d1dfa6f4335
 Kube-Proxy Version:            v1.6.9+a3d1dfa6f4335
ExternalID:                     15233045891481496305
Non-terminated Pods:            (9 in total)
  Namespace                     Name                                            CPU Requests    CPU Limits      Memory Requests Memory Limits
  ---------                     ----                                            ------------    ----------      --------------- -------------
......
Allocated resources:
  (Total limits may be over 100 percent, i.e., overcommitted.)
  CPU Requests  CPU Limits      Memory Requests         Memory Limits
  ------------  ----------      ---------------         -------------
  900m (60%)    2200m (146%)    1009286400 (66%)        5681286400 (375%)
Events:         <none>
kubectl get node kubernetes-node-861h -o yaml
apiVersion: v1
kind: Node
metadata:
  creationTimestamp: 2015-07-10T21:32:29Z
  labels:
    kubernetes.io/hostname: kubernetes-node-861h
  name: kubernetes-node-861h
  resourceVersion: "757"
  uid: 2a69374e-274b-11e5-a234-42010af0d969
spec:
  externalID: "15233045891481496305"
  podCIDR: 10.244.0.0/24
  providerID: gce://striped-torus-760/us-central1-b/kubernetes-node-861h
status:
  addresses:
  - address: 10.240.115.55
    type: InternalIP
  - address: 104.197.0.26
    type: ExternalIP
  capacity:
    cpu: "1"
    memory: 3800808Ki
    pods: "100"
  conditions:
  - lastHeartbeatTime: 2015-07-10T21:34:32Z
    lastTransitionTime: 2015-07-10T21:35:15Z
    reason: Kubelet stopped posting node status.
    status: Unknown
    type: Ready
  nodeInfo:
    bootID: 4e316776-b40d-4f78-a4ea-ab0d73390897
    containerRuntimeVersion: docker://Unknown
    kernelVersion: 3.16.0-0.bpo.4-amd64
    kubeProxyVersion: v0.21.1-185-gffc5a86098dc01
    kubeletVersion: v0.21.1-185-gffc5a86098dc01
    machineID: ""
    osImage: Debian GNU/Linux 7 (wheezy)
    systemUUID: ABE5F6B4-D44B-108B-C46A-24CCE16C8B6E

Podログを調べます

まず、影響を受けるコンテナのログを見ます。

kubectl logs ${POD_NAME} ${CONTAINER_NAME}

コンテナが以前にクラッシュしたことがある場合、次のコマンドで以前のコンテナのクラッシュログにアクセスすることができます:

kubectl logs --previous ${POD_NAME} ${CONTAINER_NAME}

container execによるデバッグ

もしcontainer imageがデバッグユーティリティを含んでいれば、LinuxやWindows OSのベースイメージからビルドしたイメージのように、kubectl execで特定のコンテナ内でコマンドを実行することが可能です:

kubectl exec ${POD_NAME} -c ${CONTAINER_NAME} -- ${CMD} ${ARG1} ${ARG2} ... ${ARGN}

例として、実行中のCassandra Podからログを見るには、次のように実行します。

kubectl exec cassandra -- cat /var/log/cassandra/system.log

例えばkubectl exec-i-t引数を使って、端末に接続されたシェルを実行することができます:

kubectl exec -it cassandra -- sh

詳しくは、実行中のコンテナへのシェルを取得するを参照してください。

エフェメラルコンテナによるデバッグ

FEATURE STATE: Kubernetes v1.25 [stable]

エフェメラルコンテナは、コンテナがクラッシュしたり、コンテナイメージにデバッグユーティリティが含まれていないなどの理由でkubectl execが不十分な場合に、対話的にトラブルシューティングを行うのに便利です(ディストロレスイメージの場合など)。

エフェメラルコンテナを使用したデバッグ例

実行中のPodにエフェメラルコンテナを追加するには、kubectl debugコマンドを使用することができます。 まず、サンプル用のPodを作成します:

kubectl run ephemeral-demo --image=registry.k8s.io/pause:3.1 --restart=Never

このセクションの例では、デバッグユーティリティが含まれていないpauseコンテナイメージを使用していますが、この方法はすべてのコンテナイメージで動作します。

もし、kubectl execを使用してシェルを作成しようとすると、このコンテナイメージにはシェルが存在しないため、エラーが表示されます。

kubectl exec -it ephemeral-demo -- sh
OCI runtime exec failed: exec failed: container_linux.go:346: starting container process caused "exec: \"sh\": executable file not found in $PATH": unknown

代わりに、kubectl debugを使ってデバッグ用のコンテナを追加することができます。 引数に-i/--interactiveを指定すると、kubectlは自動的にエフェメラルコンテナのコンソールにアタッチされます。

kubectl debug -it ephemeral-demo --image=busybox:1.28 --target=ephemeral-demo
Defaulting debug container name to debugger-8xzrl.
If you don't see a command prompt, try pressing enter.
/ #

このコマンドは新しいbusyboxコンテナを追加し、それにアタッチします。--targetパラメーターは、他のコンテナのプロセス名前空間をターゲットにします。これはkubectl runが作成するPodでプロセス名前空間の共有を有効にしないため、指定する必要があります。

新しく作成されたエフェメラルコンテナの状態はkubectl describeを使って見ることができます:

kubectl describe pod ephemeral-demo
...
Ephemeral Containers:
  debugger-8xzrl:
    Container ID:   docker://b888f9adfd15bd5739fefaa39e1df4dd3c617b9902082b1cfdc29c4028ffb2eb
    Image:          busybox
    Image ID:       docker-pullable://busybox@sha256:1828edd60c5efd34b2bf5dd3282ec0cc04d47b2ff9caa0b6d4f07a21d1c08084
    Port:           <none>
    Host Port:      <none>
    State:          Running
      Started:      Wed, 12 Feb 2020 14:25:42 +0100
    Ready:          False
    Restart Count:  0
    Environment:    <none>
    Mounts:         <none>
...

終了したらkubectl deleteを使ってPodを削除してください:

kubectl delete pod ephemeral-demo

Podのコピーを使ったデバッグ

Podの設定オプションによって、特定の状況でのトラブルシューティングが困難になることがあります。 例えば、コンテナイメージにシェルが含まれていない場合、またはアプリケーションが起動時にクラッシュした場合は、kubectl execを実行してトラブルシューティングを行うことができません。 このような状況では、kubectl debugを使用してデバッグを支援するために設定値を変更したPodのコピーを作ることができます。

新しいコンテナを追加しながらPodをコピーします

新しいコンテナを追加することは、アプリケーションは動作しているが期待通りの動作をせず、トラブルシューティングユーティリティをPodに追加したい場合に便利です。 例えば、アプリケーションのコンテナイメージはbusybox上にビルドされているが、busyboxに含まれていないデバッグユーティリティが必要な場合があります。このシナリオはkubectl runを使ってシミュレーションすることができます。

kubectl run myapp --image=busybox:1.28 --restart=Never -- sleep 1d

このコマンドを実行すると、myappのコピーにmyapp-debugという名前が付き、デバッグ用の新しいUbuntuコンテナが追加されます。

kubectl debug myapp -it --image=ubuntu --share-processes --copy-to=myapp-debug
Defaulting debug container name to debugger-w7xmf.
If you don't see a command prompt, try pressing enter.
root@myapp-debug:/#

デバッグが終わったら、Podの後始末をするのを忘れないでください。

kubectl delete pod myapp myapp-debug

Podのコマンドを変更しながらコピーします

例えば、デバッグフラグを追加する場合や、アプリケーションがクラッシュしている場合などでは、コンテナのコマンドを変更すると便利なことがあります。 アプリケーションのクラッシュをシミュレートするには、kubectl runを使用して、すぐに終了するコンテナを作成します:

kubectl run --image=busybox:1.28 myapp -- false

kubectl describe pod myappを使用すると、このコンテナがクラッシュしていることがわかります:

Containers:
  myapp:
    Image:         busybox
    ...
    Args:
      false
    State:          Waiting
      Reason:       CrashLoopBackOff
    Last State:     Terminated
      Reason:       Error
      Exit Code:    1

kubectl debugを使うと、コマンドをインタラクティブシェルに変更したこのPodのコピーを作成することができます。

kubectl debug myapp -it --copy-to=myapp-debug --container=myapp -- sh
If you don't see a command prompt, try pressing enter.
/ #

これで、ファイルシステムのパスのチェックやコンテナコマンドの手動実行などのタスクを実行するために使用できる対話型シェルが完成しました。

デバッグが終わったら、Podの後始末をするのを忘れないでください:

kubectl delete pod myapp myapp-debug

コンテナイメージを変更してPodをコピーします

状況によっては、動作不良のPodを通常のプロダクション用のコンテナイメージから、デバッグビルドや追加ユーティリティを含むイメージに変更したい場合があります。

例として、kubectl runを使用してPodを作成します:

kubectl run myapp --image=busybox:1.28 --restart=Never -- sleep 1d

ここで、kubectl debugを使用してコピーを作成し、そのコンテナイメージをubuntuに変更します:

kubectl debug myapp --copy-to=myapp-debug --set-image=*=ubuntu

--set-imageの構文は、kubectl set imageと同じcontainer_name=imageの構文を使用します。*=ubuntuは、全てのコンテナのイメージをubuntuに変更することを意味します。

デバッグが終わったら、Podの後始末をするのを忘れないでください:

kubectl delete pod myapp myapp-debug

ノード上のシェルによるデバッグ

いずれの方法でもうまくいかない場合は、Podが動作しているノードを探し出し、ホストの名前空間で動作するデバッグ用のPodを作成します。 ノード上でkubectl debugを使って対話型のシェルを作成するには、以下を実行します:

kubectl debug node/mynode -it --image=ubuntu
Creating debugging pod node-debugger-mynode-pdx84 with container debugger on node mynode.
If you don't see a command prompt, try pressing enter.
root@ek8s:/#

ノードでデバッグセッションを作成する場合、以下の点に注意してください:

  • kubectl debugはノードの名前に基づいて新しいPodの名前を自動的に生成します。
  • ノードのルートファイルシステムは/hostにマウントされます。
  • コンテナはホストのIPC、Network、PIDネームスペースで実行されますが、特権は付与されません。そのため、ホスト上のプロセス情報の参照や、chroot /hostの実行に失敗する場合があります。
  • 特権が必要な場合は手動でPodを作成するか、--profile=sysadminを使用してください。

デバッグが終わったら、Podの後始末をするのを忘れないでください:

kubectl delete pod node-debugger-mynode-pdx84

デバッグプロファイルを使用したPodやNodeのデバッグ

kubectl debugでノードやPodをデバッグする場合、デバッグ用のPod、エフェメラルコンテナ、またはコピーされたPodにデバッグプロファイルを適用できます。 デバッグプロファイルを適用することで、securityContextなど特定のプロパティが設定され、 さまざまなシナリオに適応できるようになります。 デバッグプロファイルにはスタティックプロファイルとカスタムプロファイルの2種類があります。

スタティックプロファイルの適用

スタティックプロファイルは事前に定義されたプロパティの組み合わせで構成され、--profileフラグを使用して適用できます。 使用可能なスタティックプロファイルは以下の通りです:

Profile Description
legacy v1.22と互換性を保つプロパティのセット
general 各デバッグシナリオに対応する汎用的なプロパティのセット
baseline PodSecurityStandard baseline policy に準拠したプロパティのセット
restricted PodSecurityStandard restricted policyに準拠したプロパティのセット
netadmin ネットワーク管理者権限を含むプロパティのセット
sysadmin システム管理者(root)権限を含むプロパティのセット

例えば、myappという名前のPodを作成し、デバッグを行います:

kubectl run myapp --image=busybox:1.28 --restart=Never -- sleep 1d

エフェメラルコンテナを使用して、Podをデバッグします。 エフェメラルコンテナに特権が必要な場合は、sysadminプロファイルを使用できます:

kubectl debug -it myapp --image=busybox:1.28 --target=myapp --profile=sysadmin
Targeting container "myapp". If you don't see processes from this container it may be because the container runtime doesn't support this feature.
Defaulting debug container name to debugger-6kg4x.
If you don't see a command prompt, try pressing enter.
/ #

コンテナで次のコマンドを実行して、エフェメラルコンテナプロセスのケーパビリティを確認します:

/ # grep Cap /proc/$$/status
...
CapPrm:	000001ffffffffff
CapEff:	000001ffffffffff
...

この結果は、sysadminプロファイルを適用したことで、エフェメラルコンテナプロセスに特権が付与されていることを示しています。 詳細はコンテナにケーパビリティを設定するを参照してください。

エフェメラルコンテナが特権コンテナであることは、次のコマンドからも確認できます:

kubectl get pod myapp -o jsonpath='{.spec.ephemeralContainers[0].securityContext}'
{"privileged":true}

確認が終わったらPodを削除します:

kubectl delete pod myapp

カスタムプロファイルの適用

FEATURE STATE: Kubernetes v1.31 [beta]

デバッグに使用するコンテナのspecをYAMLまたはJSON形式でカスタムプロファイルとして定義し、--customフラグを使用して適用できます。

例えば、myappという名前のPodを作成します:

kubectl run myapp --image=busybox:1.28 --restart=Never -- sleep 1d

YAMLまたはJSON形式でカスタムプロファイルを作成します。 ここでは、custom-profile.yamlという名前のYAML形式のファイルを作成します:

env:
- name: ENV_VAR_1
  value: value_1
- name: ENV_VAR_2
  value: value_2
securityContext:
  capabilities:
    add:
    - NET_ADMIN
    - SYS_TIME

次のコマンドを実行することで、エフェメラルコンテナにカスタムプロファイルを適用し、Podをデバッグします:

kubectl debug -it myapp --image=busybox:1.28 --target=myapp --profile=general --custom=custom-profile.yaml

Podにカスタムプロファイルが適用された状態のエフェメラルコンテナが追加されたことを確認できます:

kubectl get pod myapp -o jsonpath='{.spec.ephemeralContainers[0].env}'
[{"name":"ENV_VAR_1","value":"value_1"},{"name":"ENV_VAR_2","value":"value_2"}]
kubectl get pod myapp -o jsonpath='{.spec.ephemeralContainers[0].securityContext}'
{"capabilities":{"add":["NET_ADMIN","SYS_TIME"]}}

確認が終わったらPodを削除します:

kubectl delete pod myapp

7 - 実行中のコンテナへのシェルを取得する

このページはkubectl execを使用して実行中のコンテナへのシェルを取得する方法を説明します。

始める前に

Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:

コンテナへのシェルの取得

このエクササイズでは、1つのコンテナを持つPodを作成します。 コンテナはnginxのイメージを実行します。以下がそのPodの設定ファイルです:

apiVersion: v1
kind: Pod
metadata:
  name: shell-demo
spec:
  volumes:
  - name: shared-data
    emptyDir: {}
  containers:
  - name: nginx
    image: nginx
    volumeMounts:
    - name: shared-data
      mountPath: /usr/share/nginx/html

Podを作成します:

kubectl apply -f https://k8s.io/examples/application/shell-demo.yaml

コンテナが実行中であることを確認します:

kubectl get pod shell-demo

実行中のコンテナへのシェルを取得します:

kubectl exec --stdin --tty shell-demo -- /bin/bash

シェル内で、ルートディレクトリーのファイル一覧を表示します:

# このコマンドをコンテナ内で実行します
ls /

シェル内で、他のコマンドを試しましょう。以下がいくつかの例です:

# これらのサンプルコマンドをコンテナ内で実行することができます
ls /
cat /proc/mounts
cat /proc/1/maps
apt-get update
apt-get install -y tcpdump
tcpdump
apt-get install -y lsof
lsof
apt-get install -y procps
ps aux
ps aux | grep nginx

nginxのルートページへの書き込み

Podの設定ファイルを再度確認します。PodはemptyDirボリュームを持ち、 コンテナは/usr/share/nginx/htmlボリュームをマウントします。

シェル内で、/usr/share/nginx/htmlディレクトリにindex.htmlを作成します。

# このコマンドをコンテナ内で実行します
echo 'Hello shell demo' > /usr/share/nginx/html/index.html

シェル内で、nginxサーバーにGETリクエストを送信します:

# これらのコマンドをコンテナ内のシェルで実行します
apt-get update
apt-get install curl
curl http://localhost/

出力にindex.htmlファイルに書き込んだ文字列が表示されます:

Hello shell demo

シェルを終了する場合、exitを入力します。

exit # コンテナ内のシェルを終了する

コンテナ内での各コマンドの実行

シェルではない通常のコマンドウインドウ内で、実行中のコンテナの環境変数の一覧を表示します:

kubectl exec shell-demo -- env

他のコマンドを試します。以下がいくつかの例です:

kubectl exec shell-demo -- ps aux
kubectl exec shell-demo -- ls /
kubectl exec shell-demo -- cat /proc/1/mounts

Podが1つ以上のコンテナを持つ場合にシェルを開く

Podが1つ以上のコンテナを持つ場合、--container-cを使用して、kubectl execコマンド内でコンテナを指定します。 例えば、my-podという名前のPodがあり、そのPodが main-apphelper-app という2つのコンテナを持つとします。 以下のコマンドは main-app のコンテナへのシェルを開きます。

kubectl exec -i -t my-pod --container main-app -- /bin/bash

次の項目