0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Kubernetes⑥(全7回)|kind|運用:ログ・監視・トラブルシュート — kubectlを武器にする

0
Last updated at Posted at 2026-02-18

シリーズ記事一覧

📑 目次

  1. この記事について
  2. この記事のゴール
  3. 前提条件
  4. Docker Composeではこうだった(Before)
  5. k8sではこうなる(After)
  6. ハンズオン:壊して直す3つのシナリオ
  7. 実務で使うkubectlコマンド集
  8. つまずきポイント(体験談)
  9. まとめ
  10. 次回予告

1. この記事について

ここまで5回にわたって、k8sの主要リソースを学んできました。
Pod、Service、ConfigMap、Secret、Namespace、RBAC... 「作る」ことはできるようになりました。

でも、実務で最も時間を使うのは作ることではなく、直すことです。

🍽️ レストランを開店するのは1回。
でも毎日の営業(トラブル対応・品質管理)はずっと続く。
「コンロの火がつかない!」「食材が届かない!」「お客さんから料理が出てこないとクレーム!」— これらに対応するスキルが、実務では最も求められます。

今回は意図的にPodを壊して、調査→特定→修正の流れを体験します。


2. この記事のゴール

この記事で書いていること:

  • logs / describe / exec の使い分けの整理
  • 「Podが起動しない!」の原因を3パターン体験してみた話
  • トラブルシュートの思考フロー
  • 実務でよく使うkubectlコマンド集

3. 前提条件

項目 要件
前回の完了 第5回でNamespace/RBACを理解済み
クラスタ状態 kindクラスタが起動中
# WSL2 Ubuntu で実行

kubectl get nodes

4. Docker Composeではこうだった(Before)

4-1. Docker Composeの調査コマンド

# ログを見る
docker-compose logs web

# コンテナに入る
docker-compose exec web bash

# コンテナの状態を見る
docker-compose ps

シンプルで分かりやすい。
コンテナが1〜3個なら十分です。

4-2. でもこの壁がある

しかし、コンテナの数が増えると以下の限界が見えてきます。

# Docker Composeの現実
壁1 複数コンテナの横断調査が辛い 1つずつログを見て回る
壁2 「なぜ起動しないか」の情報が少ない docker-compose ps は Exit Code くらい
壁3 コンテナが消えるとログも消える ログの永続化は自分で設定

5. k8sではこうなる(After)

5-1. 調査コマンド3兄弟

k8sのトラブルシュートは、主に3つのコマンドで行います。

🍽️ 比喩:本部のトラブル対応ツール

コマンド 比喩 いつ使う
kubectl logs 防犯カメラの映像 「何が起きたか」を時系列で確認
kubectl describe 店舗の点検報告書 「設備の状態」「最近のイベント」を確認
kubectl exec 店舗に直接行って確認 現場で実際に触って調査

5-2. 3兄弟の使い分け

3つのコマンドの違いを整理しましょう。
「どんな情報が欲しいか」で使い分けます。

コマンド 得られる情報 対応するDocker 最初に見る場面
kubectl logs <pod> アプリの標準出力/エラー docker logs アプリがエラーを吐いている
kubectl describe <resource> リソースの設定・状態・イベント (該当なし) Podが起動しない・Pendingのまま
kubectl exec -it <pod> -- bash コンテナ内のリアルタイム状態 docker exec アプリは動いてるが応答がおかしい

🔰 Note: 迷ったら describe から始める のが鉄則だと実感しました。
Eventsセクションに「なぜ」が書いてあることが多いです。

🔰 Memo: describe の出力は長いですが、全部読む必要はありません。最後の Events セクションだけ見れば、たいていの原因がわかります:

kubectl describe pod <Pod名> | grep -A 20 "Events:"

5-3. トラブルシュートの思考フロー

🍽️ これは「本部のトラブル対応マニュアル」です。
電話がかかってきたら、まず「店舗の状態は?」を聞いて、症状に応じて調査方法を変える。


