これは、このセクションの複数ページの印刷可能なビューです。 印刷するには、ここをクリックしてください.
監視、ログ、デバッグ
- 1: crictlによるKubernetesノードのデバッグ
- 2: Initコンテナのデバッグ
- 3: PodとReplicationControllerのデバッグ
- 4: Pod障害の原因を特定する
- 5: Serviceのデバッグ
- 6: StatefulSetのデバッグ
- 7: アプリケーションのトラブルシューティング
- 8: アプリケーションの自己観察とデバッグ
- 9: リソースメトリクスパイプライン
- 10: リソース監視のためのツール
- 11: ローカルでのサービス開発・デバッグ
- 12: 実行中のコンテナへのシェルを取得する
- 13: 監査
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:141c253bc4c3fd0a201d32dc1f493bcf3fff003b6df416dea4f41046e0f37d47
-
Podとコンテナのコンフィグを作成します:
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.yaml
YAMLファイルの
command
フィールドとargs
フィールドで、コンテナが10秒間スリープしてから/dev/termination-log
ファイルに「Sleep expired」と書いているのがわかります。コンテナが「Sleep expired」メッセージを書き込んだ後、コンテナは終了します。 -
Podに関する情報を表示します:
kubectl get pod termination-demo
Podが実行されなくなるまで、上記のコマンドを繰り返します。
-
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 - リソースメトリクスパイプライン
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)。
10 - リソース監視のためのツール
アプリケーションを拡張し、信頼性の高いサービスを提供するために、デプロイ時にアプリケーションがどのように動作するかを理解する必要があります。 コンテナ、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のドキュメントの範囲外です。
11 - ローカルでのサービス開発・デバッグ
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をご覧ください。
12 - 実行中のコンテナへのシェルを取得する
このページは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について読む
13 - 監査
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
を設定して、この機能を有効にする必要があります。