2026年7月28日

2026年7月28日

KubernetesのPersistentVolumeとPVCの使い方|動的・静的プロビジョニング

Kubernetes の Pod の中のファイルは、Pod を削除したり作り直したりすると消えます。データベースのデータやアップロードされたファイルのように残しておきたいデータは、PersistentVolume(PV)に保存します。

この記事では、PV と PersistentVolumeClaim(PVC)の関係を整理し、次の2つの方法で Pod にストレージを付ける手順を説明します。

  • 動的プロビジョニング:PVC を作ると、StorageClass に従って PV が自動で作られる。クラウドのマネージド Kubernetes や多くのクラスターでの通常の方法
  • 静的プロビジョニング:管理者が PV を手で作り、PVC をそれに結び付ける

マニフェストと出力は、2026年10月時点の Kubernetes 1.34(k3s、既定の StorageClass は local-path)で確認しています。

PV・PVC・StorageClassの関係

リソース 役割 作る人
PersistentVolume(PV) 実際のストレージ(ディスク、NFS、クラウドのブロックストレージなど)を表す。クラスター全体のリソース 管理者、または StorageClass による自動作成
PersistentVolumeClaim(PVC) 「この容量・このアクセスモードのストレージが欲しい」という要求。名前空間ごとのリソース アプリを動かす人
StorageClass PV を自動で作るときの種類(プロビジョナーやパラメーター) 管理者

Pod は PVC を名前で指定し、PVC に結び付けられた(Bound の)PV がマウントされます。Pod を作り直しても、同じ PVC を使えば同じデータが見えます。

まずStorageClassを確かめる

kubectl get storageclass
NAME                   PROVISIONER             RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
local-path (default)   rancher.io/local-path   Delete          WaitForFirstConsumer   false                  2s

(default) が付いた StorageClass があれば、PVC を作るだけで PV が自動で作られます(動的プロビジョニング)。表示される名前やプロビジョナーはクラスターによって違います。何も表示されない場合は、静的プロビジョニングで PV を自分で用意するか、ストレージのドライバー(CSI ドライバー)を導入します。

動的プロビジョニングで使う

PVC と、それをマウントする Pod を1つのファイル(web.yaml)に書きます。

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: web-data
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
---
apiVersion: v1
kind: Pod
metadata:
  name: web
spec:
  containers:
    - name: nginx
      image: nginx:1.28
      volumeMounts:
        - name: data
          mountPath: /usr/share/nginx/html
  volumes:
    - name: data
      persistentVolumeClaim:
        claimName: web-data

storageClassName を書いていないので、既定の StorageClass が使われます。特定の StorageClass を使う場合は、PVC の spec に storageClassName: 名前 を加えます。

kubectl apply -f web.yaml
kubectl get pvc
NAME       STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
web-data   Bound    pvc-843d1db2-d309-40e5-b160-93506f1dc039   1Gi        RWO            local-path     <unset>                 18s

STATUS が Bound になれば、PV が作られて PVC に結び付いています。StorageClass の VOLUMEBINDINGMODE が WaitForFirstConsumer の場合、PVC を使う Pod が作られるまでは Pending のままです。これは正常な動きです。

データが残ることを確かめる

Pod の中でファイルを作り、Pod を削除して作り直しても残っているかを確かめます。

kubectl exec web -- sh -c 'echo hello-pv > /usr/share/nginx/html/index.html'
kubectl delete pod web
kubectl apply -f web.yaml
kubectl exec web -- cat /usr/share/nginx/html/index.html

最後のコマンドで hello-pv と表示されれば、データは PV に保存されています。

実際の運用では、Pod を直接作るより Deployment(複数の Pod でそれぞれ別のボリュームが必要なら StatefulSet の volumeClaimTemplates)から PVC を使うのが一般的です。指定の方法(volumes の persistentVolumeClaim)は同じです。

静的プロビジョニングで使う

既存の NFS サーバーやディスクを使いたい場合など、PV を自分で作る方法です。次の例は、ノードのディレクトリーを使う hostPath の PV です。hostPath は1台のノードでの検証用で、Pod が別のノードで動くとデータが見えなくなるため、本番では使いません。

apiVersion: v1
kind: PersistentVolume
metadata:
  name: manual-pv
spec:
  capacity:
    storage: 5Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  storageClassName: manual
  hostPath:
    path: /srv/k8s-data/manual-pv
    type: DirectoryOrCreate
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: manual-pvc
spec:
  storageClassName: manual
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi
kubectl apply -f manual.yaml
kubectl get pv manual-pv
NAME        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                STORAGECLASS   VOLUMEATTRIBUTESCLASS   REASON   AGE
manual-pv   5Gi        RWO            Retain           Bound    default/manual-pvc   manual         <unset>                          3s

