Kubernetes Storage
Concept
![[images/截屏2026-03-24 16.45.32.png]]
A Volume can be used to hold data and state for Pods and containers.
- A Pod can have multiple Volumes attached to it.
- Containers rely on a mountPath to access a volume.
Storage Types
- Volumes
- PersistentVolumes
- PersistentVolumeClaims
- StorageClasses
Volumes
- A Volume references a storage location
- Must have a unique name
- Attached to a Pod and may or may not be tied to the Pod’s lifetime (depending on the Volume type)
- A Volume Mount references a Volume by name and defines a mountPath
Volume Types
- emptyDir: Empty directory for storing transient data (shares a Pod’s lifetime) useful for sharing files between containers running in a Pod. (Ephemeral storage)
- hostPath: Pod mounts into the node’s filesystem.
- Network File System (nfs): An NFS share mounted into the Pod.
- configMap/secret: Special types of volumes that provide a Pod with access to Kubernetes resources.
- persistentVolumeClaim: Provides Pods with a more persistent storage option that is abstracted from the details.
- cloud: Cluster-wide storage
emptyDir Volume
apiVersion: v1
kind: Pod
metadata:
name: nginx-alpine-volume
spec:
containers:
- name: nginx
image: nginx:alpine
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html
readOnly: true
resources:
- name: html-updater
image: alpine
command: ["/bin/sh", "-c"]
args:
- while true; do date >> /html/index.html;sleep 10; done
resources:
volumeMounts:
- name: html
mountPath: /html
volumes:
- name: html
emptyDir: {} #lifecycle tied to Pod
# kubectl apply -f nginx-alpine-emptyDir.pod.yml
# kubectl port-forward nginx-alpine-volume 8080:80
![[images/截屏2026-03-24 17.14.14.png]]
hostPath Volume
apiVersion: v1
kind: Pod
metadata:
name: docker-volume
spec:
containers:
- name: docker
image: docker
command: ["sleep"]
args: ["100000"]
volumeMounts:
- name: docker-socket
mountPath: /var/run/docker.sock
resources:
volumes:
- name: docker-socket
hostPath:
path: /var/run/docker.sock
type: Socket
# Once Pod is created you can shell into it to run Docker commands:
# kubectl exec [pod-name] -it -- sh
Valid types includes:
- DirectoryOrCreate
- Directory
- FileOrCreate
- File
- Socket
- CharDevice
- BlockDevice
![[images/截屏2026-03-24 17.22.15.png]]
Cloud Volumes
Cloud providers support different types of Volumes:
- Azure: Azure Disk and Azure File
- AWS: Elastic Block Store
- GCP: GCE Persistent Disk
![[images/截屏2026-03-24 17.26.28.png]]
![[images/截屏2026-03-24 17.27.06.png]]
![[images/截屏2026-03-24 17.27.29.png]]
Check
kubectl describe pod [pod_name]
# Get Pod YAML
kubectl get pod [pod_name] -o yaml
PersistentVolumes and PersistentVolumeClaims
A PersistentVolume (PV) is a cluster-wide storage unit provisioned by an administrator with a lifecycle independent from a Pod.
A PersistentVolumeClaim (PVC) is a request for a storage unit (PV).
![[images/截屏2026-03-25 15.14.44.png]]
- A PersistentVolume is a cluster-wide storage resource that relies on network-attached storage (NAS).
- Normally provisioned by a cluster administrator.
- Available to a Pod even if it gets rescheduled to a different Node.
- Rely on a storage provider such as NFS, cloud storage, or other options.
- Associated with a Pod by using a PersistentVolumeClaim.
PersistentVolume Workflow
- Create network storage resource (NFS, cloud, …)
- Define a PV and send to the Kubernetes API
- Create a PVC
- Kubernetes binds the PVC to the PV
- Pod Volume references the PVC
![[images/截屏2026-03-25 15.18.40.png]]
YAML
Create PV
![[images/截屏2026-03-25 15.22.06.png]]
Create PVC
![[images/截屏2026-03-25 15.22.55.png]]
Create Reference
![[images/截屏2026-03-25 15.24.08.png]]
StorageClasses
A StorageClasses (SC) is a type of storage template that can be used to dynamically provision storage.
![[images/截屏2026-03-25 15.25.59.png]]
- Used to define different classes of storage
- Act as a type of storage template
- Supports dynamic provisioning of PersistentVolumes
- Don’t need to create PV in advance
StorageClass Workflow
- Create Storage Class
- Create PVC referencing to SC
- Kubernetes uses SC provisioner to provision a PV
- Storage provisioned, PV created and bound to PVC
- Pod volume references PVC
![[images/截屏2026-03-25 15.29.41.png]]
YAML
Define SC
![[images/截屏2026-03-25 15.31.02.png]]
Define PV
![[images/截屏2026-03-25 15.32.48.png]]
Define PVC
![[images/截屏2026-03-25 15.33.50.png]]
![[images/截屏2026-03-25 15.34.15.png]]
Mongo Example
apiVersion: v1
kind: ConfigMap
metadata:
labels:
app: mongo-env
name: mongo-env
data:
MONGODB_DBNAME: codeWithDan
#NO - not a good idea to store a password in a ConfigMap (demo only). See the "secrets" folder for another demo of this.
MONGODB_PASSWORD: password
MONGODB_ROLE: readWrite
#NO - not a good idea to store a password in a ConfigMap (demo only). See the "secrets" folder for another demo of this.
MONGODB_ROOT_PASSWORD: password
MONGODB_ROOT_ROLE: root
MONGODB_ROOT_USERNAME: dbadmin
MONGODB_USERNAME: webrole
---
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: local-storage
provisioner: kubernetes.io/no-provisioner
# The reclaim policy applies to the persistent volumes not the storage class itself.
# pvs and pvcs that are created using that storage class will inherit the reclaim policy set here.
reclaimPolicy: Retain
volumeBindingMode: WaitForFirstConsumer
---
# Note: While a local storage PV works, going with a more durable solution (NFS, cloud option, etc.) is recommended
# Adding this for demo purposes to run on Docker Desktop Kubernetes since it only supports a single Node
# https://kubernetes.io/blog/2018/04/13/local-persistent-volumes-beta/
apiVersion: v1
kind: PersistentVolume
metadata:
name: mongo-pv
spec:
capacity:
storage: 1Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
# StorageClass has a reclaim policy default so it'll be "inherited" by the PV
# persistentVolumeReclaimPolicy: Retain
storageClassName: local-storage
hostPath:
path: /private/tmp/data/db
type: DirectoryOrCreate
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- docker-desktop
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mongo-pvc
spec:
accessModes:
- ReadWriteOnce
storageClassName: local-storage
resources:
requests:
storage: 1Gi
---
apiVersion: v1
kind: Service
metadata:
name: mongo
spec:
selector:
app: mongo
ports:
- port: 27017
targetPort: 27017
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
labels:
app: mongo
name: mongo
spec:
serviceName: mongo
replicas: 1
selector:
matchLabels:
app: mongo
template:
metadata:
labels:
app: mongo
spec:
containers:
- image: mongo
name: mongo
ports:
- containerPort: 27017
command:
- mongod
- "--auth"
resources: {}
volumeMounts:
- name: mongo-volume
mountPath: /data/db
env:
- name: MONGODB_DBNAME
valueFrom:
configMapKeyRef:
key: MONGODB_DBNAME
name: mongo-env
- name: MONGODB_PASSWORD
valueFrom:
configMapKeyRef:
key: MONGODB_PASSWORD
name: mongo-env
- name: MONGODB_ROLE
valueFrom:
configMapKeyRef:
key: MONGODB_ROLE
name: mongo-env
- name: MONGODB_ROOT_PASSWORD
valueFrom:
configMapKeyRef:
key: MONGODB_ROOT_PASSWORD
name: mongo-env
- name: MONGODB_ROOT_ROLE
valueFrom:
configMapKeyRef:
key: MONGODB_ROOT_ROLE
name: mongo-env
- name: MONGODB_ROOT_USERNAME
valueFrom:
configMapKeyRef:
key: MONGODB_ROOT_USERNAME
name: mongo-env
- name: MONGODB_USERNAME
valueFrom:
configMapKeyRef:
key: MONGODB_USERNAME
name: mongo-env
volumes:
- name: mongo-volume
persistentVolumeClaim:
claimName: mongo-pvc