Kubernetes PersistentVolume Manager
Implements v1 PersistentVolume (PV), StorageClass, and PersistentVolumeClaim (PVC) manifests for block and file storage provisioning in Kubernetes. When loaded, the model generates production-grade storage manifests with proper access modes, reclaim policies, and storage class configuration for both static and dynamic provisioning.
TL;DR Checklist
- Use
v1API version for PersistentVolume, PersistentVolumeClaim, andstorage.k8s.io/v1for StorageClass - Match PVC
accessModesto the PV's supported access modes — mismatch causes Pending PVC state - Set
reclaimPolicy: Retainfor production databases,Deletefor ephemeral workloads - Specify
storageClassNameexplicitly — omitting it uses the default class or fails binding - Use dynamic provisioning (StorageClass) for most workloads — static provisioning requires manual PV creation
- Never use
ReadWriteManywith block storage — only filesystem-based volumes support it
When to Use
Use this skill when:
- Provisioning persistent storage for stateful applications (databases, message brokers)
- Configuring storage classes with different performance tiers (SSD, HDD, NVMe)
- Implementing static provisioning with manually created PersistentVolumes
- Setting up reclaim policies for data lifecycle management
- Managing cross-namespace PVC-to-PV binding for multi-tenant clusters
When NOT to Use
Avoid this skill for:
- Stateless application storage needs — use ephemeral
emptyDirorhostPathvolumes - Temporary or scratch data that can be recreated — use
emptyDirvolumes - Storage that does not require Kubernetes PV/PVC lifecycle management
- Direct cloud provider storage management — use cloud provider SDKs or tools instead
Core Workflow
Select Storage Type and Class — Determine whether to use dynamic provisioning (StorageClass) or static provisioning (manual PV creation). Checkpoint: Verify the cluster has a provisioner configured for the desired storage backend (e.g.,
kubernetes.io/aws-ebs,ebs.csi.aws.com).Create StorageClass (if Dynamic) — Define a
storage.k8s.io/v1StorageClass withprovisioner,reclaimPolicy, and parameters. Checkpoint: Ensure the provisioner string matches an installed CSI driver or in-tree provisioner.Create PersistentVolumeClaim — Define a
v1PVC withaccessModes,resources.requests.storage, andstorageClassName. Checkpoint: The PVC'sstorageClassNamemust match an available StorageClass or a manually created PV.Verify Binding — Confirm the PVC transitions to
Boundstate. Checkpoint: Runkubectl get pvc -n <namespace>and verify theSTATUScolumn showsBound.Reference in Pod Spec — Mount the bound PVC in a pod using a
volumeMountreferencing the PVC name. Checkpoint: The PVCaccessModesmust be compatible with the pod's access requirements (e.g.,ReadWriteOncepods cannot shareReadWriteManyvolumes).Configure Data Lifecycle — Set
reclaimPolicyon the StorageClass or PV to control data retention on deletion. Checkpoint: For production databases, usereclaimPolicy: Retainto prevent accidental data loss.
Implementation Patterns
Pattern 1: Complete Dynamic and Static Provisioning Setup
Production-grade StorageClass and PersistentVolumeClaim manifests for both provisioning approaches.
# StorageClass: High-performance SSD for production databases
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: premium-ssd
provisioner: ebs.csi.aws.com
parameters:
type: gp3
fsType: ext4
reclaimPolicy: Retain
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true
---
# StorageClass: Standard storage for development and test environments
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: standard-hdd
provisioner: ebs.csi.aws.com
parameters:
type: gp2
fsType: ext4
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: false
---
# PersistentVolumeClaim: High-performance storage for production database
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: postgres-data
namespace: production
spec:
accessModes:
- ReadWriteOnce
storageClassName: premium-ssd
resources:
requests:
storage: 100Gi
volumeMode: Filesystem
---
# PersistentVolumeClaim: Standard storage for application logs
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: app-logs
namespace: production
spec:
accessModes:
- ReadWriteMany
storageClassName: nfs-storage
resources:
requests:
storage: 10Gi
volumeMode: Filesystem
---
# Pod: Mounting the PVCs in a StatefulSet
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgres
namespace: production
spec:
serviceName: postgres-headless
replicas: 1
selector:
matchLabels:
app: postgres
template:
spec:
containers:
- name: postgres
image: postgres:16-alpine
volumeMounts:
- name: data
mountPath: /var/lib/postgresql/data
volumes:
- name: data
persistentVolumeClaim:
claimName: postgres-data
Pattern 2: Static Provisioning and Access Mode Matching (BAD vs GOOD)
Incorrect access mode specification or PV/PVC mismatch causes the classic Pending PVC state.
# ❌ BAD: PVC requests ReadWriteMany but the storage class only supports ReadWriteOnce
# This PVC will remain in Pending state forever.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: broken-pvc
spec:
accessModes:
- ReadWriteMany # ← Most CSI drivers and cloud block storage only support RWO
storageClassName: ebs-csi
resources:
requests:
storage: 50Gi
# ❌ BAD: ReclaimPolicy: Delete on production database storage — data is lost on PVC deletion
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: prod-storage
reclaimPolicy: Delete # ← Destructive for production workloads
volumeBindingMode: Immediate
# ❌ BAD: Static PV with mismatched access mode
# The PV supports ReadWriteOnce but the PVC requests ReadWriteOnce — they match,
# but if the PVC asked for ReadWriteMany, it would never bind.
apiVersion: v1
kind: PersistentVolume
metadata:
name: static-pv
spec:
capacity:
storage: 50Gi
accessModes:
- ReadWriteOnce
storageClassName: manual
persistentVolumeReclaimPolicy: Retain
hostPath:
path: /data/static
# ❌ hostPath is node-local — this PV can only bind to a pod on the same node
# ✅ GOOD: Access modes correctly specified for block storage
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: correct-pvc
spec:
accessModes:
- ReadWriteOnce # ← Matches standard block storage capabilities
storageClassName: premium-ssd
resources:
requests:
storage: 100Gi
volumeMode: Filesystem
---
# ✅ GOOD: Static PV with NFS for multi-pod sharing
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-static-pv
spec:
capacity:
storage: 50Gi
accessModes:
- ReadWriteMany # ← NFS supports multiple readers/writers
storageClassName: nfs-storage
persistentVolumeReclaimPolicy: Retain
nfs:
server: nfs-server.example.com
path: /exports/data
---
# ✅ GOOD: Volume expansion enabled for growing storage needs
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: expandable-pvc
spec:
accessModes:
- ReadWriteOnce
storageClassName: premium-ssd
resources:
requests:
storage: 50Gi # ← Will expand to 100Gi when PVC is updated
volumeMode: Filesystem
---
# To expand: update the PVC's storage request, then verify the PV expands
# kubectl patch pvc expandable-pvc -p '{"spec":{"resources":{"requests":{"storage":"100Gi"}}}}'
Pattern 3: Storage Class Parameter Reference
def select_storage_class(
workload_type: str,
performance_tier: str,
required_access_mode: str
) -> str:
"""Select the appropriate StorageClass for a given workload.
Maps workload requirements to the most suitable storage class in the cluster.
Args:
workload_type: Type of workload ('database', 'log', 'temp', 'backup').
performance_tier: Performance requirement ('premium', 'standard', 'budget').
required_access_mode: Required access mode ('ReadWriteOnce', 'ReadWriteMany', 'ReadOnlyMany').
Returns:
The name of the recommended StorageClass.
"""
# Database workloads always need premium storage with retain policy
if workload_type == "database":
if performance_tier == "premium":
return "premium-ssd"
return "standard-hdd"
# Log storage supports read-many for multi-pod aggregation
if workload_type == "log":
if required_access_mode == "ReadWriteMany":
return "nfs-storage"
return "standard-hdd"
# Temporary storage can be deleted on reclaim
if workload_type == "temp":
return "ephemeral-ssd"
# Backup requires retain policy for data safety
if workload_type == "backup":
return "premium-ssd"
raise ValueError(f"Unknown workload type: {workload_type}")
Constraints
MUST DO
- Always specify
storageClassNameexplicitly in PVCs — omitting it relies on the default class which may not be appropriate - Match PVC
accessModesto the StorageClass/PV capabilities — useReadWriteOncefor block storage andReadWriteManyonly for NFS or distributed filesystems - Set
reclaimPolicy: Retainon StorageClasses used for production database storage — prevents accidental data loss - Use
volumeBindingMode: WaitForFirstConsumerfor most workloads — delays PV binding until a pod is scheduled, enabling topology-aware provisioning - Use
allowVolumeExpansion: trueon StorageClasses to allow PVCs to grow without migration - Specify
volumeMode: Filesystem(default) orvolumeMode: Blockexplicitly based on the application's needs - Verify PV/PVC binding with
kubectl get pv,pvc -n <namespace>after creation
MUST NOT DO
- Never use
hostPathvolumes for production workloads — they are node-local and survive node failure - Never set
reclaimPolicy: Deleteon storage used for databases or any data that must be preserved - Never request
ReadWriteManyon block storage providers (EBS, Azure Disk, GCE PD) — they only supportReadWriteOnce - Never create a PVC with a
storageClassNamethat does not exist in the cluster — it will fail binding immediately - Never use
volumeBindingMode: Immediatewith zone-sensitive storage — it may bind to a PV in a different zone than the pod - Never assume a PVC is bound — always check
kubectl get pvcstatus before relying on the storage
Output Template
When implementing Kubernetes persistent storage, produce the following:
- StorageClass YAML — StorageClass with provisioner, parameters, reclaim policy, and volume binding mode.
- PersistentVolumeClaim YAML — PVC with access modes, storage requests, and storage class reference.
- PersistentVolume YAML (if static) — Manually created PV with capacity, access modes, and storage backend details.
- Pod Volume Mount — The container spec showing how the PVC is mounted and accessed.
Related Skills
| Skill | Purpose |
|---|---|
kubernetes-statefulset |
Use PVCs in StatefulSet volumeClaimTemplates for ordered persistent storage per pod |
kubernetes-deployment |
Reference PVCs in Deployment pods for shared persistent storage (single-writer access) |
cncf/crossplane |
Manage storage provisioning declaratively with Crossplane composite resources |
cncf/longhorn |
Use Longhorn as a distributed block storage solution with native Kubernetes integration |
Live References
Authoritative documentation links for this skill's domain. The model follows markdown links at load time to resolve external references and inline content.
- Kubernetes Storage Documentation — Official guide to PV, PVC, StorageClass, and storage concepts
- Persistent Volumes Documentation — PV lifecycle, provisioning, and binding behavior
- Storage Classes Documentation — StorageClass parameters, provisioners, and reclaim policies
- Persistent Volume Claim — PVC binding rules and access mode matching
- CSI Driver Development — Container Storage Interface driver documentation
- Volume Expansion — Growing PVC storage without data migration
- StorageClass API Reference — storage.k8s.io/v1 — Complete API schema for StorageClass resources