合うディスクがあるのに PVC がバインドされない
目標
no-provisionerのStorageClassと手で作ったPVを使い、PVCがいつバインドされるのか(WaitForFirstConsumer)、どんな要求だと最後までバインドされないのか(accessModeの不一致)、PVCを削除したあとPVがどう残るのか(Retain → Released)を、自分で観察します。
なぜ重要なのか
Podが消えても、データは残らなければなりません。Kubernetesはそのために、「ディスクそのもの(PV)」と「ディスクをくださいという要求(PVC)」を分け、両者を対応づける仕事をコントローラーに任せています。そのため、PVCがPendingという1つの症状の裏には、「まだ使うPodがないので、わざと待っている最中」と「条件に合うボリュームがそもそもない」という、まったく異なる原因が隠れています。
reclaimポリシーも、運用でよく事故が起きる箇所です。Deleteポリシーだと、PVCを1つ削除しただけでデータが消え、Retainだとデータは守られますが、PVがReleasedのまま残って自動的には再利用されません。両者の違いを知らずにPVCを削除すると、取り返しのつかないことが起こります。
ステップ
- ネームスペース
kcna-storageを作成してください。 - StorageClass
local-fast(no-provisioner、WaitForFirstConsumer、Retain)を作成してください。 - PV
pv-fast-1(1Gi、ReadWriteOnce、Retain、hostPath)を作成してください。 - PVC
dataを作成し、消費者がいないためPendingのままであることを確認してください。 - Pod
writerがdataをマウントすると、PVCがpv-fast-1にバインドされることを確認してください。 - ReadWriteManyを要求するPVC
wideとPodwiderが、最後までバインドされないことを確認してください。 writerとdataを削除し、pv-fast-1がReleasedのまま残ることを確認してください。- 観察結果を
/root/kcna-storage/report.txtに帳簿として残してください。
参考
kubectl describe pvc <이름> -n kcna-storageのEventsが、「なぜまだバインドされていないのか」を教えてくれます(プレースホルダーはPVC名です)。kubectl get pvのCLAIM列は、Releasedになったあとも古いPVCの名前を覚えています。そのため、ほかのPVCに自動でバインドされることはありません。- 公式ドキュメント: PersistentVolume・StorageClass
ディスクを分け与える作業場を開く
ネームスペースkcna-storageを作成してください。
PVCとPodはネームスペースに属しますが、PVとStorageClassはクラスタースコープです。まず、PVCが入るネームスペースを用意してください。createを--dry-run=client -o yamlで出力してapplyすれば、繰り返し実行しても安全です。
使う人が現れるまで待つストレージのクラス
StorageClasslocal-fastを作成してください。provisionerはkubernetes.io/no-provisioner、volumeBindingModeはWaitForFirstConsumer、reclaimPolicyはRetainです。
no-provisionerは、ボリュームを自動で作らないという意味なので、PVは管理者が手で用意します。volumeBindingModeのデフォルト値Immediateは、PVCができた途端にPVを対応づけ、WaitForFirstConsumerは、そのPVCを使うPodがスケジュールされるまで対応づけを遅らせます。StorageClassにはkubectl createのサブコマンドがないので、YAML(apiVersion storage.k8s.io/v1)で書いてapplyしてください。
管理者が手で敷いておいた1Giのディスク
PersistentVolumepv-fast-1を作成してください。容量は1Gi、accessModesは[ReadWriteOnce]、persistentVolumeReclaimPolicyはRetain、storageClassNameはlocal-fast、hostPathのパスは/tmp/pv-fast-1です。
PVはクラスタースコープのオブジェクトなので、metadataにnamespaceがありません。PVCと対応づけられるには、storageClassName・accessModes・容量が要求を満たしている必要があります。StorageClassのreclaimPolicyは、動的プロビジョニングされたPVにのみ適用されるため、手で作るPVには、specにreclaimポリシーを直接書く必要があります。作成した直後にSTATUSを見てください。
合うディスクがあるのにPVCがPendingのままになる
ネームスペースkcna-storageにPVCdataを作成してください。accessModesは[ReadWriteOnce]、storageClassNameはlocal-fast、要求容量は1Giです。まだこのPVCを使うPodがないので、Pendingのままになります。その瞬間を/root/kcna-storage/pending.jsonに記録してください。PVCのuid・phase・volumeNameの3つのキーです。あとのステップでPVCがバインドされて削除されても、このステップはこの記録とクラスターのイベントで判定します。
条件に合うPVがあっても、WaitForFirstConsumerのクラスでは、消費者(Pod)が現れるまでバインドが起こりません。これは故障ではなく設計です。Podがどのノードに行くかが決まってから、そのノードで使えるボリュームを選ぶためです。kubectl describe pvc dataのEventsで理由を読んだあと、kubectl get pvc data -o jsonから必要な3つの値をjqで選び出し、ファイルに残してください。値を手で作り出すと、イベントのUIDと合わず失敗します。
Podが現れるとPVCがバインドされる
ネームスペースkcna-storageにPodwriter(イメージnginx:1.27-alpine)を作成し、PVCdataを/dataにマウントしてください。PVCdataがBoundになり、対応づけられたボリュームがpv-fast-1であれば、その瞬間のPVCのuid・phase・volumeNameを/root/kcna-storage/bound.jsonに記録してください。
PodのspecのvolumesにpersistentVolumeClaim(claimName)のボリュームを宣言し、コンテナのvolumeMountsで、そのボリューム名をmountPathに結び付けます。スケジューラーがPodをノードに配置した瞬間に、遅延していたバインドが進みます。固定のsleepの代わりに、PVCのstatus.phaseを数秒おきに読み直して、Boundになるまで待ってください。
複数で一緒に使いたいという要求は、誰も受け入れてくれない
ネームスペースkcna-storageにPVCwideを作成してください。accessModesは[ReadWriteMany]、storageClassNameはlocal-fast、要求容量は1Giです。そしてPodwider(イメージnginx:1.27-alpine)が、このPVCをマウントするようにしてください。ReadWriteManyを提供するPVがないので、PVCwideはBoundにならないはずです。
PVCのaccessModesは、「この方式が可能なボリュームをください」という要求です。クラスターにあるPVはReadWriteOnceの1つだけで、それも、すでにほかのPVCにバインドされています。消費者のPodがあっても、条件を満たすPVがなければ、PVCはPending、Podはスケジュールされません。ステップ5と同じ形でPVCとPodを作り、accessModesだけを変えてください。
PVCを削除したのに、ディスクは残った
Podwriterを削除してから、PVCdataを削除してください。reclaimポリシーがRetainのPVpv-fast-1は、削除されずReleased状態で残る必要があります。
使用中のPVCは、保護用のfinalizerのため、Podが消えるまで削除されないので、先にPodを削除します。PVCが消えると、PVはreclaimポリシーに従います。Deleteなら、PVも削除され、Retainなら、データを守るためにReleasedのまま残り、ほかのPVCには再びバインドされません。PVのSTATUSが変わるまでポーリングしてください。
ディスクがどう流れていったかを帳簿に残す
観察した結果を/root/kcna-storage/report.txtに、ちょうど4行で書いてください。sc-binding-mode=WaitForFirstConsumer、pv-reclaim=Retain、pv-phase-after-release=Released、wide-pvc=Pendingです。値は実際のクラスターの状態と一致している必要があります。
採点ツールは、各行を、実際のStorageClassのvolumeBindingMode、PVのreclaimポリシーとphase、PVC wideのphaseと照合します。kubectl get sc,pvとkubectl get pvc -n kcna-storageで確認した値を、そのまま写してください。