Certified Kubernetes Application Developer (CKAD) #12 オブザーバビリティ: logging、kubectl debug、port-forward、ephemeral container

#11 Probes では、liveness と readiness でアプリの健康状態をクラスタに知らせる方法を身につけました。ところが probe が失敗したり Pod が再起動を繰り返したりするとき、その中で 何が起きているのか を直接覗き込まないと原因は見つかりません。CKAD 試験でオブザーバビリティ (observability) は比重が 15% のドメインですが、他のすべての問題を解いていて行き詰まったときに必ず通る要所でもあります。

この記事では、アプリが正しく動かないときに取り出すツールをコマンド中心に整理します。ログを読み、状態とイベントを確認し、コンテナの中に入り、ポートをローカルへ引き寄せ、シェルのないコンテナまでデバッグする順序で進めます。

ログ: 最初に見る場所 #

アプリがおかしいとき、最初に見るのがログです。コンテナが標準出力 (stdout) と標準エラー (stderr) へ出した内容を kubectl logs がそのまま見せてくれます。

# 基本のログ
k logs mypod

# リアルタイムで追う (-f = follow)
k logs -f mypod

# 最後の 50 行だけ
k logs mypod --tail=50

# 直近 10 分ぶんだけ
k logs mypod --since=10m

-f はログをリアルタイムで追い、アプリがリクエストを処理する間に何を出力するかを見守るときに使います。--tail--since はログが長いときに必要な部分だけを切り出して見せてくれます。

再起動したコンテナの以前のログ #

Pod が CrashLoopBackOff に陥ったなら、今上がっているコンテナのログではなく 死ぬ直前のコンテナのログ を見ないと原因は出てきません。このとき --previous を使います。

# 直前に終了したコンテナのログ
k logs mypod --previous

# 短くは -p
k logs mypod -p

クラッシュを繰り返す Pod をデバッグするとき、--previous は実技でよく使うオプションです。現在のコンテナは起動したばかりでログが空になっていることが多いからです。

マルチコンテナ Pod のログ #

1 つの Pod にコンテナが複数あるなら、どのコンテナのログかを -c で指定する必要があります。指定しないとコンテナを選ぶよう求めるエラーが出ます。

# 特定のコンテナだけ
k logs mypod -c sidecar

# すべてのコンテナを一度に
k logs mypod --all-containers=true

# ラベルで複数の Pod のログを同時に
k logs -l app=web --all-containers=true --tail=20

--all-containers は Pod 内のすべてのコンテナのログをまとめて見せ、-l でラベルを与えると、そのラベルを持つ複数の Pod のログを一度に追えます。

状態とイベント: ログに出ない原因 #

ログはコンテナが 実行され始めた後 の話です。イメージプル失敗、スケジューリング失敗、probe 失敗のように、コンテナが上がる前やクラスタ次元で起きた問題はログに出ません。このときは describe と events を見ます。

# Pod の詳細な状態と最近のイベント
k describe pod mypod

k describe pod の出力の一番下にある Events セクションが核心です。Failed to pull imageLiveness probe failedInsufficient memory のようなメッセージがここにそのまま出ます。コンテナの StateLast StateExit CodeReason も合わせて読んでおきます。

# ネームスペース全体のイベントを時系列で
k get events --sort-by=.lastTimestamp
# 特定の Pod のイベントだけ
k get events --field-selector involvedObject.name=mypod

--sort-by=.lastTimestamp を付けるとイベントが最新順に並び、たった今何が起きたかが一目で分かります。ソートしないと順序が入り混じって読みづらくなります。

オブジェクトの実際の定義の確認 #

マニフェストが意図どおり適用されたか確信が持てないときは、クラスタに保存された実際のオブジェクトを YAML で取り出してみます。

# 適用された定義全体を YAML で
k get pod mypod -o yaml

# 特定のフィールドだけ jsonpath で (イメージ、状態フェーズなど)
k get pod mypod -o jsonpath='{.spec.containers[*].image}'
k get pod mypod -o jsonpath='{.status.phase}'

-o yaml はデフォルト値やコントローラが埋めたフィールドまですべて見せてくれるので、自分が書いたマニフェストと実際の適用結果の差を確認するときに役立ちます。

コンテナの中に入る #

ログと状態でも原因がつかめないなら、コンテナの中に入って直接確認します。kubectl exec で実行中のコンテナの中でコマンドを実行します。

# 対話型シェルを開く (-it = interactive + tty)
k exec -it mypod -- sh

# 一行コマンドだけ実行
k exec mypod -- env
k exec mypod -- cat /etc/config/app.conf

# マルチコンテナなら -c でコンテナを指定
k exec -it mypod -c sidecar -- sh

