| name | kubernetes-persistentvolume |
| description | Implements v1 PersistentVolume, StorageClass, and PersistentVolumeClaim manifests with static/dynamic provisioning, access modes, and reclaim policies for Kubernetes storage. |
| license | MIT |
| compatibility | opencode |
| metadata | {"version":"1.0.0","domain":"cncf","triggers":"static provisioning, dynamic provisioning, storage class, access modes, reclaim policy, pv, pvc, storage.k8s.io","archetypes":["tactical","generation"],"anti_triggers":["pod isolation","ingress egress rules","rolling update"],"response_profile":{"verbosity":"low","directive_strength":"high","abstraction_level":"operational"},"role":"implementation","scope":"implementation","output-format":"code","content-types":["code","guidance","config","do-dont"],"related-skills":"cncf/kubernetes-statefulset, cncf/kubernetes-deployment, cncf/crossplane"} |
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
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
emptyDir or hostPath volumes
- Temporary or scratch data that can be recreated — use
emptyDir volumes
- 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/v1 StorageClass with provisioner, reclaimPolicy, and parameters. Checkpoint: Ensure the provisioner string matches an installed CSI driver or in-tree provisioner.
-
Create PersistentVolumeClaim — Define a v1 PVC with accessModes, resources.requests.storage, and storageClassName. Checkpoint: The PVC's storageClassName must match an available StorageClass or a manually created PV.
-
Verify Binding — Confirm the PVC transitions to Bound state. Checkpoint: Run kubectl get pvc -n <namespace> and verify the STATUS column shows Bound.
-
Reference in Pod Spec — Mount the bound PVC in a pod using a volumeMount referencing the PVC name. Checkpoint: The PVC accessModes must be compatible with the pod's access requirements (e.g., ReadWriteOnce pods cannot share ReadWriteMany volumes).
-
Configure Data Lifecycle — Set reclaimPolicy on the StorageClass or PV to control data retention on deletion. Checkpoint: For production databases, use reclaimPolicy: Retain to prevent accidental data loss.
Implementation Patterns
Pattern 1: Complete Dynamic and Static Provisioning Setup
Production-grade StorageClass and PersistentVolumeClaim manifests for both provisioning approaches.
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
---
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
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: postgres-data
namespace: production
spec:
accessModes:
- ReadWriteOnce
storageClassName: premium-ssd
resources:
requests:
storage: 100Gi
volumeMode: Filesystem
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: app-logs
namespace: production
spec:
accessModes:
- ReadWriteMany
storageClassName: nfs-storage
resources:
requests:
storage: 10Gi
volumeMode: Filesystem
---
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.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: broken-pvc
spec:
accessModes:
- ReadWriteMany
storageClassName: ebs-csi
resources:
requests:
storage: 50Gi
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: prod-storage
reclaimPolicy: Delete
volumeBindingMode: Immediate
apiVersion: v1
kind: PersistentVolume
metadata:
name: static-pv
spec:
capacity:
storage: 50Gi
accessModes:
- ReadWriteOnce
storageClassName: manual
persistentVolumeReclaimPolicy: Retain
hostPath:
path: /data/static
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: correct-pvc
spec:
accessModes:
- ReadWriteOnce
storageClassName: premium-ssd
resources:
requests:
storage: 100Gi
volumeMode: Filesystem
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-static-pv
spec:
capacity:
storage: 50Gi
accessModes:
- ReadWriteMany
storageClassName: nfs-storage
persistentVolumeReclaimPolicy: Retain
nfs:
server: nfs-server.example.com
path: /exports/data
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: expandable-pvc
spec:
accessModes:
- ReadWriteOnce
storageClassName: premium-ssd
resources:
requests:
storage: 50Gi
volumeMode: Filesystem
---
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.
"""
if workload_type == "database":
if performance_tier == "premium":
return "premium-ssd"
return "standard-hdd"
if workload_type == "log":
if required_access_mode == "ReadWriteMany":
return "nfs-storage"
return "standard-hdd"
if workload_type == "temp":
return "ephemeral-ssd"
if workload_type == "backup":
return "premium-ssd"
raise ValueError(f"Unknown workload type: {workload_type}")
Constraints
MUST DO
- Always specify
storageClassName explicitly in PVCs — omitting it relies on the default class which may not be appropriate
- Match PVC
accessModes to the StorageClass/PV capabilities — use ReadWriteOnce for block storage and ReadWriteMany only for NFS or distributed filesystems
- Set
reclaimPolicy: Retain on StorageClasses used for production database storage — prevents accidental data loss
- Use
volumeBindingMode: WaitForFirstConsumer for most workloads — delays PV binding until a pod is scheduled, enabling topology-aware provisioning
- Use
allowVolumeExpansion: true on StorageClasses to allow PVCs to grow without migration
- Specify
volumeMode: Filesystem (default) or volumeMode: Block explicitly based on the application's needs
- Verify PV/PVC binding with
kubectl get pv,pvc -n <namespace> after creation
MUST NOT DO
- Never use
hostPath volumes for production workloads — they are node-local and survive node failure
- Never set
reclaimPolicy: Delete on storage used for databases or any data that must be preserved
- Never request
ReadWriteMany on block storage providers (EBS, Azure Disk, GCE PD) — they only support ReadWriteOnce
- Never create a PVC with a
storageClassName that does not exist in the cluster — it will fail binding immediately
- Never use
volumeBindingMode: Immediate with 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 pvc status 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.