Core Kubernetes concepts, runnable sample manifests, and cloud provider comparisons for learners and many more.
In modern application development, containers (like those created with Docker) have become the standard way to package and run applications. They provide consistency across different environments. However, managing hundreds or thousands of containers manually across multiple machines is a significant challenge.
This is where Container Orchestration comes in. Kubernetes (often abbreviated as K8s) is an open-source container orchestration platform that automates the deployment, scaling, and management of containerized applications.
It solves key challenges by providing:
A Pod is the smallest and simplest deployable unit in the Kubernetes object model. It represents a single instance of a running process in your cluster.
Key characteristics of a Pod:
localhost
.Understand how Kubernetes abstracts, provisions, attaches, secures, expands, and retires storage for Pods. This section goes beyond basics: volume categories, PV/PVC lifecycle, StorageClasses, CSI, snapshots, expansion, security, and best practices.
Category | Examples (type) | Lifecycle | Typical use |
---|---|---|---|
Ephemeral (per Pod) | emptyDir , configMap , secret , downwardAPI , projected , ephemeral (CSI inline) |
Deleted when Pod gone | Scratch, config injection, credentials |
Node‑attached host path | hostPath , local (local PV) |
Tied to specific node | Single-node fast IO, caches (avoid for portability) |
Persistent (cluster) | persistentVolumeClaim (backed by cloud disks, NFS, filesystems, block, etc.) |
Survives Pod restarts & rescheduling (until PV reclaim) | Databases, stateful apps |
Special | emptyDir{.medium=Memory} , tmpfs , block mode PVs |
Pod lifetime / PV lifetime | High-speed temp, raw block devices |
Notes:
subPath
lets you mount a subdirectory inside a volume (avoid dynamic path mutation at runtime—can break).PVC: Namespaced request for storage (size, access modes, optional StorageClass, volumeMode [Filesystem | Block], selectors). |
allowVolumeExpansion: true
, increasing PVC spec.resources.requests.storage
(and applying) triggers expansion (filesystem grow may require Pod restart depending on driver).Static provisioning:
Dynamic provisioning (preferred):
StorageClass
with a CSI driver provisioner automatically creates the backing volume when a PVC referencing that class appears.volumeBindingMode: WaitForFirstConsumer
delays provisioning & node selection until a Pod using the PVC is scheduled (improves topology fit & AZ alignment).Fields: provisioner , parameters , reclaimPolicy (Delete |
Retain), allowVolumeExpansion , volumeBindingMode (Immediate |
WaitForFirstConsumer), mountOptions . |
Example (AWS gp3 conceptually; adapt to your cloud):
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast-retain
provisioner: ebs.csi.aws.com # cloud / CSI provisioner
parameters:
type: gp3
reclaimPolicy: Retain
allowVolumeExpansion: true
volumeBindingMode: WaitForFirstConsumer
Modern storage drivers are CSI-based (cloud disks, EFS/Azure Files/NFS, SAN vendors). Benefits: pluggable, features (snapshots, volume cloning, expansion, raw block, ephemeral inline).
Inspect installed drivers:
kubectl get csidrivers
Example snapshot objects (conceptual):
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshotClass
metadata:
name: csi-snapclass
driver: ebs.csi.aws.com
deletionPolicy: Delete
---
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
name: db-snap-2025-08-21
spec:
volumeSnapshotClassName: csi-snapclass
source:
persistentVolumeClaimName: db-data
fsGroup
(Pod securityContext
) to ensure shared writable permission for non-root containers.hostPath
in multi-tenant clusters except for controlled system workloads.apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-local-1
spec:
capacity:
storage: 5Gi
accessModes:
- ReadWriteOnce
storageClassName: "" # Ensures it only binds to PVCs without a class
persistentVolumeReclaimPolicy: Retain
hostPath:
path: /mnt/data/pv-local-1
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-claim-1
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
storageClassName: "" # Match the PV above
---
apiVersion: v1
kind: Pod
metadata:
name: app-with-pv
spec:
containers:
- name: web
image: nginx:stable
volumeMounts:
- name: app-storage
mountPath: /usr/share/nginx/html
volumes:
- name: app-storage
persistentVolumeClaim:
claimName: pvc-claim-1
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-dynamic-1
spec:
storageClassName: standard
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-dyn
spec:
replicas: 1
selector:
matchLabels:
app: web-dyn
template:
metadata:
labels:
app: web-dyn
spec:
containers:
- name: nginx
image: nginx:stable
volumeMounts:
- name: web-data
mountPath: /usr/share/nginx/html
volumes:
- name: web-data
persistentVolumeClaim:
claimName: pvc-dynamic-1
Edit PVC size (if allowVolumeExpansion: true
):
kubectl patch pvc pvc-dynamic-1 -p '{"spec":{"resources":{"requests":{"storage":"20Gi"}}}}'
kubectl get pvc pvc-dynamic-1
# List storage classes & drivers
kubectl get storageclass
kubectl get csidrivers
# Describe PVC binding events
kubectl describe pvc pvc-dynamic-1
# Show PV lifecycle
kubectl get pv
# Snapshot list (if CRDs installed)
kubectl get volumesnapshotclasses 2>/dev/null || echo 'snapshot CRDs not installed'
WaitForFirstConsumer
to avoid cross‑AZ scheduling failures in multi‑AZ clusters.Summary:
emptyDir
(scratch) vs Persistent: PV/PVC (stateful data).emptyDir
is created when a Pod is assigned to a Node and exists as long as the Pod runs on that Node.emptyDir
is lost if the Pod is evicted, deleted, or rescheduled to another Node.StorageClass
object provides parameters for dynamic provisioning (provisioner, parameters, reclaimPolicy, volumeBindingMode).provisioner
, parameters
, reclaimPolicy
(Delete/Retain), and volumeBindingMode
(Immediate/WaitForFirstConsumer).kubectl get storageclass
to see available classes in the cluster.Below are two compact examples:
# --- persistent-volume (admin)
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-local-1
spec:
capacity:
storage: 5Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
hostPath:
path: /mnt/data/pv-local-1
# --- persistent-volume-claim (user)
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-claim-1
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
# --- pod that uses the PVC
apiVersion: v1
kind: Pod
metadata:
name: app-with-pv
spec:
containers:
- name: web
image: nginx:stable
volumeMounts:
- mountPath: /usr/share/nginx/html
name: app-storage
volumes:
- name: app-storage
persistentVolumeClaim:
claimName: pvc-claim-1
standard
):# --- persistent-volume-claim (user requests dynamic provisioning)
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-dynamic-1
spec:
storageClassName: standard
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
# --- deployment that uses the dynamically provisioned PVC
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-dyn
spec:
replicas: 1
selector:
matchLabels:
app: web-dyn
template:
metadata:
labels:
app: web-dyn
spec:
containers:
- name: nginx
image: nginx:stable
volumeMounts:
- name: web-data
mountPath: /usr/share/nginx/html
volumes:
- name: web-data
persistentVolumeClaim:
claimName: pvc-dynamic-1
Summary
emptyDir
for ephemeral, per-Pod scratch space. Use PV + PVC when you need data to persist beyond Pod lifetimes.StorageClass
in cloud or well-administered clusters for simplicity and automation.Quick commands
# See storage classes
kubectl get storageclass
# Create PVC and check binding
kubectl apply -f pvc-dynamic-1.yaml
kubectl get pvc pvc-dynamic-1
kubectl describe pvc pvc-dynamic-1
Moved to a dedicated document: GKE vs AKS vs EKS to keep this introduction concise.
Express Your Support If this repo has been beneficial, show your appreciation with a ⭐