6. ハンズオン:壊して直す3つのシナリオ

6-1. 作業ディレクトリ

# WSL2 Ubuntu で実行

mkdir -p ~/k8s-handson/troubleshoot
cd ~/k8s-handson/troubleshoot

6-2. シナリオ1:ImagePullBackOff — 食材が届かない

🍽️ 「特上マグロを注文したけど、そんな食材は存在しない!」→ 食材が届かず開店できない

6-2-1. 壊れたPodを作成

~/k8s-handson/troubleshoot/
└── broken-image.yaml   # ここに作成
# broken-image.yaml
# ❌ 意図的に壊れたPod(存在しないイメージ名)

apiVersion: v1
kind: Pod
metadata:
  name: broken-image
spec:
  containers:
    - name: app
      image: nginx:99.99.99    # ← 存在しないバージョン!
      ports:
        - containerPort: 80
# ~/k8s-handson/troubleshoot/ で実行

kubectl apply -f broken-image.yaml

# 少し待ってから状態を確認
kubectl get pods

期待される出力:

NAME           READY   STATUS             RESTARTS   AGE
broken-image   0/1     ImagePullBackOff   0          30s

ImagePullBackOff — イメージの取得に失敗しています。

6-2-2. 調査:kubectl describe

kubectl describe pod broken-image

注目するのは最下部の Events セクション:

Events:
  Type     Reason     Age   From               Message
  ----     ------     ----  ----               -------
  Normal   Scheduled  30s   default-scheduler  Successfully assigned default/broken-image to ...
  Normal   Pulling    28s   kubelet            Pulling image "nginx:99.99.99"
  Warning  Failed     25s   kubelet            Failed to pull image "nginx:99.99.99": ... not found
  Warning  Failed     25s   kubelet            Error: ErrImagePull
  Normal   BackOff    10s   kubelet            Back-off pulling image "nginx:99.99.99"
  Warning  Failed     10s   kubelet            Error: ImagePullBackOff

6-2-3. Eventsの読み方

意味
Type Normal(正常)/ Warning(警告)
Reason イベントの種類
Message 具体的な内容 ← ここが最重要

🍽️ 点検報告書(describe)の「最近のイベント」欄に「食材 nginx:99.99.99 は見つかりませんでした」と書いてある。
原因は明確:イメージ名の間違い

6-2-4. 修正

⚠️ 重要: kubectl set imageDeployment / StatefulSet 等のコントローラ配下のPod にしか使えません。
今回のように Pod単体 で作った場合は、削除して作り直すのが正しい手順です。

# ① YAMLのイメージ名を修正してから再作成
kubectl delete pod broken-image
kubectl apply -f broken-image.yaml

# ② 確認
kubectl get pods --watch

🍽️ 仕込み済みの食材(Pod)が腐っていたら、捨てて(delete)新しく仕込み直す(apply)しかない。
シフト表(Deployment)経由なら、店長が自動で差し替えてくれる(set image)。

6-2-5. 学び

覚えること 内容
症状 ImagePullBackOff / ErrImagePull
調査 kubectl describe pod → Events
原因 イメージ名・タグの間違い、レジストリへの接続失敗
修正 正しいイメージ名に変更

6-3. シナリオ2:CrashLoopBackOff — スタッフが出勤直後に倒れる

🍽️ 「新人スタッフが出勤するたびに即倒れる。
何度送り出してもダメ」→ アプリのエラーで起動直後にクラッシュ

6-3-1. 壊れたPodを作成

~/k8s-handson/troubleshoot/
├── broken-image.yaml
└── broken-crash.yaml   # ここに作成
# broken-crash.yaml
# ❌ 意図的に壊れたPod(起動直後にエラー終了)

apiVersion: v1
kind: Pod
metadata:
  name: broken-crash
spec:
  containers:
    - name: app
      image: busybox
      # 存在しないコマンドを実行 → エラー終了
      command: ["this-command-does-not-exist"]
