本記事には広告(アフィリエイトリンク)が含まれます。

kubectl基本操作とPodデバッグ入門【CKAD第6回】

広告
広告

第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.0Docker 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)
contextscluster と 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 コマンド実行フロー図 - 左から kubectl(端末アイコン)→ ~/.kube/config(設定ファイルアイコン)→ HTTPS/TLS 矢印 → kube-apiserver(サーバーボックス)→ etcd(データベースシリンダー)。kube-apiserver から Scheduler・kubelet への分岐矢印も表示。

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)では kkubectl の両方を使います。

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 前の変更内容確認・誤適用防止
explainYAML スキーマ確認YAML を書く前のフィールド確認・試験中の即座参照
kubectl コマンド体系図 - 中央に kubectl ハブを置き、4 グループを 2×2 に配置。確認系(get / describe / explain)・ログ系(logs)・デバッグ系(exec)・操作系(apply / diff)。各コマンドに一言説明付き。

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 yamlYAML 完全出力(現在の状態確認・マニフェスト生成)既存リソースを元に YAML を編集したい・クラスタの実際の設定を確認したい
-o jsonJSON 完全出力(スクリプト処理・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 = 全コンテナが起動・準備完了
STATUSPod の現在の状態Running = 正常稼働。ContainerCreating / Pending は起動中
RESTARTSコンテナの再起動回数0 = 一度も再起動していない。増えている場合は何らかのエラー
AGEPod が作成されてからの経過時間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 セクションの各列の読み方:

列名意味
TypeNormal(通常)または 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 は「何も出力せずに終了」するため、ログは空です。実際のアプリケーションでは OutOfMemoryErrorConnection 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.1asia-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

単位の読み方:

  • CPUm(millicores)単位。1000m = 1 CPU コア。100m = CPU 1 コアの 10 % を使用中
  • MEMORYMi(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 / ConfigMapv1core API。将来も継続
Deployment / ReplicaSetapps/v1K8s v1.9 で stable
CronJobbatch/v1K8s v1.21 で stable
Ingressnetworking.k8s.io/v1extensions/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-labelsrun=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回の理解度を確認します。○か×で答えてください。

問 1kubectl describe pod の Events セクションには、Pod のスケジューリング・イメージ pull・コンテナ起動の経緯が時系列で記録される。

問 2kubectl logs --previous は現在起動中のコンテナのログを表示する。

問 3kubectl exec -it pod-name -- /bin/bash は、対象 Pod の中に bash がなくても実行できる。

問 4kubectl top pod を実行するには、クラスタに metrics-server が必要である。

問 5kubectl api-resources の SHORTNAMES 列に表示される po(Pod の略)は、kubectl get po のように使用できる。

問 6kubectl apply -f は対象リソースが存在しない場合はエラーになり、何も作成しない。

問 7kubectl explain pod.spec.containers を実行すると、Pod の spec.containers フィールドの説明とサブフィールド一覧が表示される。

問 8kubectl get pods -l app=nginx は、app=nginx というラベルを持つ Pod のみを表示する。

問 9kubectl convert は kubectl に組み込まれたコアコマンドであり、追加インストールなしで使用できる。

解答

解答解説(重要問のみ)
問 1
問 2×–previous は直前に終了したコンテナのログを表示する。現在起動中ではない
問 3×bash が存在しないイメージ(alpine 系など)では /bin/bash はエラーになる。/bin/sh を使う
問 4kubectl 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

第2部:Kubernetes 基礎

第3部:アプリリソース

第4部:ワークロード戦略

第5部:セキュリティ基礎

第6部:パッケージ管理 + HTTPS 公開

広告
kubernetes
スポンサーリンク