- 第6回スコープ・学習目標・今ここマップ
- kubectl の仕組み — kubeconfig から API Server への通信フロー
- alias k=kubectl の設定と kubectl 基本コマンド体系
- kubectl explain — YAML スキーマを手元で調べる(CKAD 最重要技)
- kubectl apply / diff / delete — マニフェストのライフサイクル管理
- 出力形式の使い分け — -o yaml / json / wide / jsonpath
- やってみよう①: kind 再起動 + alias 設定 + kubectl get/describe/logs 基本操作
- やってみよう②: 異常 Pod を kubectl exec / describe / events でデバッグ
- やってみよう③: metrics-server 導入 + kubectl top でリソース確認
- Step 1: kubectl top の実行(metrics-server なし)
- Step 2: metrics-server の導入(REC-7 採用・v0.8.1 ピン留め)
- Step 2.5: metrics-server イメージを Docker Hub mirror に切替(whitelist 環境向け)
- Step 3: kind 環境向け –kubelet-insecure-tls フラグの追加
- Step 4: metrics-server Pod の起動確認
- Step 5: kubectl top node / kubectl top pod の実行
- 演習後のクリーンアップ(crash-test Pod のみ削除)
- API デプリケーション検知 — kubectl api-versions / api-resources / convert
- ラベルセレクタ — -l フラグで Pod を絞り込む
- 現場ヒヤリハット — kubectl logs でターミナルが止まった / exec 中に Pod が消えた
- 理解度チェック + まとめ + 次回予告 + シリーズ一覧
第6回スコープ・学習目標・今ここマップ
動作確認バージョン: kind v0.31.0 / kindest/node:v1.35.0 / kubectl v1.35.0 (Kustomize v5.7.1) / metrics-server v0.8.1 / Docker CE 29.4.3 / containerd 2.2.3 / AlmaLinux 10.1(kernel 6.12.0-124.55.3.el10_1)(2026-05-10 時点・k8s-ops 実機検証済・SP_vol1-pre-09 起点)
本回は Kubernetes 実践教科書 第1巻(CKAD 対応・全 19 回)の第6回です。第2部「Kubernetes 基礎」の第2回として、kubectl の仕組み・基本コマンド体系・Observability(観測可能性)・デバッグ手順 を扱います。
CKAD D3(Application Observability and Maintenance・15 %)を全項目網羅し、D1 補完(kubectl explain によるスキーマ参照)も達成します。
第5回からの継承状態確認(SP_vol1-pre-09 状態):
| 項目 | 状態 | 出典 |
|---|---|---|
| kind v0.31.0 | /usr/local/bin/kind にインストール済 | ep5 完了済 |
| kubectl v1.35.0 | /usr/local/bin/kubectl にインストール済 | ep5 完了済 |
| kindest/node:v1.35.0 | Docker images に存在(1.35GB)・pull 済 | ep5 完了済 |
| kind クラスタ | 削除済(docker ps = no running container) | ep5 で kind delete 済 |
| alias k=kubectl | 未設定(ep6 で初設定) | 実機確認済 |
| metrics-server | 未導入 | 実機確認済 |
今ここマップ(第1巻 19 回中の現在位置):
第1部 コンテナとDocker
第1回: コンテナ技術概念 + Docker環境準備 [完了]
第2回: Docker基本操作 [完了]
第3回: Dockerfile + マルチステージビルド + JDK 25/Payara Micro [完了]
第4回: コンテナレジストリ + イメージタグ戦略 + Trivy スキャン [完了]
第2部 Kubernetes基礎
第5回: K8s全体像 + kind で軽量K8s [完了]
★ 第6回: kubectl基本操作 + Observability・Debug ← 今ここ
第3部 アプリリソース(第7〜11回)
第4部 ワークロード戦略(第12〜14回)
第5部 セキュリティ基礎(第15〜16回)
第6部 パッケージ管理 + HTTPS公開(第17〜19回)
第6回を終えると、以下を習得した状態になります。
- kubectl の通信フロー(kubeconfig → API Server → etcd)を説明できる
alias k=kubectlを永続設定し、get / describe / logs / exec / apply / diff / explain の 7 コマンドを実践で使いこなせる-o yaml / json / wide / jsonpathの 4 種の出力形式を場面に応じて選択できる- CrashLoopBackOff の Pod を
kubectl logs --previous/kubectl describe/kubectl get eventsの 3 コマンドで原因特定できる - metrics-server を kind クラスタに導入し
kubectl top pod/kubectl top nodeでリソース使用量を確認できる
模擬アプリ進捗(第6回):第6回は kubectl の操作習熟回のため、fanclub-api のデプロイ作業はありません。Pod を K8s に載せるのは第7回からです。演習では nginx と busybox を使ったシンプルなテスト Pod を使用します。
kubectl の仕組み — kubeconfig から API Server への通信フロー
第5回で「API Server はすべての通信のゲートウェイ」と学びました。第6回では「kubectl がどうやって API Server と通信するか」の具体的な仕組みを確認します。この仕組みを理解しておくと、kubectl の操作がなぜそう動くのかが明確になり、以降の全演習で迷わなくなります。
kubeconfig の 3 層構造
kubectl は ~/.kube/config(kubeconfig)を読み込み、接続先クラスタと認証情報を取得します。kind create cluster を実行すると、このファイルが自動的に生成・更新されます。
kubeconfig は次の 3 つのセクションで構成されています。
| セクション | 役割 | kind クラスタでの例 |
|---|---|---|
| clusters | 接続先クラスタ(API Server の URL + CA 証明書) | https://127.0.0.1:46149(ランダムポート・環境ごとに異なる) |
| users | 認証情報(クライアント証明書またはトークン) | kind-kind ユーザーの証明書データ(base64) |
| contexts | cluster と user の紐付け | kind-kind(= kind-kind クラスタ + kind-kind ユーザー) |
current-context に設定されているコンテキストが「今どのクラスタに接続しているか」を示します。kind create cluster は自動的に current-context: kind-kind を設定するため、インストール直後から kubectl が kind クラスタに接続できます。
kubectl の通信フロー
kubectl get pods を実行したときの内部フローを追います。
[kubectl get pods]
↓
[~/.kube/config 読み込み]
current-context から cluster(API Server URL)と user(証明書)を取得
↓ HTTPS / TLS 証明書認証
[kube-apiserver :6443]
認証(証明書が有効か)→ 認可(この操作が許可されているか)→ Pod 一覧を etcd から取得
↓
[etcd]
クラスタ状態の SSOT(Single Source of Truth)
↓
[kubectl] が結果を受け取り → テーブル形式で表示

