【実務・中級編】Kubernetesの永続化ストレージ入門:PersistentVolume (PV) と PersistentVolumeClaim (PVC) の仕組み – インフラ構成管理(IaC)活用バイブル

Kubernetes永続化ストレージの深淵:PV・PVC・StorageClassを完全掌握し、ステートフルの恐怖を克服する

こんにちは。テックリードの私だ。

Kubernetes(以下、K8s)の導入初期、多くのエンジニアが「コンテナはエフェメラル(はかない)である」という教義に縛られ、データベースなどのステートフルなワークロードをクラスタに乗せることに恐怖を覚える。ポッドが再起動するたびにデータが消失する――それを避けるために、ホストパスクやローカルストレージのハックで泥沼にはまった経験はないだろうか?

だが、恐れる必要はない。K8sのストレージ抽象化レイヤーである PV (PersistentVolume)、PVC (PersistentVolumeClaim)、そして StorageClass の関係性を完璧に理解し、動的プロビジョニングを血肉化すれば、インフラのプロビジョニングスピードは劇的に跳ね上がり、ステートフルアプリはステートレス並みに容易く扱えるようになる。

今回は、現場の生産性を極限まで高める実践知見とともに、このストレージの三位一体を徹底解説する。

—

1. コンテナのステートレス性とストレージの課題

K8sの根幹思想は「ポッドは使い捨てである」という点にある。Podが死ねば、その内部のエフェメラルストレージ(Container File System)に書き込まれたデータは宇宙の塵と消える。

ログや一時ファイルならそれで良い。しかし、PostgreSQL、MySQL、Redis、あるいはElasticsearchといった永続データを扱うミドルウェアを動かす場合、この仕様は致命的だ。

ここで必要になるのが、「Podのライフサイクルからストレージを完全に切り離す(Decoupling)」というアプローチである。クラスタ管理者がストレージを用意し、開発者は「これだけの容量の領域が欲しい」と宣言するだけで、基盤側の複雑さを意識せずに永続領域を手に入れる。この分離こそが、K8sストレージ設計の美しさであり、本質だ。

—

2. PV, PVC, StorageClassの関係性を図解

K8sのストレージ機構は、インフラ担当者とアプリケーション開発者の「関心の分離」を見事に実現している。

+——————————————————-+
| Cluster Administrator (インフラ担当) |
| |
| [ StorageClass ] (プロビジョナーや容量・性能を定義) |
| │ |
| ▼ (要求に応じて自動作成) |
| [ PersistentVolume (PV) ] (実際のクラウドストレージ) |
+———┼─────────────────────────────────────────────+
│ バインド (Binding)
+———┼─────────────────────────────────────────────+
| Application Developer (アプリ開発者) |
| │ |
| [ PersistentVolumeClaim (PVC) ] (ストレージの「利用券」)|
| │ |
| ▼ マウント |
| [ Pod / Container ] |
+——————————————————-+

  • PersistentVolume (PV): クラスタ内の物理的なストレージ(AWS EBS, GCP Persistent Disk, Azure Disk, NFS等)。インフラ管理者がプロビジョニングするか、後述のStorageClassによって動的に生成される。
  • PersistentVolumeClaim (PVC): 開発者が記述する「ストレージの要求書」。容量(例: `10Gi`)やアクセスモード(例: `ReadWriteOnce`)を指定する。
  • StorageClass (SC): PVを動的にプロビジョニングするための「レシピ」。どのクラウドプロバイダのどのタイプ(gp3, io2など)のストレージを使うかを定義する。

—

3. 動的プロビジョニングの設定方法:静的の呪縛からの解放

かつてはインフラエンジニアが事前にPVを手動作成(静的プロビジョニング)し、PVCと手動で紐付けるという前時代的な苦行が存在した。今やそんな時代遅れのワークフローは捨て去るべきだ。「動的プロビジョニング(Dynamic Provisioning)」こそが、開発スピードを極限まで高める鍵となる。

以下のStorageClassとPVCのベストプラクティス構成を見てほしい。

01. StorageClassの定義(AWS EBS gp3を例に)

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: ebs-gp3-sc
annotations:
storageclass.kubernetes.io/is-default-class: “true” # クラスタのデフォルトストレージに指定
provisioner: ebs.csi.aws.com # AWS EBS CSIドライバを指定
parameters:
type: gp3
iops: “3000”
throughput: “125”
reclaimPolicy: Delete # PVC削除時にPVも削除する(生産性重視。本番の永続DBではRetain推奨)
volumeBindingMode: WaitForFirstConsumer # 超重要:PodがスケジュールされるまでPV作成を遅延させ、正しいAZに配置させる
allowVolumeExpansion: true # 後からの容量拡張を許可する

> プロの知見: `volumeBindingMode: WaitForFirstConsumer` の魔術
> マルチAZ環境において、この設定を入れないと、PVC作成直後にランダムなAZでPVがプロビジョニングされ、いざPodをデプロイした際に「ストレージとPodが別AZにいてアタッチできない」という絶望的なエラー(Multi-Attach error)に直面する。この設定は、Podがどのノード(=どのAZ)に配置されるか決まってからPVをプロビジョニングさせるための、絶対に入れるべき神設定である。