ポイントは次のとおりです。

  • PV には、hostPath、nfs、csi、local などのボリュームの種類を1つ書く必要があります。種類のない PV は spec: Required value: must specify a volume type というエラーで作れません
  • PVC は、storageClassName が同じで、容量とアクセスモードの条件を満たす PV に結び付きます
  • PVC の storageClassName を省略すると、既定の StorageClass が使われて新しい PV が自動で作られ、手で作った PV には結び付きません。静的な PV を使うときは、PV と PVC の両方に同じ storageClassName を書きます(StorageClass のリソースを作らずに、manual のような名前を合わせるだけでも結び付きます)

localボリュームを使う場合

ノードに付けたディスクを本番で使う場合は、hostPath ではなく local ボリュームを使います。local の PV には、そのディスクがあるノードを nodeAffinity で指定する必要があり、StorageClass は WaitForFirstConsumer にします。

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: local-storage
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: local-pv-1
spec:
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  storageClassName: local-storage
  local:
    path: /mnt/disks/vol1
  nodeAffinity:
    required:
      nodeSelectorTerms:
        - matchExpressions:
            - key: kubernetes.io/hostname
              operator: In
              values:
                - worker-1

worker-1 は kubectl get nodes で表示されるノード名に、/mnt/disks/vol1 はそのノードで実際にマウントしてあるディレクトリーに置き換えます。kubernetes.io/no-provisioner は自動で PV を作らないので、ディスクごとに PV を用意します。

アクセスモード

アクセスモード 省略形 意味
ReadWriteOnce RWO 1つのノードから読み書きできる(同じノード上の複数の Pod からは使える)
ReadOnlyMany ROX 複数のノードから読み取りだけできる
ReadWriteMany RWX 複数のノードから読み書きできる
ReadWriteOncePod RWOP 1つの Pod だけが読み書きできる

使えるアクセスモードは、ストレージの種類によって決まります。たとえばクラウドのブロックストレージは通常 RWO だけで、複数のノードの Pod から同じデータを読み書きしたい(RWX)場合は、NFS などの共有ファイルシステムを使います。

回収ポリシー(PVCを削除したときのPV)

PV の persistentVolumeReclaimPolicy で、PVC を削除したときに PV とデータをどうするかが決まります。

ポリシー PVC を削除したとき
Retain PV は Released になり、データは残る。管理者が手で後始末する
Delete PV と、元になったストレージ(クラウドのディスクなど)も削除される

動的プロビジョニングで作られた PV は、StorageClass の reclaimPolicy(多くは Delete)を引き継ぎます。PVC を削除するとデータも消える設定になっていることが多いので、大事なデータの PVC を削除する前に確認してください。Recycle は非推奨で、使いません。

Retain の PV は、PVC を削除すると Released になり、そのままでは新しい PVC に結び付きません。データを確認したうえで同じ PV を再び使う場合は、前の PVC への参照(claimRef)を外すと Available に戻ります。

kubectl patch pv manual-pv --type json -p '[{"op":"remove","path":"/spec/claimRef"}]'

容量を増やす

StorageClass の allowVolumeExpansion が true なら、PVC の spec.resources.requests.storage を大きな値に変えるだけで容量を増やせます。

kubectl patch pvc web-data -p '{"spec":{"resources":{"requests":{"storage":"20Gi"}}}}'

容量を減らすことはできません。allowVolumeExpansion が false(または未設定)の StorageClass では、この変更は拒否されます。

PVCがPendingのままのとき

kubectl describe pvc の最後の Events に理由が表示されます。

kubectl describe pvc PVC名
Events の例 原因と対処
waiting for first consumer to be created before binding WaitForFirstConsumer の StorageClass で、まだ PVC を使う Pod がない。Pod を作れば進む
storageclass.storage.k8s.io "manual" not found 指定した storageClassName に合う PV も StorageClass もない。PV の容量・アクセスモード・storageClassName が PVC と合っているか確かめる
no persistent volumes available for this claim and no storage class is set storageClassName が空で、既定の StorageClass もなく、条件に合う PV もない
Waiting for a volume to be created either by the external provisioner ... が続く プロビジョナー(CSI ドライバーなど)が動いていない、またはエラーになっている。プロビジョナーの Pod のログを確認する

PV の一覧と状態は kubectl get pv で確かめられます。Available は未使用、Bound は使用中、Released は PVC が削除されたあと、Failed は自動の回収に失敗した状態です。

まとめ

  • Pod は PVC を指定し、PVC に結び付いた PV がマウントされる。Pod を作り直してもデータは残る
  • 既定の StorageClass があれば、PVC を作るだけで PV が自動で作られる(動的プロビジョニング)
  • PV を手で作るときは、ボリュームの種類(hostPath・nfs・local など)を書き、PV と PVC の storageClassName をそろえる
  • アクセスモードはストレージの種類で決まる。複数ノードからの読み書き(RWX)には共有ファイルシステムが必要
  • 動的に作られた PV は Delete のことが多く、PVC を削除するとデータも消える。大事なデータは Retain やバックアップで守る
  • PVC が Pending のままなら、kubectl describe pvc の Events で理由を確かめる

関連記事:

お気軽にご相談ください

お見積りへ お問い合わせへ
▲