kubectl cluster-info でクラスタ情報確認
kubectl cluster-info でクラスタの API Server URL と CoreDNS の稼働状況を確認できます。
実行コマンド:
$ kubectl cluster-info
実行結果:
Kubernetes control plane is running at https://127.0.0.1:46149
CoreDNS is running at https://127.0.0.1:46149/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
注意点(CKAD 試験):kubectl config view で表示される certificate-authority-data / client-certificate-data は base64 エンコードされた証明書データです。本番環境では安易に共有しないようにします。
CKAD 試験では試験環境の kubeconfig が事前設定されているため、受験者が kubeconfig を操作する必要はありません。
alias k=kubectl の設定と kubectl 基本コマンド体系
第6回で初めて alias k=kubectl を ~/.bashrc に永続設定します。以降のすべての回(ep7〜ep19)では k と kubectl の両方を使います。
alias の ~/.bashrc への永続設定
CKAD 試験でも「最初の 1 分間で alias k=kubectl と Tab 補完を設定する」ことが試験コミュニティで広く推奨されています。ep6 でこの手順を定着させておくと、試験本番で迷わずに済みます。
実行コマンド(alias 永続化):
$ echo 'alias k=kubectl' >> ~/.bashrc
$ echo 'source <(kubectl completion bash)' >> ~/.bashrc
$ echo 'complete -o default -F __start_kubectl k' >> ~/.bashrc
$ source ~/.bashrc
実行コマンド(alias の確認):
$ alias | grep kubectl
実行結果:
alias k='kubectl'
~/.bashrc に追記することで、次回ログイン後も alias が有効になります。source ~/.bashrc は「現在のシェルにも即時反映する」コマンドです。
kubectl 基本コマンド体系(7 コマンド)
ep6 で習得する 7 コマンドの役割を確認します。
| コマンド | 役割 | 典型的な使用場面 |
|---|---|---|
get | リソース一覧・状態確認 | Pod の STATUS 確認・デプロイ後の状態確認 |
describe | リソース詳細・Events 確認 | CrashLoopBackOff 原因調査・Scheduling 失敗調査 |
logs | コンテナログ確認 | アプリケーションエラー確認・起動失敗ログ確認 |
exec | コンテナ内コマンド実行 | 環境変数確認・ネットワーク疎通確認・ファイル確認 |
apply | マニフェスト適用(作成 + 更新) | 宣言的デプロイ・設定変更の反映 |
diff | 適用前の差分確認 | apply 前の変更内容確認・誤適用防止 |
explain | YAML スキーマ確認 | YAML を書く前のフィールド確認・試験中の即座参照 |

