Kubernetes Storage

Kubernetes storage primitives: ephemeral volumes, PersistentVolumes, PersistentVolumeClaims, StorageClasses, access modes, and reclaim policies. The ~10% Storage domain on the CKA exam. Synthesized from CKA Day 29 — Kubernetes Volume Simplified.

Overview

Containers are ephemeral by design, but many workloads (databases, file servers, CI/CD artifacts) need data to survive container restarts, Pod reschedules, and even cluster upgrades. Kubernetes provides a layered storage model that ranges from temporary scratch space to cloud-backed persistent disks.

Ephemeral Volumes

EmptyDir

An emptyDir volume is created when a Pod is scheduled and exists as long as the Pod lives on its node. If the container crashes and restarts, the emptyDir data survives because it is tied to the Pod, not the container. However, if the Pod is deleted, the emptyDir is permanently deleted.

AspectBehavior
LifecyclePod-scoped
Survives container restartYes
Survives Pod deletionNo
Use caseTemporary caches, shared scratch space between containers in a Pod
spec:
  containers:
  - name: redis
    image: redis
    volumeMounts:
    - name: cache
      mountPath: /data/redis
  volumes:
  - name: cache
    emptyDir: {}

Demo insight: In the Day 29 demo, a Redis container was killed with kill -9. Because the Pod itself remained, the file written to emptyDir was still present after the container restart. When the Pod was deleted and recreated, the file was gone. Source: CKA Day 29

hostPath

A hostPath volume mounts a directory from the host node’s filesystem into the Pod. It is the Kubernetes equivalent of a Docker bind mount.

Critical limitation: hostPath is not suitable for multi-node clusters. If the Pod is rescheduled to a different node, the new node will not have the same host directory, causing data loss or mount failures. It is acceptable only for single-node test clusters or specific node-local system utilities.

spec:
  volumes:
  - name: local-data
    hostPath:
      path: /home/ubuntu/day29
      type: Directory

In the Day 29 demo, nodeName: master was used to pin the Pod to the control plane node where the host path existed — a hack that only works because the cluster is single-node. For true persistence across nodes, use PersistentVolumes. Source: CKA Day 29

PersistentVolumes (PV)

A PersistentVolume (PV) is a cluster-scoped storage resource provisioned by a cluster administrator or by a dynamic provisioner. It represents a piece of storage in the cluster — NFS share, iSCSI LUN, cloud block disk, etc. — that has been made available for use.

PV YAML Anatomy

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-1gb
  labels:
    type: local
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  storageClassName: manual
  hostPath:
    path: /home/ubuntu/day29
FieldPurpose
capacity.storageTotal storage pool available for claims
accessModesHow the volume can be mounted (must match PVC)
persistentVolumeReclaimPolicyWhat happens to the PV when the PVC is deleted
storageClassNameLinks to a StorageClass for dynamic provisioning
hostPath / nfs / awsElasticBlockStoreThe actual backing storage implementation

PersistentVolumeClaims (PVC)

A PersistentVolumeClaim (PVC) is a namespace-scoped request for storage. Users (application teams, CI/CD pipelines) create PVCs without needing to know the underlying storage infrastructure. The Kubernetes control plane binds a suitable PV to the PVC.

PVC YAML Anatomy

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-500mi
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 500Mi
  storageClassName: manual

The Binding Lifecycle

  1. Admin provisions PV → PV exists with capacity (e.g., 1 Gi) and access modes.
  2. User creates PVC → requests 500 Mi with matching access mode.
  3. Scheduler / Controller matches → if capacity is greater than or equal to request and access mode matches, a binding is created.
  4. PV capacity is consumed → remaining cluster pool is reduced (1 Gi → ~500 Mi left, depending on implementation).
  5. Pod references PVC → the PVC is mounted into the Pod as a volume.

Pending trap: If no PV has enough capacity, or if the access mode does not match, the PVC stays in Pending and the Pod that depends on it also stays Pending. Source: CKA Day 29

Access Modes

Access modes define how a volume can be mounted by nodes. They are not enforced by Kubernetes itself; the underlying storage system (NFS, EBS, etc.) must actually support the mode.

ModeAbbreviationBehavior
ReadWriteOnceRWOVolume can be mounted read-write by a single node
ReadOnlyManyROXVolume can be mounted read-only by many nodes
ReadWriteManyRWXVolume can be mounted read-write by many nodes
ReadWriteOncePodRWXOPODVolume can be mounted read-write by a single Pod (v1.27+)

Binding rule: The PVC’s accessModes must exactly match one of the PV’s accessModes. A PV with RWO cannot satisfy a PVC requesting RWX. This is a common reason for PVCs remaining Pending.

Reclaim Policies

When a PVC is deleted, the reclaim policy tells Kubernetes what to do with the underlying PV.

PolicyBehaviorUse Case
RetainPV is released but not deleted; data remains on the backend; no new PVC can claim it unless manually re-boundData must survive workload deletion
DeletePV and its underlying storage asset are deleted automaticallyEphemeral environments, CI/CD
RecyclePV is scrubbed (emptied) and made Available againDeprecated; replaced by dynamic provisioning

Exam note: Recycle is deprecated. Modern clusters rely on dynamic provisioning via StorageClasses instead. Source: CKA Day 29

StorageClasses

A StorageClass abstracts the underlying storage provider. It defines a provisioner (e.g., kubernetes.io/aws-ebs, kubernetes.io/gce-pd, kubernetes.io/azure-file, nfs-client) and parameters (replication, tier, disk type). StorageClasses enable dynamic provisioning: when a PVC requests a class, the provisioner automatically creates the PV and the backing storage.

Static vs Dynamic Provisioning

ApproachWho creates PVWorkflow
StaticAdministratorAdmin creates PV → User creates PVC → Kubernetes binds them
DynamicProvisioner (StorageClass)User creates PVC referencing a StorageClass → Provisioner auto-creates PV and storage backend

Default StorageClass

A cluster can have multiple StorageClasses, but one should be marked as default. If a PVC omits storageClassName, the default class is used. This is how managed Kubernetes services (EKS, GKE, AKS) automatically provision cloud disks without user intervention.

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: fast-ssd
provisioner: kubernetes.io/aws-ebs
parameters:
  type: gp3
  encrypted: "true"

Using a PVC in a Pod

apiVersion: v1
kind: Pod
metadata:
  name: task-pv-pod
spec:
  nodeName: master        # Only for single-node hostPath demos
  containers:
  - name: nginx
    image: nginx
    volumeMounts:
    - name: task-pv-storage
      mountPath: /usr/share/nginx/html
  volumes:
  - name: task-pv-storage
    persistentVolumeClaim:
      claimName: pvc-500mi
FieldPurpose
volumeMounts[].nameMust match volumes[].name
volumeMounts[].mountPathDirectory inside the container
volumes[].persistentVolumeClaim.claimNameThe PVC to bind

CKA Exam Relevance

Storage appears in the ~10% Storage domain. Common tasks:

  • Create a PVC from a given StorageClass
  • Mount a PVC into a Pod at a specific path
  • Troubleshoot Pending PVCs (capacity mismatch, access mode mismatch, missing StorageClass)
  • Understand which resources are cluster-scoped (PV, StorageClass, Node) vs namespace-scoped (PVC, Pod)

Speed pattern: Know the PVC → Pod volume wiring by heart: spec.volumes[].persistentVolumeClaim.claimName and spec.containers[].volumeMounts[].


Tags: kubernetes storage persistent-volume pvc storage-class emptydir hostpath access-modes reclaim-policy cka devops