# ~/k8s-handson/troubleshoot/ で実行

kubectl apply -f broken-crash.yaml

# 少し待ってから状態を確認
kubectl get pods --watch

期待される出力(時間経過とともに):

NAME           READY   STATUS             RESTARTS     AGE
broken-crash   0/1     CrashLoopBackOff   3 (20s ago)  1m

CrashLoopBackOff — 起動→クラッシュ→再起動を繰り返しています。

Ctrl + C でwatchを終了。

6-3-2. 調査:kubectl logs

# ログを確認
kubectl logs broken-crash

期待される出力:

exec /bin/this-command-does-not-exist: no such file or directory

原因が一発で分かりました。
「存在しないコマンド」を実行しようとしている。

6-3-3. --previous フラグ

CrashLoopBackOff中は、コンテナが起動→クラッシュを繰り返すため、現在のログが取れないことがあります。

# 前回クラッシュ時のログを見る
kubectl logs broken-crash --previous

🍽️ 防犯カメラ(logs)を再生。
スタッフが倒れた瞬間の映像を確認 → 「存在しない道具を使おうとして倒れた」ことが判明。

6-3-4. describe でも確認

kubectl describe pod broken-crash | tail -20

Eventsセクション:

Events:
  Type     Reason     Age                From               Message
  ----     ------     ----               ----               -------
  Normal   Scheduled  1m                 default-scheduler  Successfully assigned ...
  Normal   Pulled     30s (x4 over 1m)   kubelet            Container image "busybox" already present
  Normal   Created    30s (x4 over 1m)   kubelet            Created container app
  Normal   Started    30s (x4 over 1m)   kubelet            Started container app
  Warning  BackOff    5s (x6 over 55s)   kubelet            Back-off restarting failed container

(x4 over 1m) は「1分間で4回繰り返した」という意味。
k8sが何度も再起動を試みていることがわかります。

6-3-5. 修正

# 壊れたPodを削除
kubectl delete pod broken-crash

正しいコマンドでYAMLを修正して再作成します。

6-3-6. 学び

覚えること 内容
症状 CrashLoopBackOff / RESTARTS が増え続ける
調査 kubectl logs--previous も)
原因 アプリのエラー、コマンドミス、設定不足
修正 アプリのコード/設定を修正

6-4. シナリオ3:Runningなのに応答しない — 設定ミス

🍽️ 「スタッフは出勤してるのに、お客さんの注文に応えない。
何か伝達ミスがある?」

6-4-1. ConfigMap + Pod + Serviceを作成

~/k8s-handson/troubleshoot/
├── broken-image.yaml
├── broken-crash.yaml
├── broken-config.yaml     # ここに作成(ConfigMap + Deployment + Service)
# broken-config.yaml
# ❌ ConfigMapの設定ミスでヘルスチェックが失敗するシナリオ

---
# ConfigMap(nginx設定)
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-broken-config
data:
  default.conf: |
    server {
        listen       8080;
        server_name  localhost;
        location / {
            root   /usr/share/nginx/html;
            index  index.html;
        }
    }

---
# Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: broken-config-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: broken-config
  template:
    metadata:
      labels:
        app: broken-config
    spec:
      containers:
        - name: nginx
          image: nginx:1.25
          ports:
            - containerPort: 80    # ← ここは80を期待
          volumeMounts:
            - name: config-volume
              mountPath: /etc/nginx/conf.d
      volumes:
        - name: config-volume
          configMap:
            name: nginx-broken-config

---
# Service
apiVersion: v1
kind: Service
metadata:
  name: broken-config-svc
spec:
  type: ClusterIP
  selector:
    app: broken-config
  ports:
    - port: 80                     # ← Serviceは80で受ける
      targetPort: 80               # ← Podの80に転送するが...

🔰 Note: ConfigMapでnginxを listen 8080 にしているのに、ServiceのtargetPortは 80 です。
ポートがずれています。