-- の後ろに実行するコマンドを置きます。シェルを開く代わりに、env で環境変数を確認したり cat でマウントされた設定ファイルを読んだりと、一行コマンドだけ投げる方が速いことが多いです。コンテナに bash がなければ sh で開きます。中では通常、環境変数が ConfigMap・Secret から正しく注入されたか (env)、マウントされた volume が期待したパスにあるか (lscat)、他の Service に届くか (wget -qO- http://svc:80nslookup svc) を確認します。

ポートフォワーディング: ローカルから直接テスト #

クラスタ内部の Pod や Service に外部公開なしでアクセスしてみたいときは kubectl port-forward を使います。ローカルポートへ入ってきたリクエストを対象までそのまま転送します。

# Pod の 80 番ポートをローカルの 8080 へ
k port-forward pod/mypod 8080:80

# Service を対象にもできる
k port-forward svc/web 8080:80

# Deployment を対象にするとその背後の Pod 1 つへ接続
k port-forward deploy/web 8080:80

こうして立ち上げておき、別のターミナルから curl http://localhost:8080 でレスポンスを確認します。Service の selector や targetPort が間違っていてトラフィックが届かないのか、それともアプリ自体が応答できないのかを切り分けるときに役立ちます。port-forward はコマンドが立ち上がっている間だけ維持されます。

ephemeral container: シェルのないコンテナのデバッグ #

最近の運用イメージはセキュリティとサイズのために、distroless のようにシェルもデバッグツールもない形が多いです。こうしたコンテナには k exec -- sh が通じません。シェル自体がないからです。このとき kubectl debugephemeral container を付けます。

ephemeral container は実行中の Pod に一時的に追加されるコンテナです。元のコンテナはそのままにし、ツールの入った別のイメージを同じ Pod に差し込んで一緒に覗き込みます。

# busybox を一時コンテナとして付けてシェルを開く
k debug -it mypod --image=busybox

# --target で対象コンテナのプロセスネームスペースを共有
k debug -it mypod --image=busybox --target=app

--target=app は ephemeral container に app という元のコンテナのプロセスネームスペースを共有させます。すると一時コンテナの中から元のコンテナのプロセス (ps) やファイルを覗けるので、シェルのないコンテナもデバッグできます。元を触らずに複製の上で実験するなら、--copy-to=mypod-debug で複製を作ってデバッグします。

ノードのデバッグ #

Pod ではなくノード自体を覗き込む必要があるときは、ノードにデバッグ Pod を立ち上げます。

# ノードのファイルシステムを /host にマウントしたデバッグ Pod
k debug node/node01 -it --image=busybox

このコマンドはノードのファイルシステムをコンテナの /host の下に付けてくれるので、ノードのログや設定ファイルを直接確認できます。

リソース使用量を見る #

Pod が OOMKilled で死んだり遅くなったりするときは、CPU・メモリの使用量を見る必要があります。kubectl top がリアルタイムの使用量を見せてくれます。

# Pod ごとの使用量 (--containers でコンテナ単位まで)
k top pod
k top pod mypod --containers

# ノードごとの使用量
k top node

k top はクラスタに metrics-server がインストールされていないと動作しません。なければ Metrics API not available エラーが出ます。実技環境には通常 metrics-server が用意されていますが、自分で立てたローカルクラスタでは別途インストールする必要があります。使用量が limits に達して throttle されるか OOM で死ぬかを判断するとき、k top pod が出発点になります。

トラブルシューティングの流れの整理 #

ツールを個別に覚えるより、症状から始まる順序 で身につける方が試験で速くなります。

  1. 症状の確認: k get pod で状態を見ます。PendingImagePullBackOffCrashLoopBackOffRunning だが READY 0/1 など何なのかを把握します。
  2. describe: k describe pod mypodEvents とコンテナの StateExit Code を読みます。スケジューリング・イメージ・probe の問題は大抵ここで明らかになります。
  3. logs: コンテナが上がっていれば k logs mypod でアプリのログを見ます。再起動中なら --previous で直前のログを見ます。
  4. exec / debug: ログでもつかめないなら k exec -it mypod -- sh で中から環境変数・ファイル・接続を確認します。シェルがなければ k debug で ephemeral container を付けます。
  5. port-forward / top: ネットワーク経路は k port-forward で、リソース限界は k top で絞り込みます。

各ステップは前のステップで原因が出ないときだけ次へ進みます。ほとんどの問題は 2 番目の describe と 3 番目の logs で終わります。

試験ポイント #

  • --previous はクラッシュデバッグの核心 です。CrashLoopBackOff の Pod は現在のコンテナのログが空なので、直前のログを見ます。
  • マルチコンテナには -c が必須 です。指定しないとエラーが出るか、最初のコンテナだけが選ばれます。
  • k get events --sort-by=.lastTimestamp でイベントを時系列に並べ、たった今起きたことを素早く見つけます。
  • k debug --image=... --target=... の形を覚えます。distroless のようにシェルのないコンテナは exec で入れず、ephemeral container でデバッグします。
  • k port-forward の対象表記 (pod/svc/deploy/) と ローカル:対象 のポート順序を混同しません。
  • k top は metrics-server に依存 することを覚えます。動かないなら、ツールではなく環境の問題かもしれません。
  • describe と logs で 90% が終わります。行き詰まったら真っ先にこの 2 つのコマンドを打ちます。

オブザーバビリティをより広い運用の文脈で見たいなら、K8s 実務トラックのトラブルシューティング編 でクラスタ次元の診断まで一緒に扱います。

まとめ #

この記事で押さえたこと:

  • ログk logs-f--previous-c--tail--since--all-containers で状況別のログを選んで見ます。
  • 状態とイベントk describe podEventsk get events --sort-by=.lastTimestampk get pod -o yaml でログに出ない原因を見つけます。
  • 中に入るk exec -it -- sh と一行コマンドで環境変数・ファイル・接続を確認します。
  • ポートフォワーディングk port-forward で公開なしにローカルから直接レスポンスをテストします。
  • ephemeral containerk debug --image=... --target=... でシェルのないコンテナやノードまでデバッグします。
  • リソース使用量k top podk top node で CPU・メモリを見ます (metrics-server が必要)。
  • 流れ。症状の確認 → describe → logs → exec/debug → port-forward/top の順で絞り込みます。

次: ConfigMap と Secret の深掘り #

アプリを覗き込むツールはそろいました。ここから、そのアプリに 設定と秘密の値を注入する 最大のドメインに入ります。

#13 ConfigMap と Secret の深掘り: volume vs env、自動更新 では、ConfigMap と Secret を環境変数として入れるときと volume としてマウントするときの違い、volume マウントが値の変更を自動で反映する仕組み、Secret のエンコーディングとタイプ、そして試験によく出る注入形式まで、自分で作りながら整理します。

X