Part of the series Kubernetes storage
Kubernetes storage explained: StorageClass, PV, and PVC
An application needs somewhere to keep its data. In Kubernetes, that involves several objects that describe different parts of the request. The application asks for storage through a PVC; Kubernetes connects that claim to a PV. A StorageClass describes the kind of storage and how it should be provisioned.
The diagrams below explain those relationships and then follow dynamic provisioning in order. Use Play to watch the phases, or Next to study one phase at a time. Each diagram also works as a complete static reference with JavaScript disabled or reduced motion enabled.
StorageClass, PV, PVC, and Pod in plain English
| Object | What it means | Scope |
|---|---|---|
| StorageClass (SC) | A storage policy: which provisioner to use and which provisioning settings apply. | Cluster-wide |
| PersistentVolume (PV) | A Kubernetes object representing storage supplied by a storage system or administrator. The PV object is distinct from the physical disk or network share. | Cluster-wide |
| PersistentVolumeClaim (PVC) | An application’s request for storage, including capacity and access requirements. | Namespace |
| Pod | The workload that references the PVC and exposes the volume to a container. | Namespace |
For example, a claim might request 10Gi from a class named fast-ssd. The Pod references that claim by name and mounts the volume at /data.
The Pod’s volumes entry identifies the claim. Its container’s volumeMounts entry selects where the files appear inside the container. For background on the workload itself, see What is a Kubernetes Pod?.
Dynamic provisioning: storage created on demand
With dynamic provisioning, a supported provisioner creates storage to satisfy a claim when the class’s binding policy allows it. The administrator does not need to create each PV manually. This relationship is described in the official dynamic provisioning documentation.
Open the dynamic provisioning diagram in a full browser tab.
Read the diagram as relationships: Pod → PVC → StorageClass → provisioner. The provisioner requests the actual storage and creates a PV representing it. Kubernetes then binds the claim and PV.
A StorageClass is a policy, not a storage device. Creating the class alone does not create a disk. The provisioner and its storage backend must already be configured.
The architecture view explains who refers to whom. It is not the order of every API operation, and application file reads and writes do not pass through the StorageClass or provisioning sidecar.
WaitForFirstConsumer: why the PVC can stay Pending
Some storage is tied to a node or availability zone. Provisioning before the workload’s placement is understood can produce a volume that the Pod cannot use.
volumeBindingMode: WaitForFirstConsumer delays binding and provisioning until a consuming Pod lets Kubernetes consider scheduling constraints. See the StorageClass volume binding documentation.
Open the provisioning sequence in a full browser tab.
The sequence has six phases:
- Create a PVC. The request can remain
Pendingwhile it waits for a consumer. - Create a Pod that uses the claim. The scheduler observes the workload.
- Select a candidate node. Scheduling takes storage topology into account. In this example, the selected node is recorded on the claim.
- Provision storage and create a PV. The external-provisioner coordinates with the CSI driver to create suitable backing storage and its PV representation.
- Bind the PVC and PV. The claim and volume become associated.
- Complete Pod binding and prepare the volume. Attachment, where required, and node-side mounting make the volume available to the container.
Choosing a candidate node is different from completing Pod scheduling. The diagram separates these events so the delayed-binding process is easier to follow.
A claim waiting for its first consumer is not necessarily broken. Check its Events before treating Pending as a provisioning failure.
Static provisioning: the PV exists first
An administrator can also prepare storage and create PVs ahead of time. Kubernetes matches a suitable available PV to a claim instead of asking a provisioner to create a new one.
Watch the static provisioning flow
Open the static provisioning diagram in a full browser tab.
The class in this example uses kubernetes.io/no-provisioner. That class creates neither disks nor PVs. If no suitable PV exists, the claim has nothing to bind to.
For local volumes, the administrator also describes the PV’s node affinity so Kubernetes knows which node can access it. Matching involves more than the class name: capacity, access requirements, and placement must also be suitable. See the PersistentVolume documentation.
Example: a StorageClass, PVC, and consuming Pod
This example follows the AWS EBS CSI driver named in the supplied architecture diagram. It requires that driver, its controller and node components, suitable permissions, and a compatible cluster. It is an illustrative configuration, not a deployment tested for this article.
The StorageClass selects the EBS CSI driver and uses delayed binding:
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast-ssd
provisioner: ebs.csi.aws.com
parameters:
type: gp3
volumeBindingMode: WaitForFirstConsumer
reclaimPolicy: Retain
The claim requests capacity from that class:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-data
spec:
storageClassName: fast-ssd
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
The Pod references the claim and mounts it at /data:
apiVersion: v1
kind: Pod
metadata:
name: storage-demo
spec:
containers:
- name: app
image: busybox:1.37
command: ["sh", "-c", "sleep 3600"]
volumeMounts:
- name: data
mountPath: /data
volumes:
- name: data
persistentVolumeClaim:
claimName: my-data
Create the PVC and Pod in the same namespace. This example uses ReadWriteOnce, which describes read/write mounting by one node; it does not by itself guarantee that only one Pod can use the volume.
Retain is explicit here so deleting a claim does not automatically reclaim its backing storage. It requires an administrator to manage eventual storage cleanup. Reclaim policy is separate from a backup strategy; the PV lifecycle documentation explains the distinction between retention and deletion.
Troubleshoot the request before the mount
Start with the class, claim, and Pod. Add -n YOUR_NAMESPACE where needed:
kubectl get storageclass
kubectl get pvc,pods
kubectl describe pvc my-data
kubectl describe pod storage-demo
kubectl get pv
| Symptom | What to inspect |
|---|---|
PVC is Pending, with no consuming Pod |
Check whether its class uses WaitForFirstConsumer. |
PVC stays Pending after the Pod exists |
Read claim and Pod Events; check class, scheduling constraints, driver availability, and capacity. |
| A no-provisioner claim never binds | Look for a compatible administrator-created PV. |
PVC is Bound, but the Pod cannot start |
Inspect scheduling, topology, volume attachment, and mount errors in Pod Events and driver logs. |
| Storage exists but the application cannot write | Check filesystem permissions, mount settings, and the application’s user identity. |
Bound means the claim has a volume. It does not prove that mounting succeeded or that the application is healthy. Follow the evidence from claim to Pod to node-side storage components.
Download the source diagrams
The interactive views are adapted from the two supplied HTML diagrams. The architecture file is separated into dynamic and static views; the sequence retains its twelve messages, grouped into six playback phases. The controller, API server, storage backend, and node operations are simplified for explanation; real systems also handle retries, failures, and driver-specific behavior.
- Original architecture diagram: dynamic and static provisioning
- Original dynamic provisioning sequence
Use the architecture diagram to understand the references. Use the sequence to understand when provisioning, binding, and mounting happen.