Skip to content

Persistent volumes in practice

A PersistentVolumeClaim (PVC) is how your workload requests storage from the cluster. You declare the size and storage class you need, commit the manifest to your repo, and ArgoCD syncs it — the Cinder CSI provisioner creates the underlying volume automatically.

A single-writer volume uses ReadWriteOnce against the default class:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-data
namespace: <your-tenant>-prod
spec:
accessModes:
- ReadWriteOnce
storageClassName: csi-cinder-sc-delete
resources:
requests:
storage: 10Gi

Both Cinder storage classes are block volumes and support ReadWriteOnce only. A PVC bound to csi-cinder-sc-delete (the default) is destroyed when the claim is deleted; use csi-cinder-sc-retain if you need the underlying volume to survive accidental PVC deletion. See Storage classes for the comparison.

Replace <your-tenant> with your actual tenant name. The namespace must start with your tenant prefix — see Namespace prefix for the enforcement rule.

storageClassName selects which Cinder storage class provisions the volume. Kestrel allows exactly two:

  • csi-cinder-sc-delete — block storage, ReadWriteOnce, reclaim policy Delete. This is the cluster default; omitting storageClassName selects it.
  • csi-cinder-sc-retain — block storage, ReadWriteOnce, reclaim policy Retain.

See Storage classes for the full comparison, including reclaim policy and backup behaviour.

These are the only two classes the cluster accepts. If you name any other storageClassName, the PVC is rejected at admission and stays Pending — it never binds.

Neither Cinder class supports ReadWriteMany, so a shared, multi-writer volume cannot be requested through a storage class. When a tenant needs RWX storage, RCS provisions a per-tenant NFS export and binds it in as a static PersistentVolume. Open a ticket with RCS to request one.

Once RCS has created the PV for your tenant, claim it with a PVC that has an empty storageClassName (so the dynamic Cinder provisioner is bypassed) and matches the PV’s access mode and capacity. A real tenant export looks like this — an NFS-backed PV created by RCS on server rsfshare.uvic.ca:

apiVersion: v1
kind: PersistentVolume
metadata:
name: my-nfs-pv
spec:
capacity:
storage: 10Ti
accessModes:
- ReadWriteMany
storageClassName: ""
nfs:
server: rsfshare.uvic.ca
path: /mlp

You then bind it from your namespace with a matching PVC:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: shared-uploads
namespace: <your-tenant>-prod
spec:
accessModes:
- ReadWriteMany
storageClassName: ""
volumeName: my-nfs-pv
resources:
requests:
storage: 10Ti

The PV is cluster-scoped and created by RCS; the PVC lives in your namespace and binds to it by volumeName. Multiple Pods across nodes can mount an RWX NFS volume concurrently.

Request what you need, not what you think the ceiling should be. The requested size counts against your tenant’s storage quota immediately, regardless of how much your workload actually writes.

  • Start small, grow later. Increasing a volume’s size means editing spec.resources.requests.storage in the PVC manifest. Whether expansion can be applied to an existing PVC without recreating it depends on the storage class’s allowVolumeExpansion setting — confirm with RCS before relying on in-place growth for a live workload. Shrinking is never supported.
  • Watch for quota exhaustion. The total requested storage across all PVCs in all namespaces of your tenant counts against one shared pool. If you exceed your quota, new PVCs stay Pending and existing workloads are unaffected.

Storage quota is part of your tenant’s ResourcePool, shared across all namespaces in the tenant. The quota tracks the sum of spec.resources.requests.storage across every PVC — actual bytes on disk do not matter, only what you requested.

When quota is exhausted:

  1. New PVCs stay Pending with an event like exceeded quota.
  2. Existing PVCs and their Pods continue to run — quota enforcement does not evict running workloads.
  3. Resizing an existing PVC larger also fails if the new size would exceed quota.

To free quota, delete PVCs you no longer need. See Resource pools and quotas for the tier numbers and the accounting model.

Reference the PVC in your Pod spec’s volumes and volumeMounts:

spec:
containers:
- name: app
image: your-image:latest
volumeMounts:
- name: data
mountPath: /data
volumes:
- name: data
persistentVolumeClaim:
claimName: my-data

The Pod and PVC must be in the same namespace. Both Cinder classes are ReadWriteOnce, so the volume can be mounted by one node at a time — schedule the consuming Pods accordingly. If the PVC binds an RCS-provisioned NFS PV (RWX), multiple Pods can mount it concurrently.

SymptomLikely cause
PVC stays PendingStorage quota exceeded, or storageClassName names a class other than csi-cinder-sc-delete / csi-cinder-sc-retain (rejected at admission)
Pod stays Pending with volume errorPVC is RWO and already mounted by another Pod on a different node
Permission denied writing to mountPod security context does not match the volume’s filesystem permissions — check fsGroup in your Pod spec
Data missing after Pod restartYou mounted an emptyDir or wrote to the container filesystem instead of the PVC path — ephemeral storage is lost on restart