kubectl explain — YAML スキーマを手元で調べる(CKAD 最重要技)
kubectl explain は、kubernetes.io のドキュメントを開かずに YAML スキーマを確認できる組み込みコマンドです。CKAD 試験中でも使用可能であり、フィールド名・型・説明をターミナル上で素早く確認できます。
基本構文と出力の読み方
実行コマンド:
$ kubectl explain pod
実行結果(抜粋):
KIND: Pod
VERSION: v1
DESCRIPTION:
Pod is a collection of containers that can run on a host. This resource is
created by clients and scheduled onto hosts.
FIELDS:
apiVersion <string>
kind <string>
metadata <ObjectMeta>
spec <PodSpec>
status <PodStatus> -ro-
出力の読み方:
<string>:文字列型のフィールド<ObjectMeta>:別のオブジェクト型(ネスト構造がある)-ro-:Read Only(ユーザーが直接書かない・K8s が自動設定するフィールド)
フィールドの掘り下げ
実行コマンド:
$ kubectl explain pod.spec.containers
実行結果(抜粋):
KIND: Pod
VERSION: v1
FIELD: containers <[]Container>
DESCRIPTION:
List of containers belonging to the pod. Containers cannot currently be
added or removed. There must be at least one container in a Pod. Cannot be
updated.
A single application container that you want to run within a pod.
FIELDS:
args <[]string>
Arguments to the entrypoint. The container image's CMD is used if this is
not provided. ...
command <[]string>
Entrypoint array. Not executed within a shell. ...
env <[]EnvVar>
envFrom <[]EnvFromSource>
image <string>
imagePullPolicy <string>
enum: Always, IfNotPresent, Never
...
–recursive で全フィールドを展開する
--recursive オプションを付けると、ネストされたフィールドをすべて展開した一覧を表示できます。ただし出力が数百行になるため、head コマンドで先頭部分のみ確認するのが実用的です。
実行コマンド(先頭 50 行を抜粋):
$ kubectl explain pod.spec.containers --recursive | head -50
実行結果(抜粋):
FIELDS:
args <[]string>
command <[]string>
env <[]EnvVar>
name <string> -required-
value <string>
valueFrom <EnvVarSource>
configMapKeyRef <ConfigMapKeySelector>
key <string> -required-
name <string>
optional <boolean>
fieldRef <ObjectFieldSelector>
apiVersion <string>
fieldPath <string> -required-
secretKeyRef <SecretKeySelector>
key <string> -required-
name <string>
optional <boolean>
envFrom <[]EnvFromSource>
configMapRef <ConfigMapEnvSource>
name <string>
optional <boolean>
prefix <string>
secretRef <SecretEnvSource>
name <string>
optional <boolean>
image <string>
imagePullPolicy <string>
enum: Always, IfNotPresent, Never
特定フィールドを grep で絞り込むと、目的のフィールドを素早く見つけられます。
実行コマンド(image フィールドを検索):
$ kubectl explain pod.spec.containers --recursive | grep image
CKAD 試験での活用:kubectl explain は CKAD 試験中でも使用可能な組み込みコマンドです。kubernetes.io/docs にアクセスしなくてもスキーマを確認できるため、試験時間の節約につながります。
Pod の YAML 構造(apiVersion / kind / metadata / spec)は第7回で完全習得します。ep6 では「このフィールドが存在することを確認できる」段階で十分です。
kubectl apply / diff / delete — マニフェストのライフサイクル管理
第7回から YAML マニフェストの本格利用が始まります。ep6 では「宣言的操作」の考え方と apply / diff / delete の関係を概念として先出しします。
kubectl apply の冪等性
kubectl apply -f pod.yaml は「存在しなければ作成し、存在すれば差分を更新する」冪等な操作です。
| コマンド | リソースが存在しない場合 | リソースが存在する場合 |
|---|---|---|
kubectl apply -f | 新規作成 | 差分のみ更新(冪等) |
kubectl create -f | 新規作成 | エラー(AlreadyExists) |
ep7 以降は全面的に kubectl apply -f を使用します。kubectl create は「確実に新規作成のみ」が必要な場面に限定します。
kubectl diff で変更前に確認する
kubectl apply の前に kubectl diff で変更内容を確認する習慣をつけると、本番での誤適用を防げます。
実行コマンド:
$ kubectl diff -f pod.yaml
出力は git diff 形式(- が削除行・+ が追加行)です。apply 前に差分を目視確認することで、意図しないフィールドが変更されることを防げます。
kubectl delete
実行コマンド(ファイル指定削除):
$ kubectl delete -f pod.yaml
実行コマンド(Pod 名指定削除):
$ kubectl delete pod nginx-test
本番禁止:--grace-period=0 --force は Graceful Termination(デフォルト 30 秒)をスキップするため、本番環境では使用しません。Pod の Graceful Termination は第7回で詳細を扱います。
–dry-run=client -o yaml テクニック(概念導入)
CKAD 試験高速化の最重要テクニックとして、--dry-run=client -o yaml を紹介します。
kubectl run nginx --image=nginx --dry-run=client -o yaml
このコマンドは「実際には Pod を作成せず、YAML の雛形を標準出力に出力する」操作です。YAML ファイルをゼロから書くより、雛形を生成してから編集する方が試験で大幅に時間を節約できます。ep6 では「このテクニックがある」という概念を把握するにとどめ、本格活用は ep7 以降で行います。
出力形式の使い分け — -o yaml / json / wide / jsonpath
kubectl get の出力形式を場面に応じて使い分けることで、必要な情報を素早く取り出せます。
| オプション | 用途 | 典型的な場面 |
|---|---|---|
-o yaml | YAML 完全出力(現在の状態確認・マニフェスト生成) | 既存リソースを元に YAML を編集したい・クラスタの実際の設定を確認したい |
-o json | JSON 完全出力(スクリプト処理・jq 連携) | CI/CD パイプラインで JSON を解析したい |
-o wide | 追加列(IP・ノード名など)を表示 | どのノードで動いているか確認したい・Pod の IP を素早く見たい |
-o jsonpath='...' | 特定フィールドのみ抽出 | スクリプトで Pod IP だけ取り出したい・複数 Pod の名前をまとめて取りたい |
jsonpath 実用パターン
実行コマンド(Pod の IP を取得):
$ kubectl get pod nginx-test -o jsonpath='{.status.podIP}'
実行コマンド(ノードの内部 IP を取得):
$ kubectl get node kind-control-plane -o jsonpath='{.status.addresses[0].address}'
実行コマンド(全 Pod の名前一覧をスペース区切りで表示):
$ kubectl get pods -o jsonpath='{.items[*].metadata.name}'
実行コマンド(全 Pod の名前と Namespace を改行区切りで表示):
$ kubectl get pods -A -o jsonpath='{range .items[*]}{.metadata.namespace}{" "}{.metadata.name}{"\n"}{end}'
jsonpath の {.items[*]} は「すべての要素」を意味します。range を使うと複数の要素をループ処理できます。jsonpath は CKAD 試験でも頻出のため、上記 4 パターンを手順として覚えておくと役立ちます。
やってみよう①: kind 再起動 + alias 設定 + kubectl get/describe/logs 基本操作
演習①では kind クラスタを再作成し、alias 設定を行ってから nginx Pod を起動して get / describe / logs の 3 コマンドを実践します。所要時間の目安は 20〜25 分です。
前提状態:SP_vol1-pre-09(kind v0.31.0 + kubectl v1.35.0 インストール済・クラスタなし)
Step 1: alias 設定(永続化)
実行コマンド:
$ echo 'alias k=kubectl' >> ~/.bashrc
$ echo 'source <(kubectl completion bash)' >> ~/.bashrc
$ echo 'complete -o default -F __start_kubectl k' >> ~/.bashrc
$ source ~/.bashrc
$ alias | grep kubectl
実行結果:
alias k='kubectl'
Step 2: kind クラスタ再作成
実行コマンド:
$ kind create cluster --image docker.io/kindest/node:v1.35.0
実行結果:
Creating cluster "kind" ...
• Ensuring node image (docker.io/kindest/node:v1.35.0) 🖼 ...
✓ Ensuring node image (docker.io/kindest/node:v1.35.0) 🖼
• Preparing nodes 📦 ...
✓ Preparing nodes 📦
• Writing configuration 📜 ...
✓ Writing configuration 📜
• Starting control-plane 🕹️ ...
✓ Starting control-plane 🕹️
• Installing CNI 🔌 ...
✓ Installing CNI 🔌
• Installing StorageClass 💾 ...
✓ Installing StorageClass 💾
Set kubectl context to "kind-kind"
You can now use your cluster with:
kubectl cluster-info --context kind-kind
ep5 と同じ手順です。kindest/node:v1.35.0 が pull 済みのため「Ensuring node image」は数秒で通過します。
Step 3: クラスタ接続確認
実行コマンド:
$ k cluster-info
$ k get nodes
$ k get nodes -o wide
実行結果(kubectl get nodes):
NAME STATUS ROLES AGE VERSION
kind-control-plane Ready control-plane 52s v1.35.0
kind クラスタはシングルノード構成のため、Control Plane Node が 1 台だけ表示されます。STATUS が Ready になれば接続成功です。-o wide を付けると Pod の IP やノードが稼働する内部 IP なども確認できます。
Step 4: nginx Pod の起動
実行コマンド:
$ k run nginx-test --image=nginx:1.27-alpine --restart=Never
実行結果:
pod/nginx-test created
--restart=Never は「Pod を直接作成する(Deployment を経由しない)」オプションです。省略すると kubectl のバージョンによって挙動が異なる場合があるため、演習では明示的に指定します。
Step 5: kubectl get で Pod の状態確認(出力の読み方)
実行コマンド:
$ k get pods
実行結果:
NAME READY STATUS RESTARTS AGE
nginx-test 1/1 Running 0 15s
各列の意味:
| 列名 | 意味 | 確認ポイント |
|---|---|---|
| READY | 「起動中のコンテナ数 / 合計コンテナ数」 | 1/1 = 全コンテナが起動・準備完了 |
| STATUS | Pod の現在の状態 | Running = 正常稼働。ContainerCreating / Pending は起動中 |
| RESTARTS | コンテナの再起動回数 | 0 = 一度も再起動していない。増えている場合は何らかのエラー |
| AGE | Pod が作成されてからの経過時間 | s(秒)/ m(分)/ h(時間)/ d(日)の単位で表示 |
Step 6: kubectl describe で Pod 詳細確認(Events セクションを重点解説)
実行コマンド:
$ k describe pod nginx-test
実行結果(Events セクション抜粋):
Name: nginx-test
Namespace: default
Priority: 0
Service Account: default
Node: kind-control-plane/172.18.0.2
Start Time: Sun, 10 May 2026 08:32:16 +0900
Labels: run=nginx-test
Annotations: <none>
Status: Running
IP: 10.244.0.5
IPs:
IP: 10.244.0.5
Containers:
nginx-test:
Container ID: containerd://89de064e8943c7259a5d9dee0edaa44b3076ccd0b652b1217bcea2c76d7859a8
Image: nginx:1.27-alpine
Image ID: docker.io/library/nginx@sha256:65645c7bb6a0661892a8b03b89d0743208a18dd2f3f17a54ef4b76fb8e2f2a10
State: Running
Started: Sun, 10 May 2026 08:32:22 +0900
Ready: True
Restart Count: 0
...
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 29s default-scheduler Successfully assigned default/nginx-test to kind-control-plane
Normal Pulling 28s kubelet spec.containers{nginx-test}: Pulling image "nginx:1.27-alpine"
Normal Pulled 23s kubelet spec.containers{nginx-test}: Successfully pulled image "nginx:1.27-alpine" in 5.612s (5.612s including waiting). Image size: 20984244 bytes.
Normal Created 23s kubelet spec.containers{nginx-test}: Container created
Normal Started 23s kubelet spec.containers{nginx-test}: Container started
Events セクションの各列の読み方:
| 列名 | 意味 |
|---|---|
| Type | Normal(通常)または Warning(警告・調査が必要) |
| Reason | イベントの種類(Scheduled / Pulling / Pulled / Created / Started / BackOff など) |
| Age | このイベントが発生してからの経過時間 |
| From | このイベントを生成したコンポーネント(default-scheduler / kubelet など) |
| Message | イベントの詳細メッセージ |
Events は「Pod がどのようなライフサイクルを経て現在の状態になったか」を時系列で示します。Scheduled → Pulling → Pulled → Created → Started の順に Events が並んでいれば、Pod は正常に起動しています。異常がある場合は Warning イベントや BackOff が表示されます。
Step 7: kubectl logs でコンテナログ確認
実行コマンド(基本):
$ k logs nginx-test
実行結果:
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
/docker-entrypoint.sh: Sourcing /docker-entrypoint.d/15-local-resolvers.envsh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
2026/05/09 23:32:22 [notice] 1#1: using the "epoll" event method
2026/05/09 23:32:22 [notice] 1#1: nginx/1.27.5
2026/05/09 23:32:22 [notice] 1#1: built by gcc 14.2.0 (Alpine 14.2.0)
2026/05/09 23:32:22 [notice] 1#1: OS: Linux 6.12.0-124.55.3.el10_1.x86_64
2026/05/09 23:32:22 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1073741816:1073741816
2026/05/09 23:32:22 [notice] 1#1: start worker processes
2026/05/09 23:32:22 [notice] 1#1: start worker process 38
2026/05/09 23:32:22 [notice] 1#1: start worker process 39
実行コマンド(末尾 5 行のみ):
$ k logs nginx-test --tail=5
実行コマンド(直近 1 分以内のログのみ):
$ k logs nginx-test --since=1m
--tail と --since の使い分けが重要な理由は、本番の長時間稼働 Pod では全ログが数十万行になることがあるためです。詳細は H2-12(現場ヒヤリハット)で扱います。
やってみよう②: 異常 Pod を kubectl exec / describe / events でデバッグ
演習②では意図的に異常終了する Pod(exit 1)を作り、CrashLoopBackOff を自分で調査・原因特定します。「エラーが出たときに何をするか」のデバッグフレームワークを実機で体験します。所要時間の目安は 20〜25 分です。
前提状態:演習① 完了後(nginx-test Pod が Running の状態)
Step 1: 意図的に異常終了する Pod の作成
実行コマンド:
$ k run crash-test --image=busybox:1.36 -- /bin/sh -c "exit 1"
実行結果:
pod/crash-test created
/bin/sh -c "exit 1" は「シェルを起動して即座に終了コード 1 で終了する」コマンドです。コンテナが即座に終了すると K8s はそれを「失敗」と判断して自動再起動を試みます。再起動のたびに待機時間が指数的に増加する仕組みが CrashLoopBackOff です。
Step 2: CrashLoopBackOff の確認
実行コマンド:
$ k get pods
実行結果(5 分ほど経過後・RESTARTS が増加して BackOff が長くなった状態):
NAME READY STATUS RESTARTS AGE
crash-test 0/1 CrashLoopBackOff 6 (4m17s ago) 9m51s
nginx-test 1/1 Running 0 10m
RESTARTS の数字が増え続けることを確認します。K8s は再起動間隔を 10 秒・20 秒・40 秒・80 秒と指数的に増加させます(最大 5 分)。これが「BackOff」の名称の由来です。
Step 3: kubectl describe で Events 確認
実行コマンド:
$ k describe pod crash-test
実行結果(Events セクション抜粋):
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 60s default-scheduler Successfully assigned default/crash-test to kind-control-plane
Normal Pulling 59s kubelet spec.containers{crash-test}: Pulling image "busybox:1.36"
Normal Pulled 55s kubelet spec.containers{crash-test}: Successfully pulled image "busybox:1.36" in 3.911s. Image size: 2217006 bytes.
Normal Created 21s (x4 over 55s) kubelet spec.containers{crash-test}: Container created
Normal Started 21s (x4 over 55s) kubelet spec.containers{crash-test}: Container started
Normal Pulled 21s (x3 over 55s) kubelet spec.containers{crash-test}: Container image "busybox:1.36" already present on machine and can be accessed by the pod
Warning BackOff 21s (x4 over 54s) kubelet spec.containers{crash-test}: Back-off restarting failed container crash-test in pod crash-test_default(1d42764f-5a41-49d6-92e9-8073515e9b0e)
Warning BackOff のイベントが表示されます。「Back-off restarting failed container」というメッセージがあれば、コンテナが繰り返し失敗して再起動されていることを確認できます。
Step 4: kubectl logs –previous で前回起動ログ確認
--previous オプションは「現在ではなく直前に終了したコンテナのログ」を確認するオプションです。CrashLoopBackOff のデバッグで必須です。
実行コマンド:
$ k logs crash-test --previous
実行結果:
unable to retrieve container logs for containerd://32b07f1ae40c8ab39d5f2404a867687e4e34c9fa6b4efaf409222aa73492bc04
今回の exit 1 は「何も出力せずに終了」するため、ログは空です。実際のアプリケーションでは OutOfMemoryError や Connection refused のようなエラーメッセージがここに表示されます。「ログが空でも確認する価値がある」のは、exit 1 のような即時終了ではなく、実アプリが起動途中でクラッシュした場合に起動ログが残るからです。
Step 5: kubectl get events で時系列確認
実行コマンド:
$ k get events --sort-by='.lastTimestamp'
実行結果(抜粋):
LAST SEEN TYPE REASON OBJECT MESSAGE
102s Normal Scheduled pod/nginx-test Successfully assigned default/nginx-test to kind-control-plane
101s Normal Pulling pod/nginx-test Pulling image "nginx:1.27-alpine"
96s Normal Pulled pod/nginx-test Successfully pulled image "nginx:1.27-alpine"
96s Normal Created pod/nginx-test Container created
96s Normal Started pod/nginx-test Container started
61s Normal Scheduled pod/crash-test Successfully assigned default/crash-test to kind-control-plane
60s Normal Pulling pod/crash-test Pulling image "busybox:1.36"
56s Normal Pulled pod/crash-test Successfully pulled image "busybox:1.36"
22s Normal Created pod/crash-test Container created
22s Normal Started pod/crash-test Container started
22s Warning BackOff pod/crash-test Back-off restarting failed container crash-test ...
--sort-by='.lastTimestamp' で時系列順に並べることで、クラスタで何が起きたかを時系列で追えます。特に複数の Pod でイベントが発生している場合、全体の流れを把握するのに有効です。
Step 6: 正常 Pod へ kubectl exec でコンテナ内デバッグ
実行コマンド(nginx-test コンテナ内に入る):
$ k exec -it nginx-test -- /bin/sh
コンテナ内での操作例:
/ # hostname
/ # cat /etc/nginx/nginx.conf
/ # wget -qO- http://localhost/
/ # exit
重要な注意点:nginx:1.27-alpine は bash が入っていないイメージです。/bin/bash を指定するとエラーになるため、/bin/sh を使います。alpine ベースのイメージは軽量化のために bash を含まないことが多いため、/bin/sh を使う習慣をつけてください。
デバッグフロー(まとめ)
[kubectl get pods] でステータス確認
↓ CrashLoopBackOff / Error を発見
[kubectl describe pod] で Events を確認
→ スケジューリング失敗 / イメージ pull 失敗 / OOMKilled 等の原因を特定
↓ コンテナ起動後に落ちている場合
[kubectl logs --previous] でクラッシュ直前のアプリログを確認
↓ コンテナが起動している場合
[kubectl exec -it -- /bin/sh] でコンテナ内の環境を直接調査
↓ クラスタレベルのイベントを確認したい場合
[kubectl get events --sort-by='.lastTimestamp'] でクラスタ全体のイベント時系列を確認
このデバッグフローは第7回の OOMKilled 演習でも、第12回の Probe デバッグ演習でも同じ手順で使います。今回定着させた手順を繰り返し使うことで、トラブルシューティングの思考を身につけます。
やってみよう③: metrics-server 導入 + kubectl top でリソース確認
演習③では metrics-server v0.8.1 を kind クラスタに導入し、kubectl top node / kubectl top pod でリソース使用量を確認します。kind 環境では追加の設定が必要ですが、本番(kubeadm)との違いを意識しながら進めます。所要時間の目安は 10〜15 分です。
本番との差異:kubeadm を使う本番環境では metrics-server が最初からインストールされているケースが多く、--kubelet-insecure-tls フラグも不要です。kind は学習用の簡易構成のため、この追加設定が必要になります。
Step 1: kubectl top の実行(metrics-server なし)
まず metrics-server なしで kubectl top を実行して、エラーを確認します。
実行コマンド:
$ k top nodes
実行結果:
error: Metrics API not available
kubectl top は metrics-server が提供する Metrics API(v1beta1.metrics.k8s.io)を使用します。metrics-server がなければ「Metrics API not available」エラーになります。
Step 2: metrics-server の導入(REC-7 採用・v0.8.1 ピン留め)
実行コマンド:
$ kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.8.1/components.yaml
実行結果:
serviceaccount/metrics-server created
clusterrole.rbac.authorization.k8s.io/system:aggregated-metrics-reader created
clusterrole.rbac.authorization.k8s.io/system:metrics-server created
rolebinding.rbac.authorization.k8s.io/metrics-server-auth-reader created
clusterrolebinding.rbac.authorization.k8s.io/metrics-server:system:auth-delegator created
clusterrolebinding.rbac.authorization.k8s.io/system:metrics-server created
service/metrics-server created
deployment.apps/metrics-server created
apiservice.apiregistration.k8s.io/v1beta1.metrics.k8s.io created
URL に v0.8.1 を明示することで再現性を確保しています。本シリーズの方針では「全採用技術はバージョンピン留め」のため、latest ではなく明示バージョンを使用します。
Step 2.5: metrics-server イメージを Docker Hub mirror に切替(whitelist 環境向け)
このまま kubectl get pods -n kube-system を実行すると、metrics-server Pod は ErrImagePull / ImagePullBackOff で起動失敗します。原因は第5回 H2-9 で扱った registry.k8s.io の HTTP 307 redirect 問題です。
registry.k8s.io/metrics-server/metrics-server:v0.8.1 は asia-northeast2-docker.pkg.dev に redirect され、whitelist 未許可で 403 になります。
kindest/node:v1.35.0 と同じ問題のため、同じく Docker Hub mirror(Rancher が公開する docker.io/rancher/mirrored-metrics-server:v0.8.1)に切り替えます。
実行コマンド:
$ kubectl set image deployment/metrics-server -n kube-system \
metrics-server=docker.io/rancher/mirrored-metrics-server:v0.8.1
実行結果:
deployment.apps/metrics-server image updated
Rancher は K8s 関連イメージを Docker Hub にミラー公開しており、registry.k8s.io へアクセスできない whitelist 環境でも入手可能です。本番環境(kubeadm・第2巻)では registry.k8s.io 経由で問題なく取得できることが多いため、Docker Hub mirror への切替は kind 学習環境固有の対処です。
Step 3: kind 環境向け –kubelet-insecure-tls フラグの追加
kind 環境では kubelet の TLS 証明書検証で問題が発生するため、metrics-server の Deployment に --kubelet-insecure-tls 引数を追加します。
実行コマンド:
$ kubectl patch deployment metrics-server -n kube-system --type='json' \
-p='[{"op": "add", "path": "/spec/template/spec/containers/0/args/-", "value":"--kubelet-insecure-tls"}]'
実行結果:
deployment.apps/metrics-server patched
本番環境警告(重要):--kubelet-insecure-tls は TLS 証明書の検証をスキップします。本番環境では絶対に使用しません。kubeadm(第2巻)では適切な証明書で設定するため、このフラグは不要になります。
なお、kubectl patch の代わりに kubectl edit deployment metrics-server -n kube-system でエディタを開き、args セクションに - --kubelet-insecure-tls を手動追記する方法もあります。
GitOps 原則の観点では「宣言的な YAML 管理」が望ましいため、本番では values.yaml 編集 + helm upgrade が正道になります(第17〜19回で学びます)。
Step 4: metrics-server Pod の起動確認
実行コマンド:
$ k get pods -n kube-system
実行結果:
NAME READY STATUS RESTARTS AGE
coredns-7d764666f9-79tqb 1/1 Running 0 14m
coredns-7d764666f9-xb6st 1/1 Running 0 14m
etcd-kind-control-plane 1/1 Running 0 14m
kindnet-g8chq 1/1 Running 0 14m
kube-apiserver-kind-control-plane 1/1 Running 0 14m
kube-controller-manager-kind-control-plane 1/1 Running 0 14m
kube-proxy-szfnk 1/1 Running 0 14m
kube-scheduler-kind-control-plane 1/1 Running 0 14m
metrics-server-854dc9cfcc-cqghv 1/1 Running 0 60s
metrics-server-854dc9cfcc-cqghv(環境により Pod 名のハッシュ部は異なる)が Running 1/1 になれば準備完了です。Docker Hub mirror への切替+patch 適用から Running まで 30〜60 秒程度かかる場合があります。Running になるまで数秒待ってから Step 5 に進みます。
Step 5: kubectl top node / kubectl top pod の実行
実行コマンド:
$ k top nodes
実行結果:
NAME CPU(cores) CPU(%) MEMORY(bytes) MEMORY(%)
kind-control-plane 69m 3% 667Mi 11%
実行コマンド:
$ k top pods -A
実行結果:
NAMESPACE NAME CPU(cores) MEMORY(bytes)
default nginx-test 0m 2Mi
kube-system coredns-7d764666f9-79tqb 1m 14Mi
kube-system coredns-7d764666f9-xb6st 1m 14Mi
kube-system etcd-kind-control-plane 11m 35Mi
kube-system kindnet-g8chq 1m 11Mi
kube-system kube-apiserver-kind-control-plane 23m 220Mi
kube-system kube-controller-manager-kind-control-plane 9m 56Mi
kube-system kube-proxy-szfnk 1m 17Mi
kube-system kube-scheduler-kind-control-plane 4m 23Mi
kube-system metrics-server-854dc9cfcc-cqghv 3m 17Mi
local-path-storage local-path-provisioner-67b8995b4b-2z4ln 1m 9Mi
単位の読み方:
- CPU:
m(millicores)単位。1000m = 1 CPU コア。100m = CPU 1 コアの 10 % を使用中 - MEMORY:
Mi(Mebibytes)単位。1 Mi = 1,048,576 bytes(約 1 MB)
演習後のクリーンアップ(crash-test Pod のみ削除)
ep6 完了後、kind クラスタは削除せずに残します(ep7 の Pod 演習の起点として使用します)。ただし演習②で作成した crash-test Pod は削除します。
実行コマンド:
$ kubectl delete pod crash-test
実行結果:
pod "crash-test" deleted
ep6 完了後のクラスタ状態:kind クラスタ稼働中・metrics-server 導入済・alias k=kubectl 設定済・nginx-test Pod(Running)のみ残存。
API デプリケーション検知 — kubectl api-versions / api-resources / convert
CKAD D3「API デプリケーションの理解」の必須項目を確認します。クラスタで使える API バージョンを把握し、非推奨 API の検知方法を学びます。
kubectl api-versions — 使える API バージョン一覧
実行コマンド:
$ kubectl api-versions
実行結果(抜粋):
admissionregistration.k8s.io/v1
apiextensions.k8s.io/v1
apiregistration.k8s.io/v1
apps/v1
authentication.k8s.io/v1
authorization.k8s.io/v1
autoscaling/v1
autoscaling/v2
batch/v1
certificates.k8s.io/v1
coordination.k8s.io/v1
discovery.k8s.io/v1
events.k8s.io/v1
flowcontrol.apiserver.k8s.io/v1
networking.k8s.io/v1
node.k8s.io/v1
policy/v1
rbac.authorization.k8s.io/v1
resource.k8s.io/v1
scheduling.k8s.io/v1
storage.k8s.io/v1
v1
出力の読み方:
group/version形式(例:apps/v1= apps グループの v1)- 最後の
v1(グループなし)は「core API」と呼ばれ、Pod / Service / ConfigMap / Secret などの基本リソースが属するグループ v1が安定版(stable)・v1beta1はベータ・v1alpha1はアルファ(本番では使用しない)
kubectl api-resources — リソース種別と shortNames
実行コマンド:
$ kubectl api-resources | head -20
実行結果(抜粋):
NAME SHORTNAMES APIVERSION NAMESPACED KIND
bindings v1 true Binding
componentstatuses cs v1 false ComponentStatus
configmaps cm v1 true ConfigMap
endpoints ep v1 true Endpoints
events ev v1 true Event
limitranges limits v1 true LimitRange
namespaces ns v1 false Namespace
nodes no v1 false Node
persistentvolumeclaims pvc v1 true PersistentVolumeClaim
persistentvolumes pv v1 false PersistentVolume
pods po v1 true Pod
podtemplates v1 true PodTemplate
replicationcontrollers rc v1 true ReplicationController
resourcequotas quota v1 true ResourceQuota
secrets v1 true Secret
serviceaccounts sa v1 true ServiceAccount
services svc v1 true Service
...
SHORTNAMES は CKAD 試験で頻繁に使う短縮形です。kubectl get po(= kubectl get pods)・kubectl get svc(= kubectl get services)・kubectl get deploy(= kubectl get deployments)のように使えます。
NAMESPACED 列が true のリソースは Namespace スコープ(デフォルト namespace に属する)・false はクラスタスコープ(Node / ClusterRole など)です。
API バージョンと非推奨 API の仕組み
K8s は後方互換性を重視しますが、古い API バージョンは「非推奨(Deprecated)」を経て「削除(Removed)」されます。代表的な例として extensions/v1beta1 の Ingress は K8s v1.16 で削除されました。
現在の安定した API バージョン(本シリーズで使用するもの):
| リソース | 安定バージョン | 備考 |
|---|---|---|
| Pod / Service / ConfigMap | v1 | core API。将来も継続 |
| Deployment / ReplicaSet | apps/v1 | K8s v1.9 で stable |
| CronJob | batch/v1 | K8s v1.21 で stable |
| Ingress | networking.k8s.io/v1 | extensions/v1beta1 は削除済み |
kubectl convert(概念のみ・試験対策上の優先度は低い)
kubectl convert は古い apiVersion のマニフェストを新しい apiVersion に変換するコマンドです。ただし CKAD v1.35 試験では kubectl convert 自体が直接出題されません。概念として把握するにとどめます。
重要な点:kubectl convert は kubectl コアの組み込みコマンドではなく krew プラグインとして提供されます(kubectl krew install convert でインストール)。krew 自体のインストール手順は本シリーズのスコープ外です。ep15(CRD 回)で krew の概念を再紹介します。
非推奨 API を一括スキャンするツールとして Fairwinds の pluto(v5.24.0)等が存在します。kubectl プラグインとして動作し、クラスタ内の全リソースをスキャンして非推奨 API を検出できます。本シリーズでは「こういうツールが存在する」という認識にとどめます。
ラベルセレクタ — -l フラグで Pod を絞り込む
kubectl get の -l オプションで、特定のラベルを持つリソースだけを絞り込めます。第8回 Service の spec.selector・第16回 NetworkPolicy の podSelector への布石として、ep6 でラベルセレクタの基本を習得します。
ラベルとは何か
ラベルは K8s リソースに付与できるキー・バリューのメタデータです。kubectl run で作成した Pod には run=<name> ラベルが自動付与されます(実機の kubectl get pod nginx-test --show-labels で run=nginx-test ラベルを確認できます)。
ラベルの確認
実行コマンド:
$ kubectl get pod nginx-test --show-labels
実行結果:
NAME READY STATUS RESTARTS AGE LABELS
nginx-test 1/1 Running 0 29s run=nginx-test
等値セレクタ
実行コマンド(run=nginx-test のラベルを持つ Pod のみ表示):
$ kubectl get pods -l run=nginx-test
集合セレクタ
実行コマンド(run が nginx-test または crash-test のどちらかの Pod):
$ kubectl get pods -l 'run in (nginx-test, crash-test)'
否定セレクタ
実行コマンド(run=nginx-test 以外の Pod):
$ kubectl get pods -l run!=nginx-test
全 Namespace + ラベル絞り込み
実行コマンド(全 Namespace で component=etcd ラベルを持つ Pod):
$ kubectl get pods -A -l component=etcd
ep8・ep16 への橋渡し:Service リソースの spec.selector は「どの Pod にトラフィックを転送するか」をラベルで指定します(第8回で詳解)。NetworkPolicy の podSelector は「どの Pod に通信ポリシーを適用するか」をラベルで指定します(第16回で詳解)。ラベルは K8s でリソースを管理するための中核的な仕組みです。
現場ヒヤリハット — kubectl logs でターミナルが止まった / exec 中に Pod が消えた
事例1:kubectl logs で大量ログがターミナルを埋め尽くした
状況:本番(kubeadm)で運用中の backend Pod のアクセスログを確認しようと kubectl logs backend-pod を実行したところ、数万行のアクセスログがターミナルに流れ続けた。Ctrl+C で止めようとしたが、次に打つコマンドがログに埋もれてしまい、作業効率が大きく落ちた。
原因:kubectl logs はデフォルトでコンテナ起動から現在までの全ログを出力します。長時間稼働しているコンテナでは数十万行になることがあります。nginx や Java アプリのアクセスログは特に行数が多くなりがちです。
対策:
--tail=50:末尾 50 行のみ取得(調査の起点として十分なことが多い)--since=5m:直近 5 分のみ取得(インシデント発生直後の調査に有効)-c <container>:マルチコンテナ Pod の特定コンテナのみ指定(第7回で扱うマルチコンテナ Pod に対応)
教訓:本番 Pod のログ確認は必ず --tail か --since を付けることを習慣にします。CI/CD ツールのログ管理(Loki + Fluent Bit・第2巻第13回で登場)が整備されてからはそちらを優先し、kubectl logs は緊急時の補助手段として位置づけます。
事例2:kubectl exec セッション中に Pod が削除されてセッション強制切断された
状況:デプロイメント担当者が kubectl exec -it backend-xxx -- /bin/sh で Pod に入ってデバッグ作業をしていたところ、別の担当者が Deployment のローリングアップデートを実行(Deployment は第12回で詳しく学ぶリソース)。Pod が削除 + 再作成され、exec セッションが強制切断された。
原因:kubectl exec のセッションは Pod の生存に完全に依存します。Pod が削除されると exec セッションも即座に切断されます。Deployment のローリングアップデートは古い Pod を削除しながら新しい Pod を起動するため、exec 中の Pod が削除対象になることがあります。
対策:
- デバッグ中は別の担当者に「今 exec で作業中」と必ず共有する
- 本番でのデバッグは
kubectl debug(Ephemeral Container)を使う(第7回で学ぶ) - exec 作業は迅速に完了する。長時間の調査作業は別の方法(ログ収集・ダンプ取得)で行う
教訓:kubectl exec は「今起動している Pod のシェル」に接続していることを常に意識します。Pod の削除 = セッション切断です。本番での調査は迅速に、かつ作業前にチームに共有することが重要です。
理解度チェック + まとめ + 次回予告 + シリーズ一覧
理解度チェック(○× 形式・全 9 問)
第6回の理解度を確認します。○か×で答えてください。
問 1:kubectl describe pod の Events セクションには、Pod のスケジューリング・イメージ pull・コンテナ起動の経緯が時系列で記録される。
問 2:kubectl logs --previous は現在起動中のコンテナのログを表示する。
問 3:kubectl exec -it pod-name -- /bin/bash は、対象 Pod の中に bash がなくても実行できる。
問 4:kubectl top pod を実行するには、クラスタに metrics-server が必要である。
問 5:kubectl api-resources の SHORTNAMES 列に表示される po(Pod の略)は、kubectl get po のように使用できる。
問 6:kubectl apply -f は対象リソースが存在しない場合はエラーになり、何も作成しない。
問 7:kubectl explain pod.spec.containers を実行すると、Pod の spec.containers フィールドの説明とサブフィールド一覧が表示される。
問 8:kubectl get pods -l app=nginx は、app=nginx というラベルを持つ Pod のみを表示する。
問 9:kubectl convert は kubectl に組み込まれたコアコマンドであり、追加インストールなしで使用できる。
解答:
| 問 | 解答 | 解説(重要問のみ) |
|---|---|---|
| 問 1 | ○ | — |
| 問 2 | × | –previous は直前に終了したコンテナのログを表示する。現在起動中ではない |
| 問 3 | × | bash が存在しないイメージ(alpine 系など)では /bin/bash はエラーになる。/bin/sh を使う |
| 問 4 | ○ | kubectl top は metrics-server が提供する Metrics API を使用する。metrics-server がなければ error: Metrics API not available |
| 問 5 | ○ | — |
| 問 6 | × | kubectl apply -f はリソースが存在しなければ新規作成し、存在すれば差分を更新する冪等な操作。エラーにはならない |
| 問 7 | ○ | — |
| 問 8 | ○ | — |
| 問 9 | × | kubectl convert はプラグインであり、krew でインストールする必要がある。kubectl コアには含まれていない |
第6回まとめ
第6回では以下を実施しました。
- kubectl は
~/.kube/configを読み込んで API Server に HTTPS で接続する。kind create clusterで kubeconfig が自動生成される仕組みを確認した alias k=kubectlと Tab 補完を~/.bashrcに永続設定した。以降全回でk/kubectlを両方使用するkubectl explain <resource>.<field>で YAML スキーマを kubernetes.io を開かずに確認できることを確認した。CKAD 試験中でも使用可能- CrashLoopBackOff の調査は「get pods → describe → logs –previous → exec → get events」の順で行うデバッグフローを実践した
- metrics-server v0.8.1 を kind クラスタに導入し、
kubectl topでリソース使用量を確認した。kind 環境では--kubelet-insecure-tlsフラグが必要だが、本番(kubeadm)では不要 - CKAD D3(Application Observability and Maintenance・15 %)の全 Competency(API デプリケーション / 組み込み CLI ツール / コンテナログ / Kubernetes でのデバッグ)を網羅した
次回予告
第7回 Pod + Multi-container パターンでは、Pod の YAML 定義を完全に習得します。Init Container でデータベース接続待ちを実装し、Sidecar コンテナでログ転送を実現します。
OOMKilled を意図的に発生させてデバッグするハンズオンも含まれます。今回覚えた kubectl describe / kubectl logs --previous が第7回のデバッグ演習でそのまま活きます。
シリーズ一覧
第1部:コンテナと Docker
- 第1回 コンテナ技術概念 + Docker 環境準備
- 第2回 Docker 基本操作
- 第3回 Dockerfile + マルチステージビルド + JDK 25 / Payara Micro イメージビルド
- 第4回 コンテナレジストリ + イメージタグ戦略 + Trivy スキャン
第2部:Kubernetes 基礎
- 第5回 Kubernetes の全体像 + kind で軽量 K8s
- 第6回 kubectl 基本操作 + Observability・Debug ← 今ここ
第3部:アプリリソース
- 第7回 Pod + Multi-container パターン
- 第8回 Service とネットワーキング
- 第9回 ストレージ(PVC + StatefulSet)+ PostgreSQL DB 追加
- 第10回 ConfigMap + Secret + ServiceAccount 基礎
- 第11回 Job + CronJob + DaemonSet
第4部:ワークロード戦略
- 第12回 Deployment + 3 Probe + Rolling Update + Probe デバッグ実践
- 第13回 Deployment 戦略補完(Blue/Green + Canary + Recreate)
- 第14回 ResourceQuota + LimitRange + Multi-tenant Namespace
