これは、このセクションの複数ページの印刷可能なビューです。 印刷するには、ここをクリックしてください.
監視、ログ、デバッグ
- 1: crictlによるKubernetesノードのデバッグ
- 2: Initコンテナのデバッグ
- 3: PodとReplicationControllerのデバッグ
- 4: Pod障害の原因を特定する
- 5: Serviceのデバッグ
- 6: StatefulSetのデバッグ
- 7: アプリケーションのトラブルシューティング
- 8: アプリケーションの自己観察とデバッグ
- 9: ノードの健全性を監視します
- 10: ローカルでのサービス開発・デバッグ
- 11: クラスターのトラブルシューティング
- 12: トラブルシューティング
- 13: リソースメトリクスパイプライン
- 14: リソース監視のためのツール
- 15: 監査
- 16: 実行中のPodのデバッグ
- 17: 実行中のコンテナへのシェルを取得する
1 - crictlによるKubernetesノードのデバッグ
Kubernetes v1.11 [stable]crictlはCRI互換のコンテナランタイム用のコマンドラインインターフェイスです。
これを使って、Kubernetesノード上のコンテナランタイムやアプリケーションの検査やデバッグを行うことができます。
crictlとそのソースコードはcri-toolsリポジトリにホストされています。
始める前に
crictlにはCRIランタイムを搭載したLinuxが必要です。
crictlのインストール
cri-toolsのリリースページから、いくつかの異なるアーキテクチャ用の圧縮アーカイブcrictlをダウンロードできます。
お使いのKubernetesのバージョンに対応するバージョンをダウンロードしてください。
それを解凍してシステムパス上の/usr/local/bin/などの場所に移動します。
一般的な使い方
crictlコマンドにはいくつかのサブコマンドとランタイムフラグがあります。
詳細はcrictl helpまたはcrictl <subcommand> helpを参照してください。
crictlはデフォルトではunix:///var/run/dockershim.sockに接続します。
他のランタイムの場合は、複数の異なる方法でエンドポイントを設定することができます:
- フラグ
--runtime-endpointと--image-endpointの設定により - 環境変数
CONTAINER_RUNTIME_ENDPOINTとIMAGE_SERVICE_ENDPOINTの設定により - 設定ファイル
--config=/etc/crictl.yamlでエンドポイントの設定により
また、サーバーに接続する際のタイムアウト値を指定したり、デバッグを有効/無効にしたりすることもできます。
これには、設定ファイルでtimeoutやdebugを指定するか、--timeoutや--debugのコマンドラインフラグを使用します。
現在の設定を表示または編集するには、/etc/crictl.yamlの内容を表示または編集します。
cat /etc/crictl.yaml
runtime-endpoint: unix:///var/run/dockershim.sock
image-endpoint: unix:///var/run/dockershim.sock
timeout: 10
debug: true
crictlコマンドの例
以下の例では、いくつかのcrictlコマンドとその出力例を示しています。
crictlを使ってポッドのサンドボックスやコンテナを作成しても、Kubeletは最終的にそれらを削除します。crictl は汎用のワークフローツールではなく、デバッグに便利なツールです。podsの一覧
すべてのポッドをリストアップ:
crictl pods
出力はこのようになります:
POD ID CREATED STATE NAME NAMESPACE ATTEMPT
926f1b5a1d33a About a minute ago Ready sh-84d7dcf559-4r2gq default 0
4dccb216c4adb About a minute ago Ready nginx-65899c769f-wv2gp default 0
a86316e96fa89 17 hours ago Ready kube-proxy-gblk4 kube-system 0
919630b8f81f1 17 hours ago Ready nvidia-device-plugin-zgbbv kube-system 0
Podを名前でリストアップします:
crictl pods --name nginx-65899c769f-wv2gp
出力はこのようになります:
POD ID CREATED STATE NAME NAMESPACE ATTEMPT
4dccb216c4adb 2 minutes ago Ready nginx-65899c769f-wv2gp default 0
Podをラベルでリストアップします:
crictl pods --label run=nginx
出力はこのようになります:
POD ID CREATED STATE NAME NAMESPACE ATTEMPT
4dccb216c4adb 2 minutes ago Ready nginx-65899c769f-wv2gp default 0
イメージの一覧
すべてのイメージをリストアップします:
crictl images
出力はこのようになります:
IMAGE TAG IMAGE ID SIZE
busybox latest 8c811b4aec35f 1.15MB
k8s-gcrio.azureedge.net/hyperkube-amd64 v1.10.3 e179bbfe5d238 665MB
k8s-gcrio.azureedge.net/pause-amd64 3.1 da86e6ba6ca19 742kB
nginx latest cd5239a0906a6 109MB
イメージをリポジトリでリストアップします:
crictl images nginx
出力はこのようになります:
IMAGE TAG IMAGE ID SIZE
nginx latest cd5239a0906a6 109MB
イメージのIDのみをリストアップします:
crictl images -q
出力はこのようになります:
sha256:8c811b4aec35f259572d0f79207bc0678df4c736eeec50bc9fec37ed936a472a
sha256:e179bbfe5d238de6069f3b03fccbecc3fb4f2019af741bfff1233c4d7b2970c5
sha256:da86e6ba6ca197bf6bc5e9d900febd906b133eaa4750e6bed647b0fbe50ed43e
sha256:cd5239a0906a6ccf0562354852fae04bc5b52d72a2aff9a871ddb6bd57553569
List containers
すべてのコンテナをリストアップします:
crictl ps -a
出力はこのようになります:
CONTAINER ID IMAGE CREATED STATE NAME ATTEMPT
1f73f2d81bf98 busybox@sha256:141c253bc4c3fd0a201d32dc1f493bcf3fff003b6df416dea4f41046e0f37d47 7 minutes ago Running sh 1
9c5951df22c78 busybox@sha256:141c253bc4c3fd0a201d32dc1f493bcf3fff003b6df416dea4f41046e0f37d47 8 minutes ago Exited sh 0
87d3992f84f74 nginx@sha256:d0a8828cccb73397acb0073bf34f4d7d8aa315263f1e7806bf8c55d8ac139d5f 8 minutes ago Running nginx 0
1941fb4da154f k8s-gcrio.azureedge.net/hyperkube-amd64@sha256:00d814b1f7763f4ab5be80c58e98140dfc69df107f253d7fdd714b30a714260a 18 hours ago Running kube-proxy 0
ランニングコンテナをリストアップします:
crictl ps
出力はこのようになります:
CONTAINER ID IMAGE CREATED STATE NAME ATTEMPT
1f73f2d81bf98 busybox@sha256:141c253bc4c3fd0a201d32dc1f493bcf3fff003b6df416dea4f41046e0f37d47 6 minutes ago Running sh 1
87d3992f84f74 nginx@sha256:d0a8828cccb73397acb0073bf34f4d7d8aa315263f1e7806bf8c55d8ac139d5f 7 minutes ago Running nginx 0
1941fb4da154f k8s-gcrio.azureedge.net/hyperkube-amd64@sha256:00d814b1f7763f4ab5be80c58e98140dfc69df107f253d7fdd714b30a714260a 17 hours ago Running kube-proxy 0
実行中のコンテナでコマンドの実行
crictl exec -i -t 1f73f2d81bf98 ls
出力はこのようになります:
bin dev etc home proc root sys tmp usr var
コンテナログの取得
すべてのコンテナログを取得します:
crictl logs 87d3992f84f74
出力はこのようになります:
10.240.0.96 - - [06/Jun/2018:02:45:49 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.47.0" "-"
10.240.0.96 - - [06/Jun/2018:02:45:50 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.47.0" "-"
10.240.0.96 - - [06/Jun/2018:02:45:51 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.47.0" "-"
最新のN行のログのみを取得します:
crictl logs --tail=1 87d3992f84f74
出力はこのようになります:
10.240.0.96 - - [06/Jun/2018:02:45:51 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.47.0" "-"
Podサンドボックスの実行
crictlを使ってPodサンドボックスを実行することは、コンテナのランタイムをデバッグするのに便利です。
稼働中のKubernetesクラスタでは、サンドボックスは最終的にKubeletによって停止され、削除されます。
以下のようなJSONファイルを作成します:
{ "metadata": { "name": "nginx-sandbox", "namespace": "default", "attempt": 1, "uid": "hdishd83djaidwnduwk28bcsb" }, "logDirectory": "/tmp", "linux": { } }JSONを適用してサンドボックスを実行するには、
crictl runpコマンドを使用します:crictl runp pod-config.jsonサンドボックスのIDが返されます。
コンテナの作成
コンテナの作成にcrictlを使うと、コンテナのランタイムをデバッグするのに便利です。
稼働中のKubernetesクラスタでは、サンドボックスは最終的にKubeletによって停止され、削除されます。
busyboxイメージをプルします:
crictl pull busybox Image is up to date for busybox@sha256:141c253bc4c3fd0a201d32dc1f493bcf3fff003b6df416dea4f41046e0f37d47Podとコンテナのコンフィグを作成します:
Pod config:
{ "metadata": { "name": "nginx-sandbox", "namespace": "default", "attempt": 1, "uid": "hdishd83djaidwnduwk28bcsb" }, "log_directory": "/tmp", "linux": { } }Container config:
{ "metadata": { "name": "busybox" }, "image":{ "image": "busybox" }, "command": [ "top" ], "log_path":"busybox.log", "linux": { } }先に作成されたPodのID、コンテナの設定ファイル、Podの設定ファイルを渡して、コンテナを作成します。コンテナのIDが返されます。
crictl create f84dd361f8dc51518ed291fbadd6db537b0496536c1d2d6c05ff943ce8c9a54f container-config.json pod-config.jsonすべてのコンテナをリストアップし、新しく作成されたコンテナの状態が
Createdに設定されていることを確認します:crictl ps -a出力はこのようになります:
CONTAINER ID IMAGE CREATED STATE NAME ATTEMPT 3e025dd50a72d busybox 32 seconds ago Created busybox 0
コンテナの起動
コンテナを起動するには、そのコンテナのIDをcrictl startに渡します:
crictl start 3e025dd50a72d956c4f14881fbb5b1080c9275674e95fb67f965f6478a957d60
出力はこのようになります:
3e025dd50a72d956c4f14881fbb5b1080c9275674e95fb67f965f6478a957d60
コンテナの状態が「Running」に設定されていることを確認します:
crictl ps
出力はこのようになります:
CONTAINER ID IMAGE CREATED STATE NAME ATTEMPT
3e025dd50a72d busybox About a minute ago Running busybox 0
詳しくはkubernetes-sigs/cri-toolsをご覧ください。
docker cliからcrictlへのマッピング
以下のマッピング表の正確なバージョンは、docker cli v1.40とcrictl v1.19.0のものです。
この一覧はすべてを網羅しているわけではないことに注意してください。
たとえば、docker cliの実験的なコマンドは含まれていません。
デバッグ情報の取得
| docker cli | crictl | 説明 | サポートされていない機能 |
|---|---|---|---|
attach | attach | 実行中のコンテナにアタッチ | --detach-keys, --sig-proxy |
exec | exec | 実行中のコンテナでコマンドの実行 | --privileged, --user, --detach-keys |
images | images | イメージのリストアップ | |
info | info | システム全体の情報の表示 | |
inspect | inspect, inspecti | コンテナ、イメージ、タスクの低レベルの情報を返します | |
logs | logs | コンテナのログを取得します | --details |
ps | ps | コンテナのリストアップ | |
stats | stats | コンテナのリソース使用状況をライブで表示 | Column: NET/BLOCK I/O, PIDs |
version | version | ランタイム(Docker、ContainerD、その他)のバージョン情報を表示します |
変更を行います
| docker cli | crictl | 説明 | サポートされていない機能 |
|---|---|---|---|
create | create | 新しいコンテナを作成します | |
kill | stop (timeout = 0) | 1つ以上の実行中のコンテナを停止します | --signal |
pull | pull | レジストリーからイメージやリポジトリをプルします | --all-tags, --disable-content-trust |
rm | rm | 1つまたは複数のコンテナを削除します | |
rmi | rmi | 1つまたは複数のイメージを削除します | |
run | run | 新しいコンテナでコマンドを実行 | |
start | start | 停止した1つまたは複数のコンテナを起動 | --detach-keys |
stop | stop | 実行中の1つまたは複数のコンテナの停止 | |
update | update | 1つまたは複数のコンテナの構成を更新 | --restart、--blkio-weightとその他 |
crictlでのみ対応
| crictl | 説明 |
|---|---|
imagefsinfo | イメージファイルシステムの情報を返します |
inspectp | 1つまたは複数のPodの状態を表示します |
port-forward | ローカルポートをPodに転送します |
runp | 新しいPodを実行します |
rmp | 1つまたは複数のPodを削除します |
stopp | 稼働中の1つまたは複数のPodを停止します |
2 - Initコンテナのデバッグ
このページでは、Initコンテナの実行に関連する問題を調査する方法を説明します。以下のコマンドラインの例では、Podを<pod-name>、Initコンテナを<init-container-1>および<init-container-2>として参照しています。
始める前に
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
バージョンを確認するには次のコマンドを実行してください:kubectl version.- Initコンテナの基本を理解しておきましょう。
- Initコンテナを設定しておきましょう。
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コンテナの実行を終了しています。 |
3 - PodとReplicationControllerのデバッグ
このページでは、PodとReplicationControllerをデバッグする方法を説明します。
始める前に
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
バージョンを確認するには次のコマンドを実行してください:kubectl version.- PodとPodのライフサイクルの基本を理解している必要があります。
Podのデバッグ
Podのデバッグの最初のステップは、Podを調べることです。 次のコマンドで、Podの現在の状態と最近のイベントを確認して下さい。
kubectl describe pods ${POD_NAME}
Pod内のコンテナの状態を確認します。
コンテナはすべてRunning状態ですか?最近再起動はしましたか?
Podの状態に応じてデバッグを続けます。
PodがPending状態にとどまっている
PodがPending状態でスタックしている場合、ノードにスケジュールできていないことを意味します。
一般的に、これは、何らかのタイプのリソースが不足しており、それによってスケジューリングを妨げられているためです。
上述のkubectl describe...コマンドの出力を確認してください。
Podをスケジュールできない理由に関するスケジューラーからのメッセージがあるはずです。
理由としては以下のようなものがあります。
リソースが不十分
クラスター内のCPUまたはメモリーの供給を使い果たした可能性があります。 この場合、いくつかのことを試すことができます。
クラスターにノードを追加します。
不要なPodを終了して、
Pending状態のPodのための空きリソースを作ります。Podがノードよりも大きくないことを確認します。 例えば、すべてのノードのキャパシティーが
cpu: 1の場合、cpu: 1.1を要求するPodは決してスケジュールされません。kubectl get nodes -o <format>コマンドでノードのキャパシティーを確認できます。 必要な情報を抽出するコマンドラインの例を以下に示します。kubectl get nodes -o yaml | egrep '\sname:|cpu:|memory:' kubectl get nodes -o json | jq '.items[] | {name: .metadata.name, cap: .status.capacity}'リソースクォータ機能では、 消費できるリソースの合計量を制限するように構成できます。 Namespaceと組み合わせて使用すると、1つのチームがすべてのリソースを占有することを防ぐことができます。
hostPortの使用
PodをhostPortにバインドすると、Podをスケジュールできる場所の数が制限されます。
ほとんどの場合、hostPortは不要です。Serviceオブジェクトを使用してPodを公開してください。
どうしてもhostPortが必要な場合は、コンテナクラスター内のノードと同じ数のPodのみをスケジュールできます。
PodがWaiting状態にとどまっている
PodがWaiting状態でスタックしている場合、Podはワーカーノードにスケジュールされていますが、そのマシンでは実行できない状態です。
この場合も、kubectl describe ...の情報が参考になるはずです。
PodがWaiting状態となる最も一般的な原因は、イメージをプルできないことです。
確認すべき事項が3つあります。
- イメージの名前が正しいことを確認して下さい。
- イメージはリポジトリーにプッシュしましたか?
- マシンで手動で
docker pull <image>を実行し、イメージをプルできるかどうかを確認して下さい。
Podがクラッシュする、あるいはUnhealthy状態
Podがスケジュールされると、動作中のPodをデバッグするに説明されている方法がデバッグに使用可能です。
ReplicationControllerのデバッグ
ReplicationControllerはかなり明快です。Podを作成できるか、できないかのどちらかです。 Podを作成できない場合は、上述の手順を参照してPodをデバッグしてください。
kubectl describe rc ${CONTROLLER_NAME}を使用して、レプリケーションコントローラーに関連するイベントを調べることもできます。
4 - 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"]
YAML設定ファイルに基づいてPodを作成します:
kubectl apply -f https://k8s.io/examples/debug/termination.yamlYAMLファイルの
commandフィールドとargsフィールドで、コンテナが10秒間スリープしてから/dev/termination-logファイルに「Sleep expired」と書いているのがわかります。コンテナが「Sleep expired」メッセージを書き込んだ後、コンテナは終了します。Podに関する情報を表示します:
kubectl get pod termination-demoPodが実行されなくなるまで、上記のコマンドを繰り返します。
Podに関する詳細情報を表示します:
kubectl get pod termination-demo --output=yaml出力には「Sleep expired」メッセージが含まれています:
apiVersion: v1 kind: Pod ... lastState: terminated: containerID: ... exitCode: 0 finishedAt: ... message: | Sleep expired ...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です。これは、終了メッセージが終了メッセージファイルからのみ取得されることを意味します。terminationMessagePolicyをFallbackToLogsOnErrorに設定することで、終了メッセージファイルが空でコンテナがエラーで終了した場合に、コンテナログ出力の最後のチャンクを使用するようにKubernetesに指示できます。ログ出力は、2048バイトまたは80行のどちらか小さい方に制限されています。
次の項目
5 - 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=k8s.gcr.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: k8s.gcr.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名を見つけるための適切なサフィックスを含める必要があります。この場合、ローカルのNamespaceでServiceを見つけるためのサフィックス(default.svc.cluster.local)、すべてのNamespacesでServiceを見つけるためのサフィックス(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:9376、10.244.0.6:9376、10.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:9376、10.244.0.6:9376、10.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-proxyがiptablesモードで実行され、Podがブリッジネットワークに接続されている場合に発生します。Kubeletはhairpin-modeフラグを公開します。これにより、Serviceのエンドポイントが自身のServiceのVIPにアクセスしようとした場合に、自身への負荷分散を可能にします。hairpin-modeフラグはhairpin-vethまたはpromiscuous-bridgeに設定する必要があります。
この問題をトラブルシューティングする一般的な手順は次のとおりです。
hairpin-modeがhairpin-vethまたはpromiscuous-bridgeに設定されていることを確認します。次のような表示がされるはずです。この例では、hairpin-modeはpromiscuous-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-modeがhairpin-vethの場合、Kubeletにノードの/sysで操作する権限があることを確認します。すべてが正常に機能している場合、次のようなものが表示されます。
for intf in /sys/devices/virtual/net/cbr0/brif/*; do cat $intf/hairpin_mode; done
1
1
1
1
実際に使われているhairpin-modeがpromiscuous-bridgeの場合、Kubeletにノード上のLinuxブリッジを操作する権限があることを確認してください。cbr0ブリッジが使用され適切に構成されている場合、以下が表示されます。
ifconfig cbr0 |grep PROMISC
UP BROADCAST RUNNING PROMISC MULTICAST MTU:1460 Metric:1
- 上記のいずれも解決しない場合、助けを求めてください。
助けを求める
ここまでたどり着いたということは、とてもおかしなことが起こっています。Serviceは実行中で、Endpointsがあり、Podは実際にサービスを提供しています。DNSは動作していて、kube-proxyも誤動作していないようです。それでも、あなたのServiceは機能していません。おそらく私たちにお知らせ頂いた方がよいでしょう。調査をお手伝いします!
Slack、ForumまたはGitHubでお問い合わせください。
次の項目
詳細については、トラブルシューティングドキュメントをご覧ください。
6 - StatefulSetのデバッグ
このタスクでは、StatefulSetをデバッグする方法を説明します。
始める前に
- Kubernetesクラスターが必要です。また、kubectlコマンドラインツールがクラスターと通信するように設定されている必要があります。
- 調べたいStatefulSetを実行しておきましょう。
StatefulSetのデバッグ
StatefulSetに属し、ラベルapp=myappが設定されているすべてのPodを一覧表示するには、以下のコマンドを利用できます。
kubectl get pods -l app=myapp
Podが長期間UnknownまたはTerminatingの状態になっていることがわかった場合は、それらを処理する方法についてStatefulSetの削除タスクを参照してください。
Podのデバッグガイドを使用して、StatefulSet内の個々のPodをデバッグできます。
次の項目
7 - アプリケーションのトラブルシューティング
このガイドは、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がスケジュールされると、Debug Running Podsで説明されている方法がデバッグに利用できるようになります。
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のデバッグを参照してください。
次の項目
上記のいずれの方法でも問題が解決しない場合は、以下の手順に従ってください。
Debugging Service documentで、Service が実行されていること、Endpointsがあること、Podsが実際にサービスを提供していること、DNS が機能していること、IPtablesルールがインストールされていること、kube-proxyが誤作動を起こしていないようなことを確認してください。
トラブルシューティングドキュメントに詳細が記載されています。
8 - アプリケーションの自己観察とデバッグ
アプリケーションが稼働すると、必然的にその問題をデバッグする必要が出てきます。
先に、kubectl get podsを使って、Podの簡単なステータス情報を取得する方法を説明しました。
しかし、アプリケーションに関するより多くの情報を取得する方法がいくつかあります。
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 nodeやkubectl 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
次の項目
以下のような追加のデバッグツールについて学びます:
9 - ノードの健全性を監視します
Node Problem Detectorは、ノードの健全性を監視し、報告するためのデーモンです。
Node Problem DetectorはDaemonSetとして、あるいはスタンドアロンデーモンとして実行することができます。
Node Problem Detectorは様々なデーモンからノードの問題に関する情報を収集し、これらの状態をNodeConditionおよびEventとしてAPIサーバーにレポートします。
Node Problem Detectorのインストール方法と使用方法については、Node Problem Detectorプロジェクトドキュメントを参照してください。
始める前に
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
制限事項
Node Problem Detectorは、ファイルベースのカーネルログのみをサポートします。
journaldのようなログツールはサポートされていません。Node Problem Detectorは、カーネルの問題を報告するためにカーネルログフォーマットを使用します。 カーネルログフォーマットを拡張する方法については、Add support for another log format を参照してください。
ノード問題検出の有効化
クラウドプロバイダーによっては、Node Problem DetectorをAddonとして有効にしている場合があります。
また、kubectlを使ってNode Problem Detectorを有効にするか、Addon podを作成することで有効にできます。
kubectlを使用してNode Problem Detectorを有効化します
kubectlはNode Problem Detectorを最も柔軟に管理することができます。
デフォルトの設定を上書きして自分の環境に合わせたり、カスタマイズしたノードの問題を検出したりすることができます。
例えば:
node-problem-detector.yamlのようなNode Problem Detectorの設定を作成します:apiVersion: apps/v1 kind: DaemonSet metadata: name: node-problem-detector-v0.1 namespace: kube-system labels: k8s-app: node-problem-detector version: v0.1 kubernetes.io/cluster-service: "true" spec: selector: matchLabels: k8s-app: node-problem-detector version: v0.1 kubernetes.io/cluster-service: "true" template: metadata: labels: k8s-app: node-problem-detector version: v0.1 kubernetes.io/cluster-service: "true" spec: hostNetwork: true containers: - name: node-problem-detector image: k8s.gcr.io/node-problem-detector:v0.1 securityContext: privileged: true resources: limits: cpu: "200m" memory: "100Mi" requests: cpu: "20m" memory: "20Mi" volumeMounts: - name: log mountPath: /log readOnly: true volumes: - name: log hostPath: path: /var/log/備考: システムログのディレクトリが、お使いのOSのディストリビューションに合っていることを確認する必要があります。Node Problem Detectorをkubectlで起動します。kubectl apply -f https://k8s.io/examples/debug/node-problem-detector.yaml
Addon podを使用してNode Problem Detectorを有効化します
カスタムのクラスターブートストラップソリューションを使用していて、デフォルトの設定を上書きする必要がない場合は、Addon Podを利用してデプロイをさらに自動化できます。
node-problem-detector.yamlを作成し、制御プレーンノードのAddon Podのディレクトリ/etc/kubernetes/addons/node-problem-detectorに設定を保存します。
コンフィギュレーションを上書きします
Node Problem Detectorの Dockerイメージをビルドする際に、default configurationが埋め込まれます。
ConfigMap を使用することで設定を上書きすることができます。
config/にある設定ファイルを変更しますConfigMapnode-problem-detector-configを作成します。kubectl create configmap node-problem-detector-config --from-file=config/node-problem-detector.yamlを変更して、ConfigMapを使用するようにします。apiVersion: apps/v1 kind: DaemonSet metadata: name: node-problem-detector-v0.1 namespace: kube-system labels: k8s-app: node-problem-detector version: v0.1 kubernetes.io/cluster-service: "true" spec: selector: matchLabels: k8s-app: node-problem-detector version: v0.1 kubernetes.io/cluster-service: "true" template: metadata: labels: k8s-app: node-problem-detector version: v0.1 kubernetes.io/cluster-service: "true" spec: hostNetwork: true containers: - name: node-problem-detector image: k8s.gcr.io/node-problem-detector:v0.1 securityContext: privileged: true resources: limits: cpu: "200m" memory: "100Mi" requests: cpu: "20m" memory: "20Mi" volumeMounts: - name: log mountPath: /log readOnly: true - name: config # Overwrite the config/ directory with ConfigMap volume mountPath: /config readOnly: true volumes: - name: log hostPath: path: /var/log/ - name: config # Define ConfigMap volume configMap: name: node-problem-detector-config新しい設定ファイルで
Node Problem Detectorを再作成します。# If you have a node-problem-detector running, delete before recreating kubectl delete -f https://k8s.io/examples/debug/node-problem-detector.yaml kubectl apply -f https://k8s.io/examples/debug/node-problem-detector-configmap.yaml
kubectl で起動された Node Problem Detector にのみ適用されます。ノード問題検出装置がクラスターアドオンとして実行されている場合、設定の上書きはサポートされていません。
Addon Managerは、ConfigMapをサポートしていません。
Kernel Monitor
Kernel MonitorはNode Problem Detectorでサポートされるシステムログ監視デーモンです。
Kernel Monitorはカーネルログを監視し、事前に定義されたルールに従って既知のカーネル問題を検出します。
Kernel Monitorはconfig/kernel-monitor.jsonにある一連の定義済みルールリストに従ってカーネルの問題を照合します。
ルールリストは拡張可能です。設定を上書きすることで、ルールリストを拡張することができます。
新しいNodeConditionsの追加
新しいNodeConditionをサポートするには、例えばconfig/kernel-monitor.jsonのconditionsフィールド内に条件定義を作成します。
{
"type": "NodeConditionType",
"reason": "CamelCaseDefaultNodeConditionReason",
"message": "arbitrary default node condition message"
}
新たな問題の発見
新しい問題を検出するために、config/kernel-monitor.jsonのrulesフィールドを新しいルール定義で拡張することができます。
{
"type": "temporary/permanent",
"condition": "NodeConditionOfPermanentIssue",
"reason": "CamelCaseShortReason",
"message": "regexp matching the issue in the kernel log"
}
カーネルログデバイスのパスの設定
ご使用のオペレーティングシステム(OS)ディストリビューションのカーネルログパスをご確認ください。
Linuxカーネルのログデバイスは通常/dev/kmsgとして表示されます。
しかし、OSのディストリビューションによって、ログパスの位置は異なります。
config/kernel-monitor.jsonのlogフィールドは、コンテナ内のログパスを表します。
logフィールドは、Node Problem Detectorで見たデバイスパスと一致するように設定することができます。
別のログ形式をサポートします
Kernel monitorはTranslatorプラグインを使用して、カーネルログの内部データ構造を変換します。
新しいログフォーマット用に新しいトランスレータを実装することができます。
推奨・制限事項
ノードの健全性を監視するために、クラスターでNode Problem Detectorを実行することが推奨されます。
Node Problem Detectorを実行する場合、各ノードで余分なリソースのオーバーヘッドが発生することが予想されます。
通常これは問題ありません。
- カーネルログは比較的ゆっくりと成長します。
- Node Problem Detector にはリソース制限が設定されています。
- 高負荷時であっても、リソースの使用は許容範囲内です。
詳細はNode Problem Detectorベンチマーク結果を参照してください。
10 - ローカルでのサービス開発・デバッグ
Kubernetesアプリケーションは通常、複数の独立したサービスから構成され、それぞれが独自のコンテナで動作しています。これらのサービスをリモートのKubernetesクラスター上で開発・デバッグするには、get a shell on a running containerしてリモートシェル内でツールを実行しなければならず面倒な場合があります。
telepresenceは、リモートKubernetesクラスターにサービスをプロキシーしながら、ローカルでサービスを開発・デバッグするプロセスを容易にするためのツールです。
telepresence を使用すると、デバッガーやIDEなどのカスタムツールをローカルサービスで使用でき、ConfigMapやsecret、リモートクラスター上で動作しているサービスへのフルアクセスをサービスに提供します。
このドキュメントでは、リモートクラスタ上で動作しているサービスをローカルで開発・デバッグするためにtelepresenceを使用する方法を説明します。
始める前に
- Kubernetesクラスターがインストールされていること
- クラスターと通信するために
kubectlが設定されていること - telepresenceがインストールされていること
リモートクラスター上でシェルの取得
ターミナルを開いて、引数なしでtelepresenceを実行すると、telepresenceシェルが表示されます。
このシェルはローカルで動作し、ローカルのファイルシステムに完全にアクセスすることができます。
このtelepresenceシェルは様々な方法で使用することができます。
例えば、ラップトップでシェルスクリプトを書いて、それをシェルから直接リアルタイムで実行することができます。これはリモートシェルでもできますが、好みのコードエディターが使えないかもしれませんし、コンテナが終了するとスクリプトは削除されます。
終了してシェルを閉じるにはexitと入力してください。
既存サービスの開発・デバッグ
Kubernetes上でアプリケーションを開発する場合、通常は1つのサービスをプログラミングまたはデバッグすることになります。 そのサービスは、テストやデバッグのために他のサービスへのアクセスを必要とする場合があります。 継続的なデプロイメントパイプラインを使用することも一つの選択肢ですが、最速のデプロイメントパイプラインでさえ、プログラムやデバッグサイクルに遅延が発生します。
既存のデプロイメントとtelepresenceプロキシーを交換するには、--swap-deployment オプションを使用します。
スワップすることで、ローカルでサービスを実行し、リモートのKubernetesクラスターに接続することができます。
リモートクラスター内のサービスは、ローカルで実行されているインスタンスにアクセスできるようになりました。
telepresenceを「--swap-deployment」で実行するには、次のように入力します。
telepresence --swap-deployment $DEPLOYMENT_NAME
ここで、$DEPLOYMENT_NAMEは既存のDeploymentの名前です。
このコマンドを実行すると、シェルが起動します。そのシェルで、サービスを起動します。 そして、ローカルでソースコードの編集を行い、保存すると、すぐに変更が反映されるのを確認できます。 また、デバッガーやその他のローカルな開発ツールでサービスを実行することもできます。
次の項目
もしハンズオンのチュートリアルに興味があるなら、Google Kubernetes Engine上でGuestbookアプリケーションをローカルに開発する手順を説明したこちらのチュートリアルをチェックしてみてください。
telepresenceには、状況に応じてnumerous proxying optionsがあります。
さらに詳しい情報は、telepresence websiteをご覧ください。
11 - クラスターのトラブルシューティング
このドキュメントはクラスターのトラブルシューティングに関するもので、あなたが経験している問題の根本原因として、アプリケーションをすでに除外していることを前提としています。 アプリケーションのデバッグのコツは、application troubleshooting guideをご覧ください。 また、troubleshooting documentにも詳しい情報があります。
クラスターのリストアップ
クラスターで最初にデバッグするのは、ノードがすべて正しく登録されているかどうかです。
kubectl get nodes
そして、期待するノードがすべて存在し、それらがすべて Ready 状態であることを確認します。
クラスター全体の健全性に関する詳細な情報を得るには、以下を実行します。
kubectl cluster-info dump
ログの確認
今のところ、クラスターをより深く掘り下げるには、関連するマシンにログインする必要があります。
以下は、関連するログファイルの場所です。
(systemdベースのシステムでは、代わりに journalctl を使う必要があるかもしれないことに注意してください)
マスターノード
/var/log/kube-apiserver.log- APIの提供を担当するAPIサーバーのログ/var/log/kube-scheduler.log- スケジューリング決定責任者であるスケジューラーのログ/var/log/kube-controller-manager.log- レプリケーションコントローラーを管理するコントローラーのログ
ワーカーノード
/var/log/kubelet.log- ノード上でコンテナの実行を担当するKubeletのログ/var/log/kube-proxy.log- サービスのロードバランシングを担うKube Proxyのログ
クラスター障害モードの一般的な概要
これは、問題が発生する可能性のある事柄と、問題を軽減するためにクラスターのセットアップを調整する方法の不完全なリストです。
根本的な原因
- VMのシャットダウン
- クラスター内、またはクラスターとユーザー間のネットワークパーティション
- Kubernetesソフトウェアのクラッシュ
- データの損失や永続的ストレージ(GCE PDやAWS EBSボリュームなど)の使用不能
- Kubernetesソフトウェアやアプリケーションソフトウェアの設定ミスなど、オペレーターのミス
具体的なシナリオ
apiserver VMのシャットダウンまたはapiserverのクラッシュ
- 新しいPod、サービス、レプリケーションコントローラの停止、更新、起動ができない
- Kubernetes APIに依存していない限り、既存のPodやサービスは正常に動作し続けるはずです
apiserverのバックアップストレージが失われた
- apiserverが立ち上がらない
- kubeletsは到達できなくなりますが、同じPodを実行し、同じサービスのプロキシを提供し続けます
- apiserverを再起動する前に、手動でapiserverの状態を回復または再現する必要がある
サポートサービス(ノードコントローラ、レプリケーションコントローラーマネージャー、スケジューラーなど)VMのシャットダウンまたはクラッシュ
- 現在、これらはapiserverとコロケーションしており、使用できない場合はapiserverと同様の影響があります
- 将来的には、これらも複製されるようになり、同じ場所に配置されない可能性があります
- 独自の永続的な状態を持っていない。
個別ノード(VMまたは物理マシン)のシャットダウン
- そのノード上のPodの実行を停止
ネットワークパーティション
- パーティションAはパーティションBのノードがダウンしていると考え、パーティションBはapiserverがダウンしていると考えています。(マスターVMがパーティションAで終了したと仮定)
Kubeletソフトウェア障害
- クラッシュしたkubeletがノード上で新しいPodを起動できない
- kubeletがPodを削除するかどうか
- ノードが不健全と判定される
- レプリケーションコントローラーが別の場所で新しいPodを起動する
クラスターオペレーターエラー
- PodやServiceなどの損失
- apiserverのバックエンドストレージの紛失
- ユーザーがAPIを読めなくなる
- その他
軽減策
対処法: IaaSプロバイダーの自動VM再起動機能をIaaS VMに使用する
- 異常: Apiserver VMのシャットダウンまたはApiserverのクラッシュ
- 異常: サポートサービスのVMシャットダウンまたはクラッシュ
対処法: IaaSプロバイダーの信頼できるストレージ(GCE PDやAWS EBSボリュームなど)をapiserver+etcdを使用するVMに使用する
- 異常: Apiserverのバックエンドストレージが失われる
対処法: 高可用性構成を使用します
- 異常: コントロールプレーンノードのシャットダウンまたはコントロールプレーンコンポーネント(スケジューラー、APIサーバー、コントローラーマネージャー)のクラッシュ
- 1つ以上のノードまたはコンポーネントの同時故障に耐えることができる
- 異常: APIサーバーのバックアップストレージ(etcdのデータディレクトリーなど)が消失
- HA(高可用性) etcdの構成を想定しています
- 異常: コントロールプレーンノードのシャットダウンまたはコントロールプレーンコンポーネント(スケジューラー、APIサーバー、コントローラーマネージャー)のクラッシュ
対処法: apiserver PDs/EBS-volumesを定期的にスナップショットする
- 異常: Apiserver のバックエンドストレージが失われる
- 異常: 操作ミスが発生する場合がある
- 異常: Kubernetesのソフトウェアに障害が発生する場合がある
対処法:レプリケーションコントローラーとServiceをPodの前に使用する
- 異常: ノードのシャットダウン
- 異常: Kubeletソフトウェア障害
対処法: 予期せぬ再起動に耐えられるように設計されたアプリケーション(コンテナ)
- 異常: ノードのシャットダウン
- 異常: Kubeletソフトウェア障害
12 - トラブルシューティング
時には物事がうまくいかないこともあります。このガイドは、それらを正すことを目的としています。
2つのセクションから構成されています:
- Troubleshooting your application - Kubernetesにコードをデプロイしていて、なぜ動かないのか不思議に思っているユーザーに便利です。
- Troubleshooting your cluster - クラスター管理者やKubernetesクラスターに不満がある人に有用です。
また、使用しているリリースの既知の問題を確認する必要があります。
ヘルプを受けます
もしあなたの問題が上記のどのガイドでも解決されない場合は、Kubernetesコミュニティから助けを得るための様々な方法があります。
ご質問
本サイトのドキュメントは、様々な疑問に対する答えを提供するために構成されています。
Conceptsでは、Kubernetesのアーキテクチャーと各コンポーネントの動作について説明し、Setupでは、使い始めるための実用的な手順を提供しています。
Tasks は、よく使われるタスクの実行方法を示し、 Tutorialsは、実世界の業界特有、またはエンドツーエンドの開発シナリオ、より包括的なウォークスルーとなります。
Referenceセクションでは、Kubernetes API(/docs/reference/generated/kubernetes-api/v1.24/)とkubectlなどのコマンドラインインターフェース(CLI)に関する詳しいドキュメントが提供されています。
ヘルプ!私の質問はカバーされていません!今すぐ助けてください!
Stack Overflow
コミュニティの誰かがすでに同じような質問をしている可能性があり、あなたの問題を解決できるかもしれません。 KubernetesチームもKubernetesタグが付けられた投稿を監視しています。 もし役立つ既存の質問がない場合は、新しく質問してみてください。
Slack
Kubernetesコミュニティの多くの人々は、Kubernetes Slackの#kubernetes-usersチャンネルに集まっています。
Slackは登録が必要です。招待をリクエストすることができ、登録は誰でも可能です)。
お気軽にお越しいただき、何でも質問してください。
登録が完了したら、WebブラウザまたはSlackの専用アプリからKubernetes organization in Slackにアクセスします。
登録が完了したら、増え続けるチャンネルリストを見て、興味のある様々なテーマについて調べてみましょう。
たとえば、Kubernetesの初心者は、#kubernetes-noviceに参加してみるのもよいでしょう。
別の例として、開発者は#kubernetes-devチャンネルに参加するとよいでしょう。
また、多くの国別/言語別チャンネルがあります。これらのチャンネルに参加すれば、地域特有のサポートや情報を得ることができます。
| Country | Channels |
|---|---|
| 中国 | #cn-users, #cn-events |
| フィンランド | #fi-users |
| フランス | #fr-users, #fr-events |
| ドイツ | #de-users, #de-events |
| インド | #in-users, #in-events |
| イタリア | #it-users, #it-events |
| 日本 | #jp-users, #jp-events |
| 韓国 | #kr-users |
| オランダ | #nl-users |
| ノルウェー | #norw-users |
| ポーランド | #pl-users |
| ロシア | #ru-users |
| スペイン | #es-users |
| スウェーデン | #se-users |
| トルコ | #tr-users, #tr-events |
フォーラム
Kubernetesの公式フォーラムへの参加は大歓迎ですdiscuss.kubernetes.io。
バグと機能の要望
バグらしきものを発見した場合、または機能要望を出したい場合、GitHub課題追跡システムをご利用ください。 課題を提出する前に、既存の課題を検索して、あなたの課題が解決されているかどうかを確認してください。
バグを報告する場合は、そのバグを再現するための詳細な情報を含めてください。
- Kubernetes のバージョン:
kubectl version - クラウドプロバイダー、OSディストリビューション、ネットワーク構成、Dockerバージョン
- 問題を再現するための手順
13 - リソースメトリクスパイプライン
Kubernetesでは、コンテナのCPU使用率やメモリ使用率といったリソース使用量のメトリクスが、メトリクスAPIを通じて提供されています。これらのメトリクスは、ユーザーがkubectl topコマンドで直接アクセスするか、クラスター内のコントローラー(例えばHorizontal Pod Autoscaler)が判断するためにアクセスすることができます。
メトリクスAPI
メトリクスAPIを使用すると、指定したノードやPodが現在使用しているリソース量を取得することができます。 このAPIはメトリックの値を保存しないので、例えば10分前に指定されたノードが使用したリソース量を取得することはできません。
メトリクスAPIは他のAPIと何ら変わりはありません。
- 他のKubernetes APIと同じエンドポイントを経由して、
/apis/metrics.k8s.io/パスの下で発見できます。 - 同じセキュリティ、スケーラビリティ、信頼性の保証を提供します。
メトリクスAPIはk8s.io/metricsリポジトリで定義されています。 メトリクスAPIについての詳しい情報はそちらをご覧ください。
リソース使用量の測定
CPU
CPUは、一定期間の平均使用量をCPU coresという単位で報告されます。 この値は、カーネルが提供する累積CPUカウンターの比率を取得することで得られます(LinuxとWindowsの両カーネルで)。 kubeletは、比率計算のためのウィンドウを選択します。
メモリ
メモリは、測定値が収集された時点のワーキングセットとして、バイト単位で報告されます。 理想的な世界では、「ワーキングセット」は、メモリ不足で解放できない使用中のメモリ量です。 しかし、ワーキングセットの計算はホストOSによって異なり、一般に推定値を生成するために経験則を多用しています。 Kubernetesはスワップをサポートしていないため、すべての匿名(非ファイルバックアップ)メモリが含まれます。 ホストOSは常にそのようなページを再請求することができないため、メトリックには通常、一部のキャッシュされた(ファイルバックされた)メモリも含まれます。
メトリクスサーバー
メトリクスサーバーは、クラスター全体のリソース使用量データのアグリゲーターです。
デフォルトでは、kube-up.shスクリプトで作成されたクラスターにDeploymentオブジェクトとしてデプロイされます。
別のKubernetesセットアップ機構を使用する場合は、提供されるdeployment components.yamlファイルを使用してデプロイすることができます。
メトリクスサーバーは、Summary APIからメトリクスを収集します。
各ノードのKubeletからKubernetes aggregator経由でメインAPIサーバーに登録されるようになっています。
メトリクスサーバーについては、Design proposalsで詳しく解説しています。
Summary APIソース
Kubeletは、ノード、ボリューム、Pod、コンテナレベルの統計情報を収集し、Summary APIで省略して消費者が読めるようにするものです。
1.23以前は、これらのリソースは主にcAdvisorから収集されていました。しかし、1.23ではPodAndContainerStatsFromCRIフィーチャーゲートの導入により、コンテナとPodレベルの統計情報をCRI実装で収集することができます。
注意: これはCRI実装によるサポートも必要です(containerd >= 1.6.0, CRI-O >= 1.23.0)。
14 - リソース監視のためのツール
アプリケーションを拡張し、信頼性の高いサービスを提供するために、デプロイ時にアプリケーションがどのように動作するかを理解する必要があります。 コンテナ、Pod、Service、クラスター全体の特性を調べることにより、Kubernetesクラスターのアプリケーションパフォーマンスを調査することができます。 Kubernetesは、これらの各レベルでアプリケーションのリソース使用に関する詳細な情報を提供します。 この情報により、アプリケーションのパフォーマンスを評価し、ボトルネックを取り除くことで全体のパフォーマンスを向上させることができます。
Kubernetesでは、アプリケーションの監視は1つの監視ソリューションに依存することはありません。 新しいクラスターでは、リソースメトリクスまたはフルメトリクスパイプラインを使用してモニタリング統計を収集することができます。
リソースメトリクスパイプライン
リソースメトリックパイプラインは、Horizontal Pod Autoscalerコントローラーなどのクラスターコンポーネントや、kubectl topユーティリティに関連する限定的なメトリックセットを提供します。
これらのメトリクスは軽量、短期、インメモリーのmetrics-serverによって収集され、metrics.k8s.io APIを通じて公開されます。
metrics-serverはクラスター上のすべてのノードを検出し 各ノードのkubeletにCPUとメモリーの使用量を問い合わせます。
kubeletはKubernetesマスターとノードの橋渡し役として、マシン上で動作するPodやコンテナを管理する。 kubeletは各Podを構成するコンテナに変換し、コンテナランタイムインターフェースを介してコンテナランタイムから個々のコンテナ使用統計情報を取得します。この情報は、レガシーDocker統合のための統合cAdvisorから取得されます。
そして、集約されたPodリソース使用統計情報を、metrics-server Resource Metrics APIを通じて公開します。
このAPIは、kubeletの認証済みおよび読み取り専用ポート上の /metrics/resource/v1beta1 で提供されます。
フルメトリクスパイプライン
フルメトリクスパイプラインは、より豊富なメトリクスにアクセスすることができます。
Kubernetesは、Horizontal Pod Autoscalerなどのメカニズムを使用して、現在の状態に基づいてクラスターを自動的にスケールまたは適応させることによって、これらのメトリクスに対応することができます。
モニタリングパイプラインは、kubeletからメトリクスを取得し、custom.metrics.k8s.io または external.metrics.k8s.io APIを実装してアダプタ経由でKubernetesにそれらを公開します。
CNCFプロジェクトのPrometheusは、Kubernetes、ノード、Prometheus自身をネイティブに監視することができます。
CNCFに属さない完全なメトリクスパイプラインのプロジェクトは、Kubernetesのドキュメントの範囲外です。
15 - 監査
Kubernetesの監査はクラスター内の一連の行動を記録するセキュリティに関連した時系列の記録を提供します。 クラスターはユーザー、Kubernetes APIを使用するアプリケーション、 およびコントロールプレーン自体によって生成されたアクティビティなどを監査します。
監査により、クラスター管理者は以下の質問に答えることができます:
- 何が起きたのか?
- いつ起こったのか?
- 誰がそれを始めたのか?
- 何のために起こったのか?
- それはどこで観察されたのか?
- それはどこから始まったのか?
- それはどこへ向かっていたのか?
監査記録のライフサイクルはkube-apiserverコンポーネントの中で始まります。 各リクエストの実行の各段階で、監査イベントが生成されます。 ポリシーに従って前処理され、バックエンドに書き込まれます。 ポリシーが何を記録するかを決定し、 バックエンドがその記録を永続化します。現在のバックエンドの実装はログファイルやWebhookなどがあります。
各リクエストは関連する stage で記録されます。 定義されたステージは以下の通りです:
RequestReceived- 監査ハンドラーがリクエストを受信すると同時に生成されるイベントのステージ。 つまり、ハンドラーチェーンに委譲される前に生成されるイベントのステージです。ResponseStarted- レスポンスヘッダーが送信された後、レスポンスボディが送信される前のステージです。 このステージは長時間実行されるリクエスト(watchなど)でのみ発生します。ResponseComplete- レスポンスボディの送信が完了して、それ以上のバイトは送信されません。Panic- パニックが起きたときに発生するイベント。
監査ログ機能は、リクエストごとに監査に必要なコンテキストが保存されるため、APIサーバーのメモリー消費量が増加します。 メモリーの消費量は、監査ログ機能の設定によって異なります。
監査ポリシー
監査ポリシーはどのようなイベントを記録し、どのようなデータを含むべきかについてのルールを定義します。
監査ポリシーのオブジェクト構造は、audit.k8s.io API groupで定義されています。
イベントが処理されると、そのイベントは順番にルールのリストと比較されます。 最初のマッチングルールは、イベントの監査レベルを設定します。
定義されている監査レベルは:
None- ルールに一致するイベントを記録しません。Metadata- リクエストのメタデータ(リクエストしたユーザー、タイムスタンプ、リソース、動作など)を記録しますが、リクエストやレスポンスのボディは記録しません。Request- ログイベントのメタデータとリクエストボディは表示されますが、レスポンスボディは表示されません。 これは非リソースリクエストには適用されません。RequestResponse- イベントのメタデータ、リクエストとレスポンスのボディを記録しますが、 非リソースリクエストには適用されません。
audit-policy-fileフラグを使って、ポリシーを記述したファイルを kube-apiserverに渡すことができます。
このフラグが省略された場合イベントは記録されません。
監査ポリシーファイルでは、rulesフィールドが必ず指定されることに注意してください。
ルールがない(0)ポリシーは不当なものとして扱われます。
以下は監査ポリシーファイルの例です:
apiVersion: audit.k8s.io/v1 # This is required.
kind: Policy
# Don't generate audit events for all requests in RequestReceived stage.
omitStages:
- "RequestReceived"
rules:
# Log pod changes at RequestResponse level
- level: RequestResponse
resources:
- group: ""
# Resource "pods" doesn't match requests to any subresource of pods,
# which is consistent with the RBAC policy.
resources: ["pods"]
# Log "pods/log", "pods/status" at Metadata level
- level: Metadata
resources:
- group: ""
resources: ["pods/log", "pods/status"]
# Don't log requests to a configmap called "controller-leader"
- level: None
resources:
- group: ""
resources: ["configmaps"]
resourceNames: ["controller-leader"]
# Don't log watch requests by the "system:kube-proxy" on endpoints or services
- level: None
users: ["system:kube-proxy"]
verbs: ["watch"]
resources:
- group: "" # core API group
resources: ["endpoints", "services"]
# Don't log authenticated requests to certain non-resource URL paths.
- level: None
userGroups: ["system:authenticated"]
nonResourceURLs:
- "/api*" # Wildcard matching.
- "/version"
# Log the request body of configmap changes in kube-system.
- level: Request
resources:
- group: "" # core API group
resources: ["configmaps"]
# This rule only applies to resources in the "kube-system" namespace.
# The empty string "" can be used to select non-namespaced resources.
namespaces: ["kube-system"]
# Log configmap and secret changes in all other namespaces at the Metadata level.
- level: Metadata
resources:
- group: "" # core API group
resources: ["secrets", "configmaps"]
# Log all other resources in core and extensions at the Request level.
- level: Request
resources:
- group: "" # core API group
- group: "extensions" # Version of group should NOT be included.
# A catch-all rule to log all other requests at the Metadata level.
- level: Metadata
# Long-running requests like watches that fall under this rule will not
# generate an audit event in RequestReceived.
omitStages:
- "RequestReceived"
最小限の監査ポリシーファイルを使用して、すべてのリクエストを Metadataレベルで記録することができます。
# Log all requests at the Metadata level.
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
- level: Metadata
独自の監査プロファイルを作成する場合は、Google Container-Optimized OSの監査プロファイルを出発点として使用できます。 監査ポリシーファイルを生成するconfigure-helper.shスクリプトを確認することができます。 スクリプトを直接見ることで、監査ポリシーファイルのほとんどを見ることができます。
また、定義されているフィールドの詳細については、Policy` configuration referenceを参照できます。
監査バックエンド
監査バックエンドは監査イベントを外部ストレージに永続化します。 kube-apiserverには2つのバックエンドが用意されています。
- イベントをファイルシステムに書き込むログバックエンド
- 外部のHTTP APIにイベントを送信するWebhookバックエンド
いずれの場合も、監査イベントはKubernetes APIaudit.k8s.io API groupで定義されている構造に従います。
パッチの場合、リクエストボディはパッチ操作を含むJSON配列であり、適切なKubernetes APIオブジェクトを含むJSONオブジェクトではありません。
例えば、以下のリクエストボディは/apis/batch/v1/namespaces/some-namespace/jobs/some-job-nameに対する有効なパッチリクエストです。
[
{
"op": "replace",
"path": "/spec/parallelism",
"value": 0
},
{
"op": "remove",
"path": "/spec/template/spec/containers/0/terminationMessagePolicy"
}
]
ログバックエンド
ログバックエンドは監査イベントをJSONlines形式のファイルに書き込みます。
以下の kube-apiserver フラグを使ってログ監査バックエンドを設定できます。
--audit-log-pathは、ログバックエンドが監査イベントを書き込む際に使用するログファイルのパスを指定します。 このフラグを指定しないと、ログバックエンドは無効になります。-は標準出力を意味します。--audit-log-maxageは、古い監査ログファイルを保持する最大日数を定義します。audit-log-maxbackupは、保持する監査ログファイルの最大数を定義します。--audit-log-maxsizeは、監査ログファイルがローテーションされるまでの最大サイズをメガバイト単位で定義します。
クラスターのコントロールプレーンでkube-apiserverをPodとして動作させている場合は、監査記録が永久化されるように、ポリシーファイルとログファイルの場所にhostPathをマウントすることを忘れないでください。
例えば:
--audit-policy-file=/etc/kubernetes/audit-policy.yaml \
--audit-log-path=/var/log/audit.log
それからボリュームをマウントします:
...
volumeMounts:
- mountPath: /etc/kubernetes/audit-policy.yaml
name: audit
readOnly: true
- mountPath: /var/log/audit.log
name: audit-log
readOnly: false
最後にhostPathを設定します:
...
volumes:
- name: audit
hostPath:
path: /etc/kubernetes/audit-policy.yaml
type: File
- name: audit-log
hostPath:
path: /var/log/audit.log
type: FileOrCreate
Webhookバックエンド
Webhook監査バックエンドは、監査イベントをリモートのWeb APIに送信しますが、 これは認証手段を含むKubernetes APIの形式であると想定されます。
Webhook監査バックエンドを設定するには、以下のkube-apiserverフラグを使用します。
--audit-webhook-config-fileは、Webhookの設定ファイルのパスを指定します。 webhookの設定は、事実上特化したkubeconfigです。--audit-webhook-initial-backoffは、最初に失敗したリクエストの後、再試行するまでに待つ時間を指定します。 それ以降のリクエストは、指数関数的なバックオフで再試行されます。
Webhookの設定ファイルは、kubeconfig形式でサービスのリモートアドレスと接続に使用する認証情報を指定します。
イベントバッチ
ログバックエンドとwebhookバックエンドの両方がバッチ処理をサポートしています。
webhookを例に、利用可能なフラグの一覧を示します。
ログバックエンドで同じフラグを取得するには、フラグ名のwebhookをlogに置き換えてください。
デフォルトでは、バッチングはwebhookでは有効で、logでは無効です。
同様に、デフォルトではスロットリングは webhook で有効で、logでは無効です。
--audit-webhook-modeは、バッファリング戦略を定義します。以下のいずれかとなります。batch- イベントをバッファリングして、非同期にバッチ処理します。これがデフォルトです。blocking- 個々のイベントを処理する際に、APIサーバーの応答をブロックします。blocking-strict- blockingと同じですが、RequestReceivedステージでの監査ログに失敗した場合は RequestReceivedステージで監査ログに失敗すると、kube-apiserverへのリクエスト全体が失敗します。
以下のフラグは batch モードでのみ使用されます:
--audit-webhook-batch-buffer-sizeは、バッチ処理を行う前にバッファリングするイベントの数を定義します。 入力イベントの割合がバッファをオーバーフローすると、イベントはドロップされます。--audit-webhook-batch-max-sizeは、1つのバッチに入れるイベントの最大数を定義します。--audit-webhook-batch-max-waitは、キュー内のイベントを無条件にバッチ処理するまでの最大待機時間を定義します。--audit-webhook-batch-throttle-qpsは、1秒あたりに生成されるバッチの最大平均数を定義します。--audit-webhook-batch-throttle-burstは、許可された QPS が低い場合に、同じ瞬間に生成されるバッチの最大数を定義します。
パラメーターチューニング
パラメーターは、APIサーバーの負荷に合わせて設定してください。
例えば、kube-apiserverが毎秒100件のリクエストを受け取り、それぞれのリクエストがResponseStartedとResponseCompleteの段階でのみ監査されるとします。毎秒≅200の監査イベントが発生すると考えてください。
1つのバッチに最大100個のイベントがあるの場合、スロットリングレベルを少なくとも2クエリ/秒に設定する必要があります。
バックエンドがイベントを書き込むのに最大で5秒かかる場合、5秒分のイベントを保持するようにバッファーサイズを設定する必要があります。
10バッチ、または1000イベントとなります。
しかし、ほとんどの場合デフォルトのパラメーターで十分であり、手動で設定する必要はありません。 kube-apiserverが公開している以下のPrometheusメトリクスや、ログを見て監査サブシステムの状態を監視することができます。
apiserver_audit_event_totalメトリックには、エクスポートされた監査イベントの合計数が含まれます。apiserver_audit_error_totalメトリックには、エクスポート中にエラーが発生してドロップされたイベントの総数が含まれます。
ログエントリー・トランケーション
logバックエンドとwebhookバックエンドは、ログに記録されるイベントのサイズを制限することをサポートしています。
例として、logバックエンドで利用可能なフラグの一覧を以下に示します
audit-log-truncate-enabledイベントとバッチの切り捨てを有効にするかどうかです。audit-log-truncate-max-batch-sizeバックエンドに送信されるバッチのバイト単位の最大サイズ。audit-log-truncate-max-event-sizeバックエンドに送信される監査イベントのバイト単位の最大サイズです。
デフォルトでは、webhookとlogの両方で切り捨ては無効になっていますが、クラスター管理者は audit-log-truncate-enabledまたはaudit-webhook-truncate-enabledを設定して、この機能を有効にする必要があります。
次の項目
16 - 実行中のPodのデバッグ
このページでは、ノード上で動作している(またはクラッシュしている)Podをデバッグする方法について説明します。
始める前に
あなたのPodは既にスケジュールされ、実行されているはずです。Pod がまだ実行されていない場合は、Troubleshoot Applications から始めてください。
いくつかの高度なデバッグ手順では、Podがどのノードで動作しているかを知り、そのノードでコマンドを実行するためのシェルアクセス権を持っていることが必要です。
kubectlを使用する標準的なデバッグ手順の実行には、そのようなアクセスは必要ではありません。
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}
-c ${CONTAINER_NAME}は省略可能です。コンテナを1つだけ含むPodの場合は省略できます。例として、実行中のCassandra Podからログを見るには、次のように実行します。
kubectl exec cassandra -- cat /var/log/cassandra/system.log
例えばkubectl execの-iと-t引数を使って、端末に接続されたシェルを実行することができます。
kubectl exec -it cassandra -- sh
詳しくは、実行中のコンテナのシェルを取得するを参照してください。
エフェメラルコンテナによるデバッグ
Kubernetes v1.23 [beta]エフェメラルコンテナは、コンテナがクラッシュしたり、コンテナイメージにデバッグユーティリティが含まれていないなどの理由でkubectl execが不十分な場合に、対話的にトラブルシューティングを行うのに便利です(ディストロ・イメージの場合など)。
エフェメラルコンテナを使用したデバッグ例
実行中のPodにエフェメラルコンテナを追加するには、kubectl debugコマンドを使用することができます。
まず、サンプル用のPodを作成します。
kubectl run ephemeral-demo --image=k8s.gcr.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 --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でprocess namespace sharingを有効にしないため、指定する必要があります。
target パラメーターは Container Runtime でサポートされている必要があります。サポートされていない場合、エフェメラルコンテナは起動されないか、psが他のコンテナ内のプロセスを表示しないように孤立したプロセス名前空間を使用して起動されます。新しく作成されたエフェメラルコンテナの状態は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 --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:/#
kubectl debugは--containerフラグでコンテナ名を選択しない場合、自動的にコンテナ名を生成します。iフラグを指定すると、デフォルトでkubectl debugが新しいコンテナにアタッチされます。これを防ぐには、--attach=falseを指定します。セッションが切断された場合は、kubectl attachを使用して再接続することができます。share-processesを指定すると、Pod 内のコンテナからプロセスを参照することができます。この仕組みについて詳しくは、Share Process Namespace between Containers in a Podを参照してください。
デバッグが終わったら、Podの後始末をするのを忘れないでください。
kubectl delete pod myapp myapp-debug
Podのコマンドを変更しながらコピーします
デバッグフラグを追加するためや、アプリケーションがクラッシュするためなど、コンテナのコマンドを変更すると便利な場合があります。
アプリケーションのクラッシュをシミュレートするには、kubectl runを使用して、すぐに終了するコンテナを作成します。
kubectl run --image=busybox 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.
/ #
これで、ファイルシステムのパスのチェックやコンテナコマンドの手動実行などのタスクを実行するために使用できる対話型シェルが完成しました。
特定のコンテナのコマンドを変更するには、そのコンテナ名を
--containerで指定する必要があり、そうしないとkubectl debugが代わりに指定したコマンドを実行する新しいコンテナを作成します。iフラグは、デフォルトでkubectl debugがコンテナにアタッチされるようにします。これを防ぐには、--attach=falseを指定します。セッションが切断された場合は、kubectl attachを使用して再接続することができます。
デバッグが終わったら、Podの後始末をするのを忘れないでください。
kubectl delete pod myapp myapp-debug
コンテナイメージを変更してPodをコピーします
状況によっては、動作不良のPodを通常のプロダクション用のイメージから、デバッグ・ビルドや追加ユーティリティを含むイメージに変更したい場合があります。
例として、kubectl runを使用してPodを作成します。
kubectl run myapp --image=busybox --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 の名前を自動的に生成します。- コンテナはホストのIPC、Network、PIDネームスペースで実行されます。
- ノードのルートファイルシステムは
/hostにマウントされます。
デバッグが終わったら、Podの後始末をするのを忘れないでください。
kubectl delete pod node-debugger-mynode-pdx84
17 - 実行中のコンテナへのシェルを取得する
このページはkubectl execを使用して実行中のコンテナへのシェルを取得する方法を説明します。
始める前に
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
バージョンを確認するには次のコマンドを実行してください:kubectl version.コンテナへのシェルの取得
このエクササイズでは、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
-- はコマンドに渡す引数とkubectlの引数を分離します。シェル内で、ルートディレクトリーのファイル一覧を表示します:
# このコマンドをコンテナ内で実行します
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-app と helper-app という2つのコンテナを持つとします。
以下のコマンドは main-app のコンテナへのシェルを開きます。
kubectl exec -i -t my-pod --container main-app -- /bin/bash
-iと-tは、ロングオプションの--stdinと--ttyと同様です。次の項目
- kubectl execについて読む