02. PersistentVolumeClaim (PVC) の定義

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: postgres-pvc
namespace: database
spec:
accessModes:

  • ReadWriteOnce # 単一ノードからの読み書き

storageClassName: ebs-gp3-sc
resources:
requests:
storage: 50Gi # 50GBを要求

—

4. ステートレスからステートフルアプリ(DB等)への応用

PVCを手に入れたら、いよいよステートフルなアプリケーション(PostgreSQLなど)をデプロイする。ここで、通常の `Deployment` ではなく `StatefulSet` を使うのがK8sにおける定石だ。

以下に、実務でそのまま使えるPostgreSQLのプロダクションレディなマニフェストを示す。

apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgres
namespace: database
spec:
serviceName: “postgres-headless”
replicas: 1
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:

  • name: postgres

image: postgres:15-alpine
ports:

  • containerPort: 5432

name: postgres
env:

  • name: POSTGRES_PASSWORD

valueFrom:
secretKeyRef:
name: postgres-secret
key: password
volumeMounts:

  • name: postgres-storage

mountPath: /var/lib/postgresql/data
volumeClaimTemplates:

  • metadata:

name: postgres-storage
spec:
accessModes: [ “ReadWriteOnce” ]
storageClassName: ebs-gp3-sc
resources:
requests:
storage: 50Gi

この `volumeClaimTemplates` を使うことで、StatefulSetのレプリカ(例: `postgres-0`, `postgres-1`)ごとに一意かつ適切なPVCが自動生成され、ポッドが万が一クラッシュして別ノードに再スケジュールされても、同じPV(データ)が確実に再アタッチされる。

—

5. 現場の生産性を爆発させるプロの実践テクニック

ここからは、日々のK8s運用や開発スピードを劇的に高める、現場のシニアエンジニアが隠し持つテクニックを伝授しよう。

A. 開発スピードを高めるキーボードショートカット & エイリアス (kubectl)

ストレージの状態確認やデバッグで毎回 `kubectl get persistentvolumeclaim` と打っているようでは手首が破壊される。`.bashrc` 或いは `.zshrc` に以下を仕込め。

alias k=”kubectl”
alias kgp=”kubectl get pods”
alias kgpvc=”kubectl get pvc”
alias kgpv=”kubectl get pv”
alias kgsc=”kubectl get storageclass”

PVCとPVの紐づきを美しく一覧化するワンライナー
alias k-storage=’kubectl get pvc -o custom-columns=NAMESPACE:.metadata.namespace,NAME:.metadata.name,STATUS:.status.phase,VOLUME:.spec.volume,CAPACITY:.spec.resources.requests.storage,STORAGECLASS:.spec.storageClassName’

B. 絶対入れるべき神プラグイン:`krew` と `kubectl-df-pv`

ストレージの容量圧迫は障害の元凶である。どのPVがどれだけ容量を使っているかを瞬時に把握するために、K8sのパッケージマネージャである `krew` を使って以下のプラグインを導入せよ。

プラグインのインストール
kubectl krew install df-pv
kubectl krew install neat # YAMLから自動生成フィールドを削ぎ落として美しく出力する神ツール

実行例:

kubectl df-pv

これによって、各PVの総容量、使用量、使用率がディスクの `df` コマンドの要領で一目でリスト化される。容量枯渇アラートを鳴らす前の日常的な健康診断に必須のツールだ。

C. チーム開発で役立つ設定の共有化ルール (Kustomize / Helm)

環境(dev, stg, prd)ごとにストレージのサイズ(`storage: 50Gi` vs `storage: 500Gi`)や `storageClassName` をハードコーディングするのは素人のやることだ。
Kustomize もしくは Helm を用い、ベースの設定に対してパッチを当てる構成を強制せよ。

ディレクトリ構成例(Kustomize):

deploy/
├── base/
│ ├── kustomization.yaml
│ ├── pvc.yaml
│ └── statefulset.yaml
└── overlays/
├── dev/
│ ├── kustomization.yaml
│ └── storage-patch.yaml
└── prd/
├── kustomization.yaml
└── storage-patch.yaml

チームメンバー全員がこの構成に従うことで、ローカル環境(MinikubeやKindでの `standard` ストレージクラス)から本番のクラウド環境への移行が、コードの書き換えなしでシームレスに実現できる。

—

最後に:ストレージの恐怖を「制御下」に置け

K8sにおける永続化ストレージは、もはや「難解なブラックボックス」ではない。
StorageClassが基盤を抽象化し、PVCが宣言的に要求し、StatefulSetがライフサイクルを担保する。このモダンなパイプラインを正しく構築すれば、データベースの運用すらK8sの上でエレガントに自動化できる。

あなたのクラスタのストレージは、本当にモダンになっているか? 今すぐマニフェストを見直し、動的プロビジョニングの波に乗ってほしい。インフラの自動化に終わりはない。さらなる高みを目指せ。

タイトルとURLをコピーしました