A PersistentVolumeClaim is running out of space. What does the allowVolumeExpansion field on a Kubernetes StorageClass permit, and what are the exact steps and limits of growing an existing claim?
answer
- Edit the PVC request, never the PV
- Two stages: device then filesystem
- FileSystemResizePending → may need Pod restart
- Shrinking always rejected
- status.capacity catching up = done
basics
~20 sWith allowVolumeExpansion: true on the claim's StorageClass, you edit the PVC's spec.resources.requests.storage upward and the CSI driver grows the disk, then the filesystem. Shrinking is never allowed, and the flag only affects claims whose class had it set.
solid answer
~50 s`allowVolumeExpansion: true` lets users grow a bound PVC of that class. The procedure is a single edit: raise `spec.resources.requests.storage` on the **PVC** (never the PV). Two things then happen — the CSI controller expands the block device in the backend, and the node-side driver grows the filesystem on top of it. Progress and completion show up in `status.capacity` and in PVC conditions such as `Resizing` and `FileSystemResizePending`. Limits worth stating: - **Shrinking is rejected** — the request is validated as monotonically increasing. - The flag is read from the class *the claim uses*; if the class had it false at bind time, you must enable it on the class and, for older drivers, may still need a restart cycle. - **Online expansion** (while a Pod is running) is supported by most modern CSI drivers; some backends still require the Pod to be restarted so the filesystem can be grown offline. - Backend rules still apply: minimum increments, per-volume ceilings, cooldowns between resizes.
code
bash · 10 lineskubectl get sc fast-ssd -o jsonpath='{.allowVolumeExpansion}{"\n"}'
kubectl patch pvc data -p \
'{"spec":{"resources":{"requests":{"storage":"50Gi"}}}}'
# requested vs actual
kubectl get pvc data -o custom-columns=\
NAME:.metadata.name,REQ:.spec.resources.requests.storage,ACTUAL:.status.capacity.storage
kubectl describe pvc data | grep -A6 Conditionsgo deeper
Know that expansion requires allowVolumeExpansion: true and that you edit the PVC's requested storage, not the PV.
Explain the two-stage device-then-filesystem resize, the FileSystemResizePending condition, and that shrinking is impossible.
Cover online versus offline expansion by driver, backend increment/cooldown limits, per-replica expansion for StatefulSet claims, and recovering from a stuck resize.
Treat expansion capability as a default requirement when defining classes, tied to capacity monitoring and an incident runbook, since the fallback is a restore onto a larger volume.
## What the flag actually gates `allowVolumeExpansion` is a boolean on the StorageClass. When false or absent, the API server rejects any attempt to increase `spec.resources.requests.storage` on a bound PVC of that class with a message that the class does not allow expansion. When true, the increase is accepted and the resize controllers take over. The flag is a *permission*, not a mechanism — the actual growing is done by the CSI driver, which must itself implement the `EXPAND_VOLUME` capability. Note which object you edit. Users always edit the **PVC**. Editing the PV's capacity by hand does not resize anything; it just lies about the size and confuses the controllers. ## The two-stage resize Growing storage in Kubernetes is two separate operations: 1. **Controller expansion (the device).** The external-resizer sidecar sees the increased request and calls `ControllerExpandVolume`. The backend grows the block device from, say, 20Gi to 50Gi. The PVC gets the condition `Resizing`. 2. **Node expansion (the filesystem).** A larger block device does not make `df` show more space — the ext4/xfs filesystem on it must be extended too. The node-side driver calls `NodeExpandVolume`, which runs the equivalent of `resize2fs`/`xfs_growfs` on the mounted device. If the driver or backend cannot grow the filesystem while it is mounted, the PVC gets the condition `FileSystemResizePending` and you must restart the Pod: kubelet performs the filesystem expansion during the next mount. With modern drivers and online expansion, both stages complete with the Pod running and no restart at all. Completion is observable: `status.capacity.storage` on the PVC catches up with `spec.resources.requests.storage`. Until it does, the resize is still in flight or stuck. For raw block volumes there is no filesystem step — the device simply gets bigger and the application inside the container must notice. ## Hard limits and gotchas - **No shrinking, ever.** Validation rejects a smaller request. To reduce size you provision a smaller volume and copy the data. - **The class value is what matters at edit time**, and the flag can be toggled on an existing class — unlike `provisioner` and `parameters`. If a class was created without it, enable it there rather than hunting for another workaround. - **Backend granularity.** Cloud providers round up to their own increments and often impose a cooldown (for example, a limited number of modifications per volume per time window). A resize that returns an error about a recent modification is a backend rate limit, not a Kubernetes bug. - **Static PVs have no class** to grant permission, so expansion is generally unavailable for hand-made volumes unless they carry a class name that allows it. - **Not every volume type supports it.** `emptyDir`, `hostPath` and similar non-CSI volume kinds are outside this mechanism entirely. - **StatefulSets:** each replica has its own PVC created from `volumeClaimTemplates`, and the template itself is immutable in older Kubernetes. You expand by patching each existing PVC individually; the template's stated size may then disagree with reality until the workload is recreated. - **Failed expansion recovery.** If you request a size the backend cannot satisfy, the resize can get stuck retrying. Recent Kubernetes versions allow lowering the request back down to a value at or above the current real capacity to escape the loop; older versions leave the claim wedged until an administrator intervenes on the PV. ## Operating it well Expansion is the reason to set `allowVolumeExpansion: true` on essentially every class you create — there is no cost to enabling it, and the alternative when a database fills its disk at 2am is a full backup-and-restore onto a bigger volume. Pair it with monitoring on filesystem utilization (kubelet exports `kubelet_volume_stats_available_bytes`) so growth happens before the application starts erroring. Also be explicit in runbooks that expansion is asynchronous: `kubectl patch` returns instantly, but the space appears only after both stages complete. The check is `kubectl get pvc -o wide` comparing requested and actual capacity, plus `kubectl describe pvc` for conditions and events.
- You increased the PVC request and the device is bigger, but `df` inside the container still shows the old size. Why?The block device grew but the filesystem on top of it has not been extended. Kubernetes reports this as the PVC condition FileSystemResizePending. With drivers and versions that support online expansion this resolves on its own within seconds; otherwise the Pod must be restarted so kubelet can run the filesystem grow during the next mount.
- Can you shrink a PersistentVolumeClaim that turned out to be oversized?No. Kubernetes validates the storage request as non-decreasing and rejects a smaller value, because most filesystems and backends cannot safely shrink in place. The only path is to provision a new, smaller PVC and copy the data across, then repoint the workload and delete the old claim.
saying these in an interview costs you the question
- Editing the PersistentVolume capacity instead of the PVC request
- Claiming volumes can be shrunk if the filesystem has free space
- Assuming the new space is usable the instant kubectl returns
- Forgetting the filesystem stage and blaming the driver when df is unchanged
- Thinking allowVolumeExpansion can never be enabled after the class is created