🖥️

【4-3.5】【K8sトラブルシューティング】PodがPendingのまま起動しない!原因は「ディスク圧迫」だった

に公開

【K8sトラブルシューティング】PodがPendingのまま起動しない!原因は「ディスク圧迫」だった

はじめに

Kubernetesの学習中、Deploymentを作成してk applyを実行!…したのはいいものの、k get podsで状態を見ると、待てど暮らせどSTATUSPendingのまま変わらない…という**「Pending地獄」** に陥りました。
テザリング環境で学習していたため、最初は「ネットワークが不安定でイメージのダウンロードに失敗してるのかな?」と見当違いの予想を立てていました。
しかし、Kubernetesのdescribeコマンドを使ったところ、原因はネットワークではなくサーバーのディスク容量不足であることが判明しました。この記事では、その特定から解決までの一部始終を共有します。

Step 1: 症状の確認 (Pending地獄)

k apply -f nginx-deployment.yamlを実行した後、Podの状態を確認すると、以下のようにSTATUSPendingのまま、READY0/1から一向に進みませんでした。

adm-labuser@us01:~/k8s-practice$ k get pods -l app=nginx
NAME                                  READY   STATUS    RESTARTS   AGE
nginx-deployment-7fdd7f7c9c-czs7w   0/1     Pending   0          21m
nginx-deployment-7fdd7f7c9c-h6mb8   0/1     Pending   0          21m
nginx-deployment-7fdd7f7c9c-zgkjl   0/1     Pending   0          21m

Pendingは、Podがまだどのノード(サーバー)にも配置(スケジュール)されていない、または起動準備段階で止まっていることを示します。

Step 2: 原因の特定 (ネットワークではなかった!)

Pendingの理由を突き止めるための最強のコマンドがk describe podです。
Pod名を1つ指定して、詳細な状態とイベントログを確認します。

# Pod名は自分の環境に合わせて指定
k describe pod nginx-deployment-7fdd7f7c9c-czs7w

すると、一番下のEvents:セクションに、決定的なエラーメッセージが出力されていました。

Events:
  Type     Reason            Age                  From               Message
  ----     ------            ----                 ----               -------
  Warning  FailedScheduling  23m                  default-scheduler  0/1 nodes are available: 1 node(s) had untolerated taint {node.kubernetes.io/disk-pressure: }. preemption: 0/1 nodes are available: 1 Preemption is not helpful for scheduling.

FailedScheduling(スケジューリング失敗)の理由として、「disk-pressure(ディスク圧迫)」 というtaint(汚染/印)がノードに付いているため、配置できるノードが0台だった、と書かれています。

Step 3: 「ディスク圧迫 (Disk Pressure)」とは?

これはKubernetesの安全装置が作動している状態です。

  1. k3sが動いているサーバー(ノード)が、「自分のディスク空き容量がヤバい!」(例: 90%以上使用中)と検知しました
  2. ノードはこれ以上新しいPodを受け入れると危険だと判断し、自身に 「disk-pressure」というtaint(印) を付けます
  3. default-scheduler(Podの配置係)は、この印が付いたノードを「不健康」とみなし、新しいPodの配置を拒否します
  4. その結果、私たちのNginx Podは行き場を失い、Pendingのまま待ちぼうけになっていたのです

Step 4: 根本原因の確認 (df -h)

Kubernetesが「ディスクが一杯だ」と教えてくれたので、実際にサーバー(ubuntu-server-01)のディスク使用率を確認します。

adm-labuser@us01:~$ df -h
Filesystem                        Size  Used Avail Use% Mounted on
...
/dev/mapper/ubuntu--vg-ubuntu--lv   15G   13G  1.1G  93% /
...

ビンゴでした。
ルートファイルシステム(/)が93%も使用されており、空き容量は1.1Gしかありません。これではdisk-pressureと判断されても仕方ありません。
(原因は、以前のDocker学習で使ったイメージや、k3s自体のイメージなどで圧迫されていました)

なぜこのパスが「ubuntu-server-01」の容量だと分かるのか?

df -hの結果には多くのデバイスが表示されますが、なぜ/dev/mapper/ubuntu--vg-ubuntu--lvが「OS本体の容量」だとすぐに判断できたのでしょうか?
理由は、df -hの出力結果の2つの列にあります。

Filesystem                          Size  Used Avail Use% Mounted on
...
/dev/mapper/ubuntu--vg-ubuntu--lv   15G   13G  1.1G  93% /
...

1. Mounted on列が / だったから

Mounted on / は、このデバイスが 「ルートファイルシステム」 であることを示します。
/(ルート)は、Linuxシステムの最上位ディレクトリ(根っこ)です。OSのシステムファイル、アプリケーション、ユーザーのホームディレクトリなど、すべてがこの/の下にぶら下がっています。
つまり、/にマウントされているデバイスこそが、OS本体がインストールされているメインのディスク領域です。

2. Filesystem列の名前から「LVM」と「Ubuntu」が読み取れたから

