Note: This example uses a bare Pod and not a Deployment. In real world production you would use deployment which manages the pod for you. See the separate Deployment example for that.
Overview
The flow is always:
PV (admin creates storage) → PVC (app claims storage) → Pod (uses the storage)| Bare Pod | Deployment | |
|---|---|---|
| Who manages the pod | Nobody — we do it manually | Deployment controller |
| Update volumes | Delete and recreate pod manually | kubectl apply and it recreates automatically |
| Used in | Learning / course exercises | Real world / production |
References
Step 1 — Create the Persistent Volume (PV)
pv-nginx-data.yml
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-nginx-data
labels:
type: local
spec:
storageClassName: local-path
capacity:
storage: 100Mi
accessModes:
- ReadWriteOnce
hostPath:
path: "/data"kubectl apply -f pv-nginx-data.yml
kubectl get pvStep 2 — Create the Persistent Volume Claim (PVC)
nginx-data-pvc.yml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nginx-data-pvc
spec:
accessModes:
- ReadWriteOnce
volumeMode: Filesystem
resources:
requests:
storage: 100Mi
storageClassName: local-pathkubectl apply -f nginx-data-pvc.yml
kubectl get pvcStep 3 — Create the Pod
deploy.yaml
apiVersion: v1
kind: Pod
metadata:
labels:
run: pod
name: nginx-app
spec:
volumes:
- name: nginx-data
persistentVolumeClaim:
claimName: nginx-data-pvc
containers:
- name: nginx-app
image: nginx
volumeMounts:
- mountPath: "/nginx-data"
name: nginx-datakubectl apply -f deploy.yaml
kubectl get podsVerify Everything
kubectl get pv
kubectl get pvc
kubectl get podsExpected output:
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS
nginx-data-pvc Bound pv-nginx-data 100Mi RWO local-path
NAME READY STATUS RESTARTS AGE
nginx-app 1/1 Running 0 30sKey Points
| PV | PVC | |
|---|---|---|
| Created by | Admin | Developer/App |
| Defines | Actual storage | Request for storage |
| Storage size | capacity.storage | resources.requests.storage |
| Names must match | storageClassName | storageClassName |
- The
nameinvolumesandvolumeMountsinside the pod spec must match claimNamein the pod spec must match the PVCmetadata.name
K3s automatically creates the PV and stores data at:
/var/lib/rancher/k3s/storage/pvc-<uid>/To bind a PVC to a specific PV, use labels and selectors:
PV — add a unique label:
yaml
metadata:
name: pv-nginx-data
labels:
pv: pv-nginx-data # ← can be any key/value, just make it uniquePVC — add a selector to match:
yaml
spec:
selector:
matchLabels:
pv: pv-nginx-data # ← must match the PV labelThis ensures the PVC only ever binds to that exact PV.
(Visited 7 times, 1 visits today)

