What are the differences between Kubernetes PersistentVolume and PersistentVolumeClaim? How do you use them to manage storage?
Kubernetes PersistentVolume (PV) and PersistentVolumeClaim (PVC) are two important resources for managing storage. They implement declarative management and dynamic allocation of storage resources.
PersistentVolume (PV)
PersistentVolume is a piece of storage in the cluster, pre-configured by the administrator or dynamically created through a storage class. PV is a cluster-level resource, independent of the Pod lifecycle.
PV Lifecycle
-
Provisioning:
- Static provisioning: Administrator manually creates PV
- Dynamic provisioning: Automatically created through StorageClass
-
Binding:
- When a PVC requests storage, the controller binds the PVC to a suitable PV
- Binding is one-to-one; once bound, the PV is exclusively for that PVC
-
Using:
- Pods use storage through PVC
- Storage can be mounted to a specified path in the Pod
-
Releasing:
- After PVC is deleted, PV enters Released state
- Data in the PV is still retained
-
Reclaiming:
- Retain: Manual reclamation
- Recycle: Deprecated, replaced by dynamic provisioning
- Delete: Automatically delete PV and underlying storage
PV Access Modes
-
ReadWriteOnce (RWO):
- Volume can be mounted as read-write by a single node
- Suitable for block storage
-
ReadOnlyMany (ROX):
- Volume can be mounted as read-only by multiple nodes
- Suitable for shared read-only data
-
ReadWriteMany (RWX):
- Volume can be mounted as read-write by multiple nodes
- Suitable for file systems (such as NFS)
-
ReadWriteOncePod (RWOP):
- Volume can be mounted as read-write by a single Pod
- Ensures only one Pod accesses at a time
PV States
-
Available: Available, not bound to any PVC
-
Bound: Bound to a PVC
-
Released: PVC has been deleted, but the resource has not been reclaimed by the cluster
-
Failed: Automatic reclamation failed
PersistentVolumeClaim (PVC)
PVC is a user's request for storage, similar to a Pod's request for compute resources. PVC is a namespace-level resource.
PVC Configuration
yamlapiVersion: v1 kind: PersistentVolumeClaim metadata: name: my-pvc spec: accessModes: - ReadWriteOnce resources: requests: storage: 10Gi storageClassName: standard selector: matchLabels: environment: production
Using PVC
- Use PVC in Pod:
yamlapiVersion: v1 kind: Pod metadata: name: my-pod spec: containers: - name: my-container image: nginx volumeMounts: - name: my-volume mountPath: /data volumes: - name: my-volume persistentVolumeClaim: claimName: my-pvc
- Use PVC in Deployment:
yamlapiVersion: apps/v1 kind: Deployment metadata: name: my-deployment spec: replicas: 3 selector: matchLabels: app: my-app template: metadata: labels: app: my-app spec: volumes: - name: my-volume persistentVolumeClaim: claimName: my-pvc containers: - name: my-container image: nginx volumeMounts: - name: my-volume mountPath: /data
StorageClass
StorageClass defines different types of storage and supports dynamic provisioning of PV.
StorageClass Configuration
yamlapiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: fast provisioner: kubernetes.io/aws-ebs parameters: type: gp2 iopsPerGB: "10" reclaimPolicy: Delete volumeBindingMode: WaitForFirstConsumer allowVolumeExpansion: true
Common Provisioners
-
kubernetes.io/aws-ebs: AWS EBS block storage
-
kubernetes.io/gce-pd: GCE persistent disk
-
kubernetes.io/azure-disk: Azure disk
-
kubernetes.io/azure-file: Azure file storage
-
kubernetes.io/cinder: OpenStack Cinder
-
kubernetes.io/nfs: NFS storage
-
rancher.io/local-path: Local path storage
StorageClass Parameters
-
provisioner: Storage provider
-
parameters: Storage provider-specific parameters
-
reclaimPolicy: Reclamation policy (Delete or Retain)
-
volumeBindingMode:
- Immediate: Bind immediately
- WaitForFirstConsumer: Wait for the first consumer
-
allowVolumeExpansion: Whether to allow volume expansion
Dynamic Provisioning
Dynamic provisioning allows automatic creation of PV based on PVC without manual administrator creation.
Dynamic Provisioning Process
-
User creates PVC, specifying StorageClass
-
PersistentVolumeController monitors the PVC
-
Controller calls the StorageClass's provisioner to create PV
-
PV binds to PVC
-
Pod can use the PVC
Dynamic Provisioning Example
yamlapiVersion: v1 kind: PersistentVolumeClaim metadata: name: dynamic-pvc spec: accessModes: - ReadWriteOnce resources: requests: storage: 5Gi storageClassName: fast
Static Provisioning
Static provisioning requires administrators to manually create PV, suitable for specific storage requirements.
Static PV Example
yamlapiVersion: v1 kind: PersistentVolume metadata: name: manual-pv labels: type: local spec: storageClassName: manual capacity: storage: 10Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Retain hostPath: path: /mnt/data
Differences Between PV and PVC
| Feature | PV | PVC |
|---|---|---|
| Scope | Cluster level | Namespace level |
| Creator | Administrator or dynamic provisioning | User |
| Purpose | Provides storage resources | Requests storage resources |
| Lifecycle | Independent of Pod | Dependent on Pod |
Best Practices
-
Use Dynamic Provisioning: Prioritize using StorageClass for dynamic provisioning to reduce manual management
-
Set Reasonable Reclamation Policies: Use Retain for production environments, Delete for test environments
-
Use Access Modes: Choose appropriate access modes based on application requirements
-
Monitor Storage Usage: Monitor the usage of PV and PVC
-
Backup Important Data: Regularly backup important data in PV
-
Use Labels and Annotations: Add meaningful labels and annotations to PV and PVC
-
Set Resource Limits: Set reasonable storage requests for PVC
-
Use Storage Classes: Create different StorageClasses for different application requirements
Troubleshooting
- View PV Status:
bashkubectl get pv kubectl describe pv <pv-name>
- View PVC Status:
bashkubectl get pvc kubectl describe pvc <pvc-name>
- View StorageClass:
bashkubectl get storageclass kubectl describe storageclass <sc-name>
- View Pod Mount Status:
bashkubectl describe pod <pod-name>
- View Events:
bashkubectl get events --sort-by=.metadata.creationTimestamp