/dev/mapper/ubuntu--vg-ubuntu--lvというパス名は、以下のように分解できます。

  • /dev/mapper/: これは、OSがLVM(Logical Volume Management) というディスク管理技術を使っていることを示す共通のプレフィックスです。
  • ubuntu--vg-ubuntu--lv: これはLVMの命名規則 [VG名]-[LV名] に従っています
    • VG (Volume Group) 名: ubuntu-vg
    • LV (Logical Volume) 名: ubuntu-lv
      これは、Ubuntuサーバーを「LVMを使用する」設定で標準インストールした際、インストーラーがホスト名(ubuntu)に基づいて自動生成する、非常に典型的なデフォルト名です。

結論

**「/(ルート)にマウントされている」**+ ubuntuという名前のLVMデバイス」 という2つの情報から、これがubuntu-server-01のOS本体の容量だと即座に断定できました。

Step 5: 根本解決 (VMのディスク拡張)

解決策は、サーバーのディスク容量を増やすことです。
私の環境はProxmoxVE上のVM(Ubuntu)で、LVM(Logical Volume Management) が使われていました。
Proxmox Web UIでVMのハードディスクサイズを15Gから32Gに増やした後(「ハードウェア」→「ディスク操作」)、VM内部でOSに拡張を認識させる必要がありました。

1. パーティションの確認

lsblkで現状を確認すると、OSが使う領域(ubuntu--lv)がまだ14.5Gのままで、拡張した領域が使われていないことがわかりました。

adm-labuser@us01:~$ lsblk
NAME                      MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
...
vda                       252:0    0   32G  0 disk
├─vda1                    252:1    0    1G  0 part /boot/efi
├─vda2                    252:2    0    2G  0 part /boot
└─vda3                    252:3    0 28.9G  0 part
  └─ubuntu--vg-ubuntu--lv 253:0    0 14.5G  0 lvm  /

(vda3が28.9Gあるのに、ubuntu--lvが14.5Gしか使っていない状態)

2. LVM拡張コマンドの実行

LVMの拡張は、以下の3ステップで完了します。

# 1. 物理ボリューム(vda3)のサイズ変更をLVMに通知
sudo pvresize /dev/vda3
# 2. 論理ボリューム(ubuntu--lv)を、利用可能なすべての空き容量を使って拡張
sudo lvextend -l +100%FREE /dev/mapper/ubuntu--vg-ubuntu--lv
# 3. ファイルシステム(resize2fs)を、論理ボリュームのサイズに合わせて拡張
sudo resize2fs /dev/mapper/ubuntu--vg-ubuntu--lv
【補足】LVMディスク拡張の謎:`pvresize`, `lvextend`, `resize2fs` は何をしているのか?

df -hlsblkを叩くと/dev/mapper/ubuntu--vg-ubuntu--lvのような謎のパスに出会い、disk-pressureエラーの解決のためにpvresize, lvextend, resize2fsという3つのコマンドを実行しました。
これらが何なのかを理解するために、LVMの「なぜ?」と「仕組み」を整理します。

LVMが解決する「従来の問題」

LVMがない時代(従来のパーティショニング)では、OSインストール時に「/に30GB」「/homeに70GB」と、カッチリとコンクリートの壁で仕切る必要がありました。後から/homeが足りなくなっても、/の空きを移動するのは非常に困難でした。

LVMの解決策:「抽象化」という魔法

LVMは、この問題を解決するために「物理的なディスク」と「OSが使う領域」の間に、柔軟な管理レイヤーを挟み込みます。

例えるなら「ねんど(粘土)」です。 複数のディスク(ねんどの塊)を全部まとめて、一つの巨大な「ねんどの玉」 にし、そこから必要な分だけちぎって/用の皿」や「/home用のコップ」を作ります。皿が小さすぎたら、玉からねんどを足して大きくできます。

LVMの階層構造と今回の問題点

このLVMの仕組みを、今度は「家と土地」の例えで、今回のlsblkの結果に当てはめてみます。

lsblkで判明した状況:
「32Gの土地(vda)に、28.9Gの区画(vda3)は確保したが、LVMの登記簿(PV)と家(LV)が古い14.5Gのまま」

階層 名称 lsblkでの実体 例え 問題点
物理 物理パーティション vda3 土地 28.9Gある。問題なし。
LVM層 1 PV (Physical Volume) (PV on vda3) 登記簿 古い14.5Gのまま。
LVM層 2 VG (Volume Group) ubuntu-vg 団地 登記簿が古いため「空き地」を認識していない。
LVM層 3 LV (Logical Volume) ubuntu--vg-ubuntu--lv 14.5Gの広さで、団地いっぱいに建っている。
OS層 ファイルシステム (ext4など) 間取り 14.5Gの家いっぱいに間取りが引かれている。

解決の3ステップ

この「登記簿」「家」「間取り」のズレを、下(物理層)から順番に修正していったのが、あの3つのコマンドです。

1. sudo pvresize /dev/vda3

  • やっていること: 物理ボリューム(PV)のサイズ変更。
  • 例えるなら: LVMの登記所に行き、「土地(vda3)の登記簿を更新して! 28.9Gが正しいサイズですよ」と通知する。
  • 結果: LVMが「団地(VG)」に14.4Gの「空き地」があることを認識する。

2. sudo lvextend -l +100%FREE ...

  • やっていること: 論理ボリューム(LV)の拡張。
  • 例えるなら: LVMの管理会社に「ウチの家(lv)を増築したい。団地内の空き地を全部(+100%FREE)使って広げてくれ」と指示する。
  • 結果: 「家(LV)」の敷地が14.5Gから28.9Gに広がる。(ただし、中の間取りは古いまま)

3. sudo resize2fs ...

  • やっていること: ファイルシステムの拡張。
  • 例えるなら: OS(大工さん)に「家が広くなったぞ! 壁をぶち抜いて、間取り(Filesystem) を新しい壁(28.9G)まで広げてくれ」と指示する。
  • 結果: OSがdf -h28Gの全領域を認識できるようになり、ディスクの空き容量が確保される。

このように、LVMでは「登記の更新」→「家の増築」→「間取りの変更」という3ステップを踏むことで、安全にディスクを拡張できるのです。

【補足】`pvresize` と `vgextend` の違い:なぜVGへの追加コマンドが不要だったのか?

LVMの拡張ステップで、pvresizeを実行しただけで、vgextendのような「VG(ボリュームグループ)に追加する」コマンドが不要だったことに疑問を持ったかもしれません。

それは、pvresizeが「既存の材料」のサイズ変更を通知するコマンドだからです。

1. pvresize(今回やったこと)

  • 目的: 既にVGのメンバーであるPV(物理ボリューム, 例: /dev/vda3)のサイズが大きくなったことをVGに通知(リサイズ) する。
  • 例えるなら: 「団地」の既存の土地(vda3 が、隣の土地を買収して28.9Gに広がった。pvresizeは、その土地の登記簿を更新する手続きです。
  • 結果: VGは「お、ウチの団地の土地が広くなったな」と自動的に認識し、空き容量が増えます。

2. vgextend(今回やらなかったこと)

  • 目的: VGのメンバーではなかった、まったく新しいPV(例: 新しく増設したディスク /dev/vdb1)を、VGに追加(エクステンド) する。
  • 例えるなら: 「団地(ubuntu-vg)」の隣に、新しい土地(/dev/vdb1 を買い増し、それを団地の敷地として組み込む手続きです。
  • 手順:
    1. pvcreate /dev/vdb1 (新しい土地をLVM用に登記する)
    2. vgextend ubuntu-vg /dev/vdb1 (その土地を「ubuntu-vg」団地の一部として組み込む)
  • 結果: VGの総容量が「既存の土地+新しい土地」の分だけ増えます。

まとめ:
今回は「既存の土地」が広がっただけなのでpvresize(登記更新)だけで済みましたが、もし「新しい土地」を増設していた場合はvgextend(組み込み)が必要になっていました。

3. 拡張の確認

再度df -hを実行すると、無事にディスクが拡張されました。

adm-labuser@us01:~$ df -h
Filesystem                        Size  Used Avail Use% Mounted on
...
/dev/mapper/ubuntu--vg-ubuntu--lv   28G   13G   14G  50% /
...

使用率が93%から50% に改善しました!

Step 6: 復旧の確認

ディスクの空き容量が確保されると、Kubernetesはdisk-pressureの状態が解消されたことを自動的に検知し、ノードに付けていたtaint(印)を自動で解除します。
taintが解除されると、PendingだったPodのスケジューリングが自動的に再開されます。
k get podsを監視モード(-w)で見ていると、劇的な変化が訪れました。

adm-labuser@us01:~/k8s-practice$ k get pods -l app=nginx -w
NAME                                  READY   STATUS    RESTARTS   AGE
nginx-deployment-7fdd7f7c9c-czs7w   0/1     Pending   0          50m
nginx-deployment-7fdd7f7c9c-h6mb8   0/1     Pending   0          50m
nginx-deployment-7fdd7f7c9c-zgkjl   0/1     Pending   0          50m
# (ディスク拡張後、数分待つと...)
nginx-deployment-7fdd7f7c9c-zgkjl   0/1     ContainerCreating   0          51m
nginx-deployment-7fdd7f7c9c-czs7w   0/1     ContainerCreating   0          51m
nginx-deployment-7fdd7f7c9c-h6mb8   0/1     ContainerCreating   0          51m
# (テザリング環境なのでイメージDLに少し時間がかかり...)
nginx-deployment-7fdd7f7c9c-zgkjl   1/1     Running             0          52m
nginx-deployment-7fdd7f7c9c-czs7w   1/1     Running             0          52m
nginx-deployment-7fdd7f7c9c-h6mb8   1/1     Running             0          52m

無事にRunningになりました!

まとめ

トラブルシューティングの教訓
症状だけで原因を推測せず、ログ(k describek get events)を確認することで、正確な原因に素早くたどり着けます。Kubernetesは親切にもEventsに詳細な情報を残してくれるので、まずはそこを確認する習慣をつけましょう。

Discussion