Kubernetes入門
第11回:トラブルシューティングの作法
連載最終回となる本稿では、K8s特有の「ステータス異常」を体系的に理解し、4種の神器(get / describe / logs / events) を駆使してトラブルを切り分けるスキルを身につけます。そして最後に、全11回を走破したあなたに、次のステップへの道標を示します。
本稿の実行環境について
本稿は2つのパートで構成されています。
- 11.1 診断セクション:概念理解のための架空の出力例を使用しています。
- 11.2 実践セクション:第1回で構築したkindクラスタ上で、実際に手を動かして追体験できるハンズオン演習です。
11.2以降を実行する場合は、kindクラスタが起動していることを確認してください。
11.1 診断:K8s特有のステータス異常を読み解く
11.1.1 「なぜ動かない?」を可視化する:ステータス欄が教えるヒント
VMの世界では、仮想マシンの状態は比較的シンプルでした。「起動中」「停止」「一時停止」「異常」——せいぜいこの程度です。vSphere Clientを開けば、赤い警告アイコンが目に飛び込んできて、「あ、こいつが死んでるな」と一目で分かりました。
Kubernetesも、実は同じ思想で設計されています。ただし、可視化の粒度がはるかに細かいのです。
[Execution User: developer]
kubectl get pods
実行結果:
NAME READY STATUS RESTARTS AGE
web-server-7d8f9b6c5-abc12 1/1 Running 0 2d
api-gateway-5f4d3c2b1-xyz99 0/1 CrashLoopBackOff 127 (5m ago) 1d
batch-job-8e7f6d5c4-def34 0/1 ImagePullBackOff 0 3h
scheduler-9a8b7c6d5-ghi56 0/1 Pending 0 45m
この出力を見て、VMエンジニアのあなたはどう感じるでしょうか?
Running は分かる。Pending は「保留中」だから、まだ起動していないのだろう。でも CrashLoopBackOff とは何だ?ImagePullBackOff は?——そう思うのは当然です。
ここで重要なのは、K8sのステータスは「現在の状態」だけでなく「何を試みて失敗したか」まで教えてくれるということです。VMで言えば、「起動失敗」というステータスだけでなく、「BIOSは通過したがブートローダーで停止」「OSカーネルのロード中にパニック」といった詳細が、最初から表示されているようなものです。
ステータスの読み方:3つのカテゴリ
K8sのPodステータスは、大きく3つのカテゴリに分類できます。
| カテゴリ | 代表的なステータス | VMでの類似状況 |
|---|---|---|
| スケジューリング待ち | Pending | vMotion先のホストが見つからない |
| イメージ取得失敗 | ImagePullBackOff, ErrImagePull | ISOマウント失敗、テンプレート破損 |
| コンテナ起動失敗 | CrashLoopBackOff, Error | ゲストOSのブート失敗、アプリクラッシュ |
VMの経験があれば、この対応表を見るだけで「ああ、あの感覚か」と腑に落ちるはずです。
11.1.2 死因ランキング:CrashLoopBackOff, ImagePullBackOff, Pending の正体
現場で遭遇する頻度の高い「死因」を、ランキング形式で解説します。
第1位:CrashLoopBackOff(墜落と再起動の無限ループ)
意味: コンテナは起動できたが、何らかの理由ですぐに終了(クラッシュ)し、K8sが再起動を試み、また失敗し……を繰り返している状態。
VMでの類似状況: ゲストOSは起動するが、起動直後にアプリケーションがクラッシュしてサービスが使えない。自動再起動を設定しているため、何度も再起動がかかる。
よくある原因:
- アプリケーションの設定ミス(DB接続先が間違っている等)
- 必要な環境変数が設定されていない
- メモリ不足でOOMKilled(Out Of Memory)
- ヘルスチェック(Liveness Probe)の設定が厳しすぎる
切り分けの第一歩: kubectl logs <pod-name> でアプリケーションのログを確認。
第2位:ImagePullBackOff(イメージが取得できない)
意味: 指定されたコンテナイメージをレジストリから取得できず、バックオフ(待機時間を延ばしながら再試行)している状態。
VMでの類似状況: vSphereでテンプレートからデプロイしようとしたら、「テンプレートが見つかりません」エラー。あるいは、ISOイメージのマウントに失敗。
よくある原因:
- イメージ名のタイポ(
nginx:latesttなど) - プライベートレジストリの認証情報(ImagePullSecrets)が設定されていない
- レジストリへのネットワーク疎通がない
- 指定したタグが存在しない
切り分けの第一歩: kubectl describe pod <pod-name> でEventsセクションを確認。具体的なエラーメッセージが記載されている。
第3位:Pending(配置先が見つからない)
意味: Podをどのノードに配置するか決められず、待機している状態。
VMでの類似状況: DRS(Distributed Resource Scheduler)が「このVMを配置できるホストがありません」と言っている。リソースプールの制約、アフィニティルール、ストレージの空き容量不足など。
よくある原因:
- リソース不足(CPU/メモリの
requestsがどのノードでも満たせない) nodeSelectorやaffinityで指定した条件に合うノードがない- PersistentVolumeClaim(PVC)がバインドされていない
- Taint(汚染マーク)が設定されたノードに対するToleration(許容設定)がない
切り分けの第一歩: kubectl describe pod <pod-name> のEventsセクションで、スケジューラーからのメッセージを確認。
11.1.3 インフラの視点:Podが「Node」に配置されないときのチェック項目
Pending 状態が続くとき、VMエンジニアの視点が最も活きるのがここです。本質的には「リソースの空きがあるホストを探す」という、DRSと同じ仕事をK8sのスケジューラーが行っています。
チェックリスト:Pending の原因切り分け
1. ノードの状態を確認する
[Execution User: developer]
kubectl get nodes
実行結果:
NAME STATUS ROLES AGE VERSION
kind-control-plane Ready control-plane 7d v1.32.0
kind-worker Ready <none> 7d v1.32.0
kind-worker2 Ready <none> 7d v1.32.0
全ノードが Ready であることを確認。NotReady のノードがあれば、そこにPodは配置されません。
2. ノードのリソース状況を確認する
[Execution User: developer]
kubectl describe node kind-worker | grep -A 10 "Allocated resources"
実行結果:
Allocated resources:
(Total limits may be over 100 percent, i.e., overcommitted.)
Resource Requests Limits
-------- -------- ------
cpu 1900m (95%) 3000m (150%)
memory 1800Mi (90%) 2500Mi (125%)
ephemeral-storage 0 (0%) 0 (0%)
95% のCPUが既に予約されている! 新しいPodがCPUを requests: 200m で要求しても、配置できません。
3. PodのEvents(イベント)を確認する
[Execution User: developer]
kubectl describe pod scheduler-9a8b7c6d5-ghi56 | grep -A 20 "Events:"
実行結果:
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 45m default-scheduler 0/3 nodes are available:
1 node(s) had untolerated taint {node-role.kubernetes.io/control-plane: },
2 node(s) had insufficient memory.
ここに答えが書いてあります。「コントロールプレーンにはTaintがあり配置できない」「残り2ノードはメモリ不足」——。VMのリソースプール制約と同じ感覚で理解できるはずです。
11.2 実践:4種の神器(get/describe/logs/events)を使い倒す
ここからは、意図的に「壊れた」環境を作り、4つのコマンドを駆使してトラブルを特定・修正する実践演習を行います。
準備:問題のあるマニフェストを適用する
まず、いくつかの「地雷」を仕込んだマニフェストを作成します。
[Execution User: developer]
cat << 'EOF' > ~/broken-manifests.yaml
---
# 問題1: イメージ名のタイポ
apiVersion: v1
kind: Pod
metadata:
name: broken-image
namespace: default
spec:
containers:
- name: nginx
image: nginx:latestt # 存在しないタグ
ports:
- containerPort: 80
---
# 問題2: 環境変数の欠落によるアプリクラッシュ
apiVersion: v1
kind: Pod
metadata:
name: broken-env
namespace: default
spec:
containers:
- name: demo-app
image: busybox:1.36
command: ["/bin/sh", "-c"]
args:
- |
if [ -z "$REQUIRED_CONFIG" ]; then
echo "ERROR: REQUIRED_CONFIG is not set!" >&2
exit 1
fi
echo "Config: $REQUIRED_CONFIG"
sleep 3600
# REQUIRED_CONFIG 環境変数が設定されていない!
---
# 問題3: 過大なリソース要求
apiVersion: v1
kind: Pod
metadata:
name: broken-resources
namespace: default
spec:
containers:
- name: resource-hog
image: nginx:1.27
resources:
requests:
memory: "128Gi" # 128GB!? そんなノードはない
cpu: "64" # 64コア!?
EOF
これらを適用します。
[Execution User: developer]
kubectl apply -f ~/broken-manifests.yaml
実行結果:
pod/broken-image created
pod/broken-env created
pod/broken-resources created
30秒ほど待ってから、状況を確認しましょう。
11.2.1 まずは kubectl get pods:異変の兆候を素早く掴む
[Execution User: developer]
kubectl get pods
実行結果:
NAME READY STATUS RESTARTS AGE
broken-env 0/1 CrashLoopBackOff 3 (12s ago) 45s
broken-image 0/1 ImagePullBackOff 0 45s
broken-resources 0/1 Pending 0 45s
見事に3種類の「死因」が揃いました。VMの管理画面で赤いアイコンが3つ並んでいるのと同じ状況です。
ここでのポイントは、get pods は「一覧表示」であり「詳細診断」ではないということ。vSphere Clientでサマリー画面を見ているようなものです。何かがおかしいことは分かるが、原因までは分からない。
次のステップに進みましょう。
11.2.2 kubectl describe:K8sからの「公式な診断書」を読み解く術
kubectl describe は、K8sがそのリソースについて知っているすべての情報を、人間が読める形式で出力します。VMで言えば、vCenterの「イベント」タブと「設定」タブを合体させたようなものです。
ケース1:ImagePullBackOff の診断
[Execution User: developer]
kubectl describe pod broken-image
出力は長いですが、最も重要なのは末尾の Events セクションです。
実行結果(Eventsセクション抜粋):
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 2m10s default-scheduler Successfully assigned default/broken-image to kind-worker
Normal Pulling 45s (x4 over 2m) kubelet Pulling image "nginx:latestt"
Warning Failed 44s (x4 over 2m) kubelet Failed to pull image "nginx:latestt":
rpc error: code = NotFound desc = failed to pull and unpack image
"docker.io/library/nginx:latestt": failed to resolve reference
"docker.io/library/nginx:latestt": docker.io/library/nginx:latestt: not found
Warning Failed 44s (x4 over 2m) kubelet Error: ErrImagePull
Normal BackOff 32s (x5 over 2m) kubelet Back-off pulling image "nginx:latestt"
Warning Failed 32s (x5 over 2m) kubelet Error: ImagePullBackOff
診断書には明確に書いてあります:nginx:latestt: not found。タグ名のタイポです。
修正方法:
[Execution User: developer]
# 壊れたPodを削除
kubectl delete pod broken-image
# 正しいマニフェストを適用
kubectl run fixed-image --image=nginx:latest --port=80
[Execution User: developer]
kubectl get pods fixed-image
実行結果:
NAME READY STATUS RESTARTS AGE
fixed-image 1/1 Running 0 10s
ケース2:CrashLoopBackOff の診断
[Execution User: developer]
kubectl describe pod broken-env
実行結果(Eventsセクション抜粋):
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 3m default-scheduler Successfully assigned default/broken-env to kind-worker2
Normal Pulled 2m (x5 over 3m) kubelet Container image "busybox:1.36" already present on machine
Normal Created 2m (x5 over 3m) kubelet Created container demo-app
Normal Started 2m (x5 over 3m) kubelet Started container demo-app
Warning BackOff 90s (x10 over 3m) kubelet Back-off restarting failed container demo-app in pod broken-env_default(...)
「コンテナは起動したが、すぐに終了してバックオフ中」——ここまでは分かります。しかし、なぜ終了したのかはEventsだけでは分かりません。
ここで kubectl logs の出番です。
[Execution User: developer]
kubectl logs broken-env
実行結果:
ERROR: REQUIRED_CONFIG is not set!
アプリケーションログに答えが書いてありました。環境変数 REQUIRED_CONFIG が設定されていないため、アプリケーションが異常終了しています。
修正方法:
[Execution User: developer]
kubectl delete pod broken-env
cat << 'EOF' | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: fixed-env
spec:
containers:
- name: demo-app
image: busybox:1.36
command: ["/bin/sh", "-c"]
args:
- |
if [ -z "$REQUIRED_CONFIG" ]; then
echo "ERROR: REQUIRED_CONFIG is not set!" >&2
exit 1
fi
echo "Config: $REQUIRED_CONFIG"
sleep 3600
env:
- name: REQUIRED_CONFIG
value: "production-settings-v1"
EOF
[Execution User: developer]
kubectl get pods fixed-env
実行結果:
NAME READY STATUS RESTARTS AGE
fixed-env 1/1 Running 0 15s
ケース3:Pending の診断
[Execution User: developer]
kubectl describe pod broken-resources
実行結果(Eventsセクション抜粋):
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 4m default-scheduler 0/3 nodes are available:
1 node(s) had untolerated taint {node-role.kubernetes.io/control-plane: },
2 node(s) didn't match Pod's node affinity/selector.
2 node(s) had insufficient memory.
2 node(s) had insufficient cpu.
スケジューラーからの診断書は極めて明確です。「128GBのメモリと64コアのCPUを要求しているが、そんなノードは存在しない」。
VMで言えば、「このVMには256GBのRAMを割り当ててください」と設定したのに、クラスタ内のどのホストも128GB以上のメモリを持っていない状況です。
修正方法:
[Execution User: developer]
kubectl delete pod broken-resources
cat << 'EOF' | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: fixed-resources
spec:
containers:
- name: modest-nginx
image: nginx:1.27
resources:
requests:
memory: "64Mi"
cpu: "100m"
limits:
memory: "128Mi"
cpu: "200m"
EOF
[Execution User: developer]
kubectl get pods fixed-resources
実行結果:
NAME READY STATUS RESTARTS AGE
fixed-resources 1/1 Running 0 8s
11.2.3 kubectl events:時系列で「何が起きたか」の物語を追う
ここまでは個別のPodを診断してきました。しかし、本番環境ではもっと複雑な状況が発生します。「Deploymentを更新したら、何かがおかしくなった。でも、どのPodが、いつ、どんな順序で壊れたのか分からない」——。
こんなとき、Namespace全体のイベントを時系列で俯瞰することが重要になります。
[Execution User: developer]
kubectl events -n default --types Warning
実行結果:
LAST SEEN TYPE REASON OBJECT MESSAGE
5m Warning Failed pod/broken-image Failed to pull image "nginx:latestt"...
5m Warning Failed pod/broken-image Error: ErrImagePull
4m Warning BackOff pod/broken-image Back-off pulling image "nginx:latestt"
4m Warning BackOff pod/broken-env Back-off restarting failed container...
4m Warning FailedScheduling pod/broken-resources 0/3 nodes are available...
これは、いわばK8sの監視カメラ映像を巻き戻しているようなものです。VMwareのvRealize Log Insightや、Windows Serverのイベントビューアで「警告」「エラー」をフィルタリングするのと同じ感覚で使えます。
実践Tips:特定リソースのイベントだけを見る
[Execution User: developer]
# 特定のPodのイベントだけを抽出
kubectl events --for=pod/broken-env
# 特定のDeploymentに関連するイベント
kubectl events --for=deployment/my-app
実践Tips:リアルタイムでイベントを監視する
障害対応中は、イベントをリアルタイムで監視したいことがあります。
[Execution User: developer]
kubectl events -n default -w
-w (watch) オプションを付けると、新しいイベントが発生するたびに画面に追加表示されます。VMwareのvCenter Serverで「タスクとイベント」タブを開きっぱなしにしている状況を再現できます。
11.3 総括:VMエンジニアが「K8sネイティブ」になるためのロードマップ
11.3.1 本連載で学んだこと:VMの常識をどうアップデートできたか
全11回の連載を通じて、あなたは以下の「常識のアップデート」を体験しました。
| 回 | VMの常識 | K8sの新常識 |
|---|---|---|
| 第1回 | サーバーは「箱」、VMは「仮想の箱」 | Podは「プロセスの集合」、ノードは「リソースプール」 |
| 第2回 | OSインストール→ミドルウェア導入→設定 | コンテナイメージにすべて封入、宣言的に展開 |
| 第3回 | IPアドレスは固定、DNS手動登録 | ServiceがIPを抽象化、自動DNS登録 |
| 第4回 | 外部公開はF5/NetScaler/HAProxy | Ingressでルーティング、TLS終端も自動化 |
| 第5回 | ストレージはSAN/NAS、LUNをマウント | PV/PVCで抽象化、動的プロビジョニング |
| 第6回 | 設定ファイルは /etc に直接配置 | ConfigMap/Secretで分離、再デプロイ不要で更新可能 |
| 第7回 | 監視は Zabbix/Nagios、エージェント導入 | メトリクスは標準化、Prometheus/Grafanaエコシステム |
| 第8回 | 台数増減は手動、vMotionで負荷分散 | HPAで自動スケール、Pod単位の柔軟性 |
| 第9回 | ジョブはcron、失敗したら手動再実行 | Job/CronJobで宣言的管理、リトライも自動 |
| 第10回 | RBAC?Active Directoryで十分 | K8s RBAC で最小権限、Namespace で論理分離 |
| 第11回 | 障害時はvCenter見て、ログ見て、勘で切り分け | 4種の神器で体系的診断、イベントが物語を語る |
振り返ってみてください。あなたが長年培ってきた「インフラ運用の勘所」——リソース管理、可用性設計、セキュリティ、監視——は、K8sの世界でもそのまま活きています。変わったのは「道具」と「手順」であって、根底にある設計思想は驚くほど共通しているのです。
11.3.2 次のステップ:GitOps、Helm、マネージドサービス(EKS/AKS/GKE)への展望
本連載で扱った kind クラスタは、あくまで学習・開発用の環境です。本番環境へ進むにあたって、以下の3つの方向性を紹介します。
1. GitOps:「あるべき状態」をGitで管理する
本連載では kubectl apply -f でマニフェストを適用してきました。しかし、本番環境では「誰が」「いつ」「何を」変更したかを追跡する必要があります。
GitOps は、Gitリポジトリを「信頼できる唯一の情報源(Single Source of Truth)」とし、リポジトリの内容とクラスタの状態を自動的に同期させるアプローチです。
代表的なツール:
- Argo CD:K8sネイティブな継続的デリバリーツール
- Flux:CNCF卒業プロジェクト、軽量で拡張性が高い
VMwareでいえば、vSphereの構成をすべてコードで管理し、変更はPull Requestを経てレビュー・承認されてから適用される——そんなワークフローです。
2. Helm:「パッケージマネージャー」でアプリをまとめる
複数のマニフェスト(Deployment, Service, ConfigMap, Secret…)を個別に管理するのは、やがて破綻します。
Helm は、K8sにおけるパッケージマネージャーです。複数のマニフェストを「Chart」としてまとめ、バージョン管理、パラメータ化、依存関係の解決を行います。
[Execution User: developer]
# 例:PrometheusスタックをHelmでインストール
helm install prometheus prometheus-community/kube-prometheus-stack
VMwareでいえば、OVAテンプレートでアプライアンスをデプロイするような手軽さで、複雑なアプリケーションを導入できます。
3. マネージドK8s:運用負荷をクラウドに委譲する
kind や kubeadm で構築したクラスタは、コントロールプレーン(API Server, etcd等)の運用も自分で行う必要があります。本番環境では、この部分をクラウドプロバイダーに任せる選択肢があります。
| サービス | プロバイダー | 特徴 |
|---|---|---|
| EKS | AWS | AWSサービスとの統合が強力、Fargateでサーバーレス運用も可能 |
| AKS | Azure | Azure ADとの統合、Windows コンテナサポート |
| GKE | Google Cloud | K8s開発元の知見、Autopilotモードで全自動運用 |
VMwareを使っていた方なら、VMware Cloud on AWSやAzure VMware Solutionを検討したことがあるかもしれません。マネージドK8sはその延長線上にあり、「コントロールプレーンの運用はプロに任せ、自分たちはアプリケーションに集中する」という分業です。
11.3.3 最後に:インフラエンジニアの価値は「道具」ではなく「運用の設計思想」にある
技術は変わり続けます。VMwareがK8sに、K8sがまた別の何かに置き換わる日が来るかもしれません。しかし、「システムをどう設計し、どう監視し、どう復旧させるか」という運用の設計思想は、技術を超えて生き続けます。
あなたがVMの世界で培った経験は、無駄にはなりません。それはK8sという新しい武器を手にすることで、より強力に、より柔軟に活かせるようになりました。
本連載で身につけた「4種の神器」——get で異変を察知し、describe で診断書を読み、logs でアプリの声を聴き、events で物語を追う——これらのスキルは、どのクラウドでも、どのK8sディストリビューションでも、普遍的に使えます。
11.4 2026年版:K8sデバッグ・チェックリスト
現場で使える簡易トラブルシューティングシートです。印刷して手元に置いておくことをお勧めします。
カテゴリ1:ネットワーク疎通
| チェック項目 | 確認コマンド | 期待する結果 |
|---|---|---|
| Pod間の疎通 | kubectl exec <pod-a> -- wget -qO- <pod-b-ip> | 200 OK または期待するレスポンス |
| Service経由の疎通 | kubectl exec <pod> -- nslookup <service-name> | IPアドレスが解決される |
| 外部への疎通 | kubectl exec <pod> -- wget -qO- https://example.com | 200 OK |
| DNS解決 | kubectl exec <pod> -- cat /etc/resolv.conf | nameserver が CoreDNS の ClusterIP |
カテゴリ2:リソース(CPU/メモリ)
| チェック項目 | 確認コマンド | 注目ポイント |
|---|---|---|
| ノードのリソース状況 | kubectl top nodes | CPU/メモリの使用率が 80% 未満か |
| Podのリソース消費 | kubectl top pods | limits に近づいていないか |
| OOMKilled の確認 | kubectl describe pod <name> | Reason: OOMKilled がないか |
| リソースクォータ | kubectl describe resourcequota -n <ns> | クォータに到達していないか |
カテゴリ3:認証・認可(RBAC)
| チェック項目 | 確認コマンド | 期待する結果 |
|---|---|---|
| 自分の権限確認 | kubectl auth can-i <verb> <resource> | yes または no |
| ServiceAccount の確認 | kubectl get pod <name> -o jsonpath='{.spec.serviceAccountName}' | 期待するSA名 |
| RoleBinding の確認 | kubectl get rolebindings -n <ns> | 必要なバインディングが存在する |
| Secret のマウント確認 | kubectl exec <pod> -- ls /var/run/secrets/kubernetes.io/serviceaccount/ | token, ca.crt, namespace |
カテゴリ4:ストレージ(PV/PVC)
| チェック項目 | 確認コマンド | 期待する結果 |
|---|---|---|
| PVC のステータス | kubectl get pvc | Bound 状態 |
| PV の確認 | kubectl get pv | Available または Bound |
| StorageClass の確認 | kubectl get storageclass | デフォルトSCに (default) マーク |
| マウント状態の確認 | kubectl describe pod <name> | Volumes: セクションでマウント成功 |
クイックリファレンス:4種の神器
[Execution User: developer]
# 1. 一覧と状態確認(まず最初に)
kubectl get pods -o wide
# 2. 詳細診断(Eventsが最重要)
kubectl describe pod <pod-name>
# 3. アプリケーションログ(CrashLoopBackOff時に必須)
kubectl logs <pod-name>
kubectl logs <pod-name> --previous # 前回起動時のログ
kubectl logs <pod-name> -c <container-name> # マルチコンテナPod
# 4. イベント俯瞰(Namespace全体の時系列)
kubectl events -n <namespace>
kubectl events -w # リアルタイム監視
緊急時のエスカレーション判断基準
| 状況 | 自己解決の目安 | エスカレーション検討 |
|---|---|---|
| 単一Pod の異常 | 30分以内に原因特定 | 原因不明が1時間継続 |
| 複数Pod の同時異常 | ノード障害を疑う | 全ノードに影響時は即座に |
| コントロールプレーン異常 | kubectl 自体が動かない | 即座にエスカレーション |
| ストレージ障害 | PVCがPending | データ損失の可能性時は即座に |
