KubernetesXLVIII · Storage FundamentalsStorage fundamentals
Storage concepts — access modes, capacity, and the API surface
What you'll learn
- Explain the access modes (RWO, ROX, RWX, RWOP) and what each enables
- Distinguish volume modes (filesystem, block) and their use cases
- Describe the binding semantics between PV and PVC
- Apply the API surface to design PVCs correctly
Prerequisites
Verified against Kubernetes 1.34.x · kubeadm 1.34.x · kubectl 1.34.x · etcd 3.6.x · CoreDNS 1.11.x · containerd 1.7.x / 2.x · 2026-08-16
The Kubernetes storage API surface is small but precise: access modes, capacity, volume modes, and binding. This lesson walks each, explains what they mean, and shows how they combine in a real PVC.
Access modes
Access modes describe how a volume can be mounted:
| Mode | Meaning |
|---|---|
ReadWriteOnce (RWO) | Single node can mount as read-write |
ReadOnlyMany (ROX) | Multiple nodes can mount as read-only |
ReadWriteMany (RWX) | Multiple nodes can mount as read-write |
ReadWriteOncePod (RWOP) | Single Pod can mount as read-write (Kubernetes 1.22+) |
The access mode is a property of the volume, not the workload. The CSI driver advertises which modes it supports; the user requests a mode in the PVC.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: ssd
resources:
requests:
storage: 100Gi
A PVC requesting ReadWriteMany cannot be bound to a PV
that only supports ReadWriteOnce. The binding controller
rejects the binding if the access modes do not match.
Volume modes
Volume modes describe how the volume appears to the Pod:
| Mode | Meaning |
|---|---|
Filesystem | The volume is formatted with a filesystem and mounted as a directory. Default. |
Block | The volume is exposed as a raw block device. The application uses it directly, no filesystem. |
Filesystem is the standard mode; the kubelet formats the
volume (if needed) and mounts it as a directory. Block
is for applications that manage their own filesystem
(database storage engines, raw device access).
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: raw-data
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: ssd
volumeMode: Block
resources:
requests:
storage: 100Gi
A Block volume is mounted as a device, not a directory.
The application sees /dev/xvdba, not /mnt/data.
Capacity
The PVC’s capacity request is a minimum, not a maximum:
spec:
resources:
requests:
storage: 100Gi
The PV must provide at least 100 GB. If the PV provides more (e.g., 200 GB), the PVC sees 200 GB.
Capacity expansion (where supported by the CSI driver) allows the user to grow the PVC:
kubectl edit pvc data
# Change spec.resources.requests.storage to 200Gi
The CSI driver handles the expansion; the filesystem is resized; the application sees the new capacity.
StorageClass
The StorageClass is the user’s pointer to a provisioning template:
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: ssd
provisioner: ebs.csi.aws.com
parameters:
type: gp3
iops: "3000"
throughput: "125"
volumeBindingMode: WaitForFirstConsumer
reclaimPolicy: Delete
allowVolumeExpansion: true
The PVC references the StorageClass by name:
spec:
storageClassName: ssd
The provisioner (e.g., ebs.csi.aws.com) creates a PV
when a PVC is submitted. The volumeBindingMode controls
when the PV is created (immediately, or when a Pod
schedules).
Binding semantics
The PV and PVC are bound by a controller in the control plane:
flowchart LR
A[PVC submitted] --> B{StorageClass specified?}
B -->|yes| C[Provisioner creates PV]
B -->|no| D[Look for matching existing PV]
C --> E[Bind PV to PVC]
D --> F{Found matching PV?}
F -->|yes| E
F -->|no| G[PVC Pending]
The binding controller matches PVs to PVCs by:
- Access modes: the PV’s modes must include at least one of the PVC’s modes.
- Capacity: the PV’s capacity must be >= the PVC’s request.
- StorageClass: the PV’s StorageClass must match the PVC’s (or be unset if the PVC’s is unset).
- Selector: the PVC’s selector must match the PV’s labels (if specified).
A PVC that does not match any existing PV is Pending
until a PV is provisioned (dynamic) or until an existing
PV is created (static).
The API surface summary
| Field | Where | Effect |
|---|---|---|
accessModes | PVC | What mount modes the volume must support |
storageClassName | PVC | Which StorageClass to provision from |
resources.requests.storage | PVC | Minimum capacity |
volumeMode | PVC | Filesystem or block |
selector | PVC | Label selector for matching PVs |
volumeName | PVC | Explicit PV to bind to |
reclaimPolicy | PV | What happens to the PV when PVC is deleted |
persistentVolumeReclaimPolicy | StorageClass | Default reclaim policy for provisioned PVs |
The API surface is small but the combinations are expressive. Operators must understand each field to design PVCs correctly.
Quiz
Knowledge check · 4 questions
Q1. A database workload needs to mount the same volume from multiple Pods on different nodes with read-write access. Which access mode is required?
Q2. A PVC requesting 100 GB will be bound to a PV with exactly 100 GB of capacity.
Q3. A team designs a PVC for a database workload that needs RWX. Walk through the design decisions and identify what is required.
PostgreSQL StatefulSet. Multiple read-replica Pods on different nodes need to mount the same data volume with read-write access (for replication).
Q4. Name the four fields that determine PVC-PV binding and explain how the binding controller uses them.
Passing score: 75%. Answers are checked in this browser.
Production discipline
- Choose the access mode by the workload. RWX is rare and constrained; RWO is the standard.
- Capacity is a minimum, not a maximum. The PV can provide more than requested.
- Volume mode
Blockfor raw device access,Filesystemfor standard mounts. The choice affects the Pod’s view. - StorageClass is the template, the PVC is the request. The provisioner is the implementation.
- Binding is by selector, capacity, StorageClass, and access mode. A PVC that does not match is Pending.