# StorageClass Disallows Volume Expansion

> Flags StorageClasses whose allowVolumeExpansion is false or unset, so claims created from them cannot be resized in place.

Source: https://zop.dev/integrations/kubernetes/recommendations/storageclass-disallows-volume-expansion

---

## Why a fixed-size class becomes a migration later

Databases, queues and log stores grow. On a class that allows it, growing a volume is a one-line
change: edit the claim's requested size and the volume behind it is expanded in place. The
[PersistentVolumes documentation](https://kubernetes.io/docs/concepts/storage/persistent-volumes/)
is explicit that you can only expand a PVC if its storage class's `allowVolumeExpansion` field is
set to `true`, and that no new PersistentVolume is created in the process.

On a class that forbids it, the same request is refused. The team is left to provision a larger
claim, copy the data across and cut the workload over, which is downtime and risk for a problem
that should have been routine. Expansion only ever grows a volume; Kubernetes does not support
shrinking a claim below its current size.

## Finding classes that block resizing

```bash
kubectl get storageclass -o json | jq -r '
  .items[]
  | select(.allowVolumeExpansion != true)
  | "\(.metadata.name) provisioner=\(.provisioner) allowVolumeExpansion=\(.allowVolumeExpansion)"'
```

Then see which claims depend on each one:

```bash
kubectl get pvc -A -o json | jq -r '
  .items[] | select(.spec.storageClassName == "<class-name>")
  | "\(.metadata.namespace)/\(.metadata.name) \(.spec.resources.requests.storage)"'
```

## Anything other than true

ZopNight reads the field from the StorageClass it collected and fires when expansion is not
enabled. A class that omits `allowVolumeExpansion` is recorded as `false`, so an unset field is
flagged the same way as an explicit `false`, which matches Kubernetes, where only `true` permits
expansion. There is no metric or window. The check does not look at the claims using the class,
so a class with no claims at all is flagged the same as one backing a busy database.

## What the check cannot see

The rule does not know whether the provisioner is able to expand volumes. The
[storage classes page](https://kubernetes.io/docs/concepts/storage/storage-classes/) lists
expansion support by volume type, with CSI volumes supported from Kubernetes 1.24, but the CSI
driver itself must implement it.

## Governance, not savings

This low-severity finding has no dollar figure. Its benefit is avoiding a future data migration
and the temptation to over-provision disks up front just in case, which costs money from day one.

## Enabling expansion on the class

1. Confirm the provisioner supports volume expansion in its own documentation.
2. Patch the class in place:
   `kubectl patch storageclass <name> -p '{"allowVolumeExpansion": true}'`. Unlike the
   provisioner, parameters, reclaim policy and binding mode, this field is not immutable.
3. Test on a non-critical claim by raising `spec.resources.requests.storage` and watching
   `kubectl describe pvc` for the resize events.
4. Record the change in the manifest or chart that owns the StorageClass so a redeploy does not
   revert it.

A related setting on the same object is covered by
[StorageClass uses immediate binding](https://zop.dev/integrations/kubernetes/recommendations/storageclass-uses-immediate-binding).