# ~/k8s-handson/troubleshoot/ で実行

kubectl apply -f broken-config.yaml

# Pod は Running
kubectl get pods

期待される出力:

NAME                                 READY   STATUS    RESTARTS   AGE
broken-config-app-xxxxxxxxx-xxxxx   1/1     Running   0          10s

✅ Running... 見た目は正常です。

6-4-2. 問題を発見する

# Service経由でアクセスしてみる
kubectl run curl-test \
  --image=curlimages/curl \
  --rm -it \
  --restart=Never \
  -- curl -s --max-time 5 broken-config-svc:80

期待される出力:

curl: (28) Connection timed out after 5000 milliseconds

❌ タイムアウト! Podは Running なのに応答しません。

6-4-3. 調査:kubectl exec

# Podの中に入って直接確認
kubectl exec -it deploy/broken-config-app -- bash

Pod内で調査:

# Pod の中で実行

# nginx が何番ポートでlistenしているか確認
cat /etc/nginx/conf.d/default.conf

出力:

server {
    listen       8080;        # ← 8080で待っている!
    ...
}
# 80番ポートにアクセスしてみる
curl -s localhost:80
# → 応答なし(Connection refused)

# 8080番ポートにアクセスしてみる
curl -s localhost:8080
# → Welcome to nginx! が返る

# Pod から出る
exit

🍽️ 店舗に直接行って確認(exec)したら、スタッフは「8080番窓口」で待っていた。
でも本部(Service)は「80番窓口に案内してね」と言っていた。
お客さんが80番に行っても誰もいない!

6-4-4. 修正方法

原因がわかりました。
修正方法は2つ:

方法 修正内容
A ConfigMapの listen 8080listen 80 に変更
B ServiceのtargetPortを 8080 に変更

今回はBで修正します:

# Serviceを修正(targetPortを8080に)
kubectl patch service broken-config-svc --type='json' \
  -p='[{"op": "replace", "path": "/spec/ports/0/targetPort", "value": 8080}]'

# 再度アクセステスト
kubectl run curl-test2 \
  --image=curlimages/curl \
  --rm -it \
  --restart=Never \
  -- curl -s broken-config-svc:80

期待される出力:

<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...

修正完了。
Service経由でnginxにアクセスできるようになりました。

6-4-5. 学び

覚えること 内容
症状 Pod は Running だがアプリが応答しない
調査 kubectl exec でコンテナ内に入って直接確認
原因 ポート設定のミスマッチ、設定ファイルの誤り
修正 ConfigMap または Service の設定を修正

6-5. シナリオのまとめ

シナリオ STATUS 最初に使うコマンド 比喩
1. ImagePullBackOff ImagePullBackOff describe → Events 食材が届かない
2. CrashLoopBackOff CrashLoopBackOff logs(+ --previous スタッフが即倒れる
3. 応答しない Running exec で中に入る 伝達ミス

6-6. 後片付け

# 全てのリソースを削除
kubectl delete pod broken-image --ignore-not-found
kubectl delete pod broken-crash --ignore-not-found
kubectl delete -f broken-config.yaml --ignore-not-found

kubectl get all

7. 実務で使うkubectlコマンド集

7-1. 基本操作

コマンド 用途 頻度
kubectl get pods Pod一覧 ⭐⭐⭐
kubectl get pods -o wide Pod一覧(IP・ノード情報付き) ⭐⭐⭐
kubectl get all 全リソース一覧 ⭐⭐
kubectl get pods --all-namespaces 全NS横断 ⭐⭐

7-2. 調査系

コマンド 用途 頻度
kubectl describe pod <name> 詳細情報 + Events ⭐⭐⭐
kubectl logs <pod> ログ確認 ⭐⭐⭐
kubectl logs <pod> --previous 前回クラッシュ時のログ ⭐⭐
kubectl logs <pod> -f ログをリアルタイム追跡 ⭐⭐
kubectl logs <pod> -c <container> 特定コンテナのログ ⭐⭐
kubectl exec -it <pod> -- bash コンテナに入る ⭐⭐⭐
kubectl exec -it <pod> -- sh bashがない場合 ⭐⭐

7-3. リソース管理

コマンド 用途 頻度
kubectl apply -f <file> 作成・更新(宣言的) ⭐⭐⭐
kubectl delete -f <file> ファイルで指定して削除 ⭐⭐
kubectl scale deployment <name> --replicas=N スケール変更 ⭐⭐
kubectl rollout status deployment <name> デプロイ状況確認 ⭐⭐
kubectl rollout undo deployment <name> ロールバック ⭐⭐

7-4. 情報取得

コマンド 用途 頻度
kubectl get events --sort-by='.lastTimestamp' イベントを時系列で ⭐⭐
kubectl top pods CPU/メモリ使用量 ⭐⭐
kubectl top nodes ノードのリソース状況 ⭐⭐
kubectl auth can-i <verb> <resource> 権限確認

7-5. 便利なショートカット

省略形 正式名
po pods
svc services
deploy deployments
cm configmaps
ns namespaces
sa serviceaccounts
# これらは同じ
kubectl get pods
kubectl get po

kubectl get services
kubectl get svc

kubectl get deployments
kubectl get deploy

8. つまずきポイント(体験談)

8-1. logsが空っぽ — コンテナが起動する前に失敗している

症状: kubectl logs <pod> が何も返さない。

原因: コンテナが起動すらしていない(ImagePullBackOff等)。
ログはコンテナが起動してから出力される。

対策: kubectl describe pod <pod> のEventsを見る。
起動前の情報はここにある。

8-2. exec できない — CrashLoop中のコンテナ

症状:

error: unable to upgrade connection: container not found ("app")

原因: コンテナがクラッシュ→再起動の合間で、接続先がない。

対策:

# デバッグ用コンテナで入る(k8s 1.25+)
kubectl debug -it broken-crash \
  --image=busybox \
  --target=app

8-3. describe の出力が長すぎて迷子になる

対策: Events セクションだけを見る。

# Events だけ抽出
kubectl describe pod <pod> | grep -A 20 "Events:"

🍽️ 点検報告書(describe)は全ページ読む必要はありません。
最後の「最近のイベント」欄だけ見れば、たいていの原因がわかります。


9. まとめ

9-1. この記事でやったこと

# 内容 状態
1 調査コマンド3兄弟(logs / describe / exec)を使い分けた
2 ImagePullBackOff を調査・修正した
3 CrashLoopBackOff を調査・修正した
4 Running だが応答しない問題を調査・修正した
5 実務で使うkubectlコマンド集を確認した

9-2. トラブルシュート早見表

STATUS 最初に見る よくある原因
Pending describe → Events リソース不足、ノード不足
ImagePullBackOff describe → Events イメージ名/タグの間違い
CrashLoopBackOff logs + --previous アプリのエラー、コマンドミス
Running だが異常 exec で中に入る 設定ミス、ポートずれ
Terminating が長い describe → Events Graceful shutdown のタイムアウト

9-3. Docker Compose → k8s 対応表

Docker Compose Kubernetes 備考
docker-compose logs kubectl logs k8sは --previous -f が便利
docker-compose exec kubectl exec 同じ感覚で使える
docker-compose ps kubectl get pods + kubectl describe k8sは情報量が圧倒的に多い
(該当なし) kubectl get events クラスタ全体のイベント一覧

10. 次回予告

第7回:設計総合演習 — 「このアプリをk8sで設計して」に答える

6回にわたって学んだ知識を総動員する最終回です。

🍽️ これまで調理技術(各リソース)を個別に学んできました。
最終回は「コース料理を設計してフルで提供する」総合演習です。

次回は:

  • 「Webアプリをk8sで動かして」という要件に対して、設計から構成図まで一気通貫
  • 第1〜6回の知識を組み合わせた実践的な設計

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?