TT Lab
はじめる
学ぶ 学習パス コース

CKA — Kubernetes管理者

ボリュームは三層に分かれている

TT Labで続きを見る

一言でいうと

Kubernetesのストレージは、StorageClass(設計図) → PersistentVolume(実物) → PersistentVolumeClaim(要求書)の3層です。この3つは、それぞれ別の人の関心事を代弁しているので分かれており、ずれると、PVCが静かにPendingのままになります。

ストレージの3層: PVCは開発者が書く要求書、PVは実物、StorageClassは管理者が書く設計図です。StorageClassがPVを作り、PVとPVCが結び付きますが、storageClassNameが同じで、accessModesが要求を含み、容量が要求以上である必要があります。1つでもずれると、エラーなしにPendingになります

なぜ必要なのか

開発者は、「1Giで、複数のノードから同時に使えるディスク」を望みます。管理者は、「それはNASの/volume1/k8sの下に、NFS v4.1で、hardマウントでnconnect 4」という決定をします。この2つの関心事を1つのオブジェクトに混ぜると、開発者がストレージのベンダーを知らなければならなくなります。

そのため、PVCは要求だけを書き、StorageClassが、その要求を実物に変える方法を定義し、PVが実物を代表します。バインドの条件は単純です。storageClassNameが同じで、PVのaccessModesがPVCの要求を含み、PVの容量がPVCの要求以上なら、結び付きます。1つでもずれると、何のエラーもなくPendingになります。

CSIが登場した理由も、同じ分離の欲求です。以前は、ストレージプラグインがKubernetesのコアコードの中にあったため(in-tree)、新しいストレージを付けるには、Kubernetes自体を直さなければなりませんでした。CSIはその結合を断ち切り、ドライバーは、コントローラー(Deployment、ボリュームの作成/削除/拡張/スナップショット)とノードプラグイン(DaemonSet、マウント/アンマウント)に分かれます。ノードプラグインがDaemonSetである理由は、Podがスケジュールされうるすべてのノードに、存在する必要があるからです。

どう動くのか

StorageClassで間違えると、元に戻しにくいフィールドが3つあります。

フィールド 意味 間違えると
reclaimPolicy PVC削除後のPVの運命 Deleteにするとデータまで消える
volumeBindingMode いつボリュームを作るか ImmediateだとPodとは別のゾーンにボリュームができることがある
allowVolumeExpansion あとで拡張できるか falseで作ったクラスのPVCは、永久に拡張不可

WaitForFirstConsumerは、Podがスケジュールされるノードがわかってから、ボリュームを作ります。マルチゾーン環境では必須です。

アクセスモードは4つです。RWO(1つのノードで読み取り/書き込み)、ROX(複数のノードで読み取り専用)、RWX(複数のノードで読み取り/書き込み)、RWOP(単一のPod専用)です。ブロックストレージは、通常RWOまでで、RWXは、NFSのようなファイルストレージの領域です。

デフォルトのStorageClassが指定されたクラスターで、そのクラスを使わないようにするには、storageClassNameを省略するのではなく、空文字列で明示する必要があります。省略すると、デフォルト値が注入されます。この区別は、試験にも出ます。

現場での姿

事例1: マウントの確認が先です。ホームラボのクラスターでkubectl get scを実行すると、No resources foundでした。StorageClassがなければ、PVCは永遠にPendingで、状態を持つワークロードを1つも載せられません。自宅にあったSynologyのNASを接続することにしたのですが、ドライバーを導入する前に、Podから、NFSマウントができるかどうかを先に確認しました。最初の試みは失敗しました。

mount.nfs: Operation not permitted for 10.0.0.109:/volume1/k8s on /mnt/t

privileged: trueを指定したのに、拒否されました。足りなかったのは、hostNetwork: trueでした。NFSマウントはrpcbindと通信し、1024未満の予約ポートを送信元ポートとして使いますが、Podのネットワークネームスペースの中では、この動作が制約を受けます。privilegedはcapabilityを与えますが、ネットワークネームスペースの問題は解決しません。順序を守ったおかげで、原因がドライバーではないとすぐにわかりました。

事例2: クラスを用途別に分けます。csi-driver-nfs 4.13.4を導入したあと、StorageClassを2セット作成しました。

hardを選んだ理由が、特に重要です。softは、タイムアウト時にI/Oエラーをアプリケーションに返しますが、データベースが書き込みの途中でエラーを受け取ると、静かなデータ破損につながる可能性があります。hardは、サーバーが戻ってくるまで無限にリトライするので、データは安全な代わりに、NASの障害時にPodがエラーなしに止まったように見え、原因の把握が難しくなります。すべてのストレージ設定は、このようなトレードオフです。

subDirのパターンも、네임스페이스-PVC이름-PV이름としました(プレースホルダーは、ネームスペース、PVC名、PV名です)。PV名だけを使うと、NASのファイルエクスプローラーには、pvc-da6bb53d-...のようなUUIDだけが並び、あとで何を削除してよいのかわかりません。

事例3: 容量は強制されません。PVCに2Giを要求しましたが、NFSにはそれを強制する手段がありません。Podが100GBを使っても、止められません。PVCの容量は、スケジューリングと会計目的のメタデータにすぎず、実際の制限は、バックエンドが行う必要があります。ブロックストレージは、ボリュームのサイズがそのまま物理的な限界なので、自然に強制されますが、NFSのサブディレクトリはそうではありません。

そして、archiveポリシーの代償も、実物で確認しました。NFS exportのルートを開いてみると、以前のクラスターが残したディレクトリが32個あり、PrometheusとOpenSearchのデータがそのまま残っていて、19.9Tのうち9.4Tを使っていました。安全な代わりに、誰も削除しなければ、ずっと積み上がります。

次のラボですること

StorageClassを2セット作成して3つのフィールドの違いを確認し、PVとPVCを静的にバインドし、RWXボリュームを作成し、StatefulSetのvolumeClaimTemplatesがPVCを自動作成するのを確認します。最後のステップは、デフォルトのStorageClassを明示的に拒否する方法です。