Kubernetes Storage
Kubernetes storage — PersistentVolumes, claims, storage classes, and volume mounts for k3s.
Storage Classes
List and inspect storage classes
kubectl get storageclass
kubectl describe storageclass local-path # k3s default
kubectl get storageclass -o jsonpath='{.items[*].metadata.name}'
k3s ships with local-path as the default StorageClass. PersistentVolumes are provisioned at /var/lib/rancher/k3s/storage/ on the node.
|
PersistentVolumeClaims
Create a PVC
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: app-data
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
storageClassName: local-path
List and inspect PVCs
kubectl get pvc -A
kubectl describe pvc app-data
kubectl get pvc -o custom-columns='NAME:.metadata.name,STATUS:.status.phase,SIZE:.spec.resources.requests.storage'
PersistentVolumes
List and inspect PVs
kubectl get pv
kubectl describe pv <pv-name>
Reclaim policies
# Retain — PV persists after PVC deletion (manual cleanup)
# Delete — PV and underlying storage deleted with PVC
# Recycle — deprecated, do not use
kubectl get pv -o custom-columns='NAME:.metadata.name,RECLAIM:.spec.persistentVolumeReclaimPolicy,STATUS:.status.phase'
Mount Volumes in Pods
Use a PVC in a deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: app
spec:
replicas: 1
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: app
image: myapp:v1.0
volumeMounts:
- name: data
mountPath: /var/lib/app/data
volumes:
- name: data
persistentVolumeClaim:
claimName: app-data
Ephemeral Storage
emptyDir — shared scratch space between containers
volumes:
- name: scratch
emptyDir: {}
# emptyDir: { sizeLimit: "1Gi" } # optional size limit
hostPath — mount node filesystem (use sparingly)
volumes:
- name: host-logs
hostPath:
path: /var/log
type: Directory
hostPath breaks portability and bypasses scheduler constraints. Acceptable on single-node k3s; avoid in multi-node clusters.
|
ConfigMaps and Secrets as Volumes
Mount a ConfigMap as files
kubectl create configmap app-config --from-file=config.yaml
volumes:
- name: config
configMap:
name: app-config
Mount a Secret as files
volumes:
- name: tls-certs
secret:
secretName: my-tls
defaultMode: 0400 # read-only for owner
Troubleshooting
Debug storage issues
kubectl get events --field-selector reason=ProvisioningFailed
kubectl describe pvc app-data | awk '/Events:/,0'
kubectl get pv,pvc -A -o wide
# Check local-path provisioner logs
kubectl logs -n kube-system -l app=local-path-provisioner