LAB11d: Storage Basics

LAB100: Storage Basics

  1. pod-init-flag.yaml

apiVersion: v1
kind: Pod
metadata:
  name: init-flag-demo
spec:
  restartPolicy: Never

  volumes:
  - name: shared
    emptyDir: {}

  initContainers:
  - name: prepare-flag
    image: busybox
    command:
    - sh
    - -c
    - |
      echo "Waiting remote DB service..."
      sleep 30
      echo "db_ready" > /work/app_run.flag
      echo "Flag created."
    volumeMounts:
    - name: shared
      mountPath: /work

  containers:
  - name: main-app
    image: busybox
    command:
    - sh
    - -c
    - |
      echo "Checking flag..."
      if [ -f /work/app_run.flag ]; then
        echo "Flag found. Starting app..."
        sleep infinity
      else
        echo "Flag missing. Exiting."
        exit 1
      fi
    volumeMounts:
    - name: shared
      mountPath: /work
  1. pod-init-hostpath-flag.yaml


Kubernetes hostPath Types — Full Table

hostPath Type

Description

If Path Does NOT Exist

DirectoryOrCreate

Must be a directory. Create it if missing.

Directory is automatically created (0755, root).

FileOrCreate

Must be a file. Create it if missing.

Empty file created automatically.

Directory

Must exist and must be a directory.

Pod fails. Error: “not a directory / does not exist”.

File

Must exist and be a file.

Pod fails.

  1. pod-image-volume-psql.yaml

PV, PVC, and Storageclass

Perfect — now we move from direct volumes (emptyDir, hostPath) → to the proper Kubernetes storage pipeline:

PV → PVC → Pod

Below are simple, classroom-friendly labs that demonstrate:

  • PV + PVC using hostPath backend

  • PV + PVC using emptyDir-like behavior? (spoiler: emptyDir cannot be used inside a PV — but I’ll give you the correct equivalent: local PV)

Let’s build these cleanly.


PV/PVC using hostPath as backend

  1. Create the PV pv-hostpath.yaml

  1. Create the PVC pvc-hostpath.yaml

  1. Use It in a Pod pod-hostpath-pv.yaml

  1. Validate

Find the node and check:


emptyDir-like backend using “local volume PV"

(emptyDir cannot be used as PV backend — but local volume gives the same behavior: node-local ephemeral storage.)

⚡ What is “local PV”?

A PV backed by a local directory. Equivalent to hostPath but managed via the PV/PVC mechanism.

  1. Create Local PV pv-local.yaml

  1. PVC

  1. Pod

  1. Validate

Check the node:


Comparing emptyDir vs hostPath vs PV/PVC

Feature
emptyDir
hostPath
PV + PVC (hostPath/local)

Lives on node?

Yes

Yes

Yes

Automatically created?

Yes

Maybe (depends on type)

No, must be prepared

Survives Pod restart?

❌ No

✔️ Yes

✔️ Yes

Survives Pod deletion?

❌ No

✔️ Yes

✔️ Yes (if Retain)

Multi-pod sharing?

✔️ via PVC

Best used for

Scratch, temp storage

Demos, agents

Real apps needing persistence


Here comes the clean, sharp explanation your students will immediately understand — no fluff, just the mechanics of how PVC chooses its PV (the “storage matchmaking ritual” 💡).


🎯 How Does a PVC Know Which PV to Use?

A PVC does not pick randomly. Kubernetes performs a matching algorithm that works like a checklist.

PVC → “I need this much storage, with these access modes, and this storageClass.”

PV → “Here’s what I can offer.”

If all conditions match, Kubernetes binds them.


Matching Rules (The 3-Step Algorithm)

✔️ 1. StorageClass must match

If PVC has a storageClassName, it will only bind to PVs with the same storageClassName.

If PVC has no storageClassName:

  • It binds only to PVs with empty storageClassName.


✔️ 2. AccessModes must be compatible

PVC asks for:

PV must support:

It must include all access modes PVC requests.


✔️ 3. PV capacity must be ≥ PVC capacity

PVC:

PV:

→ Still valid (PVC does not require exact size)


If multiple PVs match?

Kubernetes chooses the smallest PV that fits (“best fit” algorithm).

Example:

Matching PVs:

PV
Size

pv1

1Gi

pv2

5Gi

If PVC requests 1Gi → pv1 wins.


If no PV matches?

PVC goes into Pending state:

It stays there until:

  • a matching PV appears, OR

  • a storageClass dynamically provisions one.


Example That Makes It Click

PVC

Matching PV?

✔ StorageClass matches ✔ AccessMode matches ✔ Size is ≥ required

→ PVC binds automatically to this PV.


Example That Does NOT Match

Reason 1 — StorageClass mismatch

PVC:

PV:

❌ Will never bind.


Example 2 — AccessMode mismatch

PVC requests:

PV offers:

❌ Will never bind.


Example 3 — Size too small

PVC requests:

PV:

❌ PV is too small.


Example 4 — PVC has no storageClassName

PVC:

PV:

❌ Will not bind.


Example 5 — PV already bound

Even if everything matches, if PV is already “Bound” to another PVC → skipped.


“PVC is a request. PV is the offer. Kubernetes binds them only when class, size, and access modes are all compatible.”


Kubernetes Storage Quick Reference Table

Category

Option

Meaning

Access Modes

ReadWriteOnce (RWO)

Mounted read/write by one node

ReadWriteMany (RWX)

Mounted read/write by multiple nodes

ReadOnlyMany (ROX)

Mounted read-only by multiple nodes

Reclaim Policies

Retain

PV is kept after PVC deletion (manual cleanup needed)

Delete

PV + backend storage deleted automatically

Recycle

Older, deprecated — PV is scrubbed (rm -rf), then reused

Storage Class Behavior

storageClassName

Determines which PV or dynamic provisioner is used

"" (empty string)

Bind only to PVs with no class (static provisioning)

unset (null)

PVC uses default StorageClass (dynamic provisioning)

Custom class (e.g., fast, local-storage)

Matches only PVs with that class or triggers that provisioner

Default Storage Class

Here’s a tight, trainer-friendly summary with only the things you asked for:

  • no-provisioner StorageClass

  • local-storage StorageClass

  • commands to list StorageClasses

  • how to set a default StorageClass

  • and the answer to: “Does a PV have to specify a storageClass?”

Let’s go. 🚀


1. StorageClass: no-provisioner (Static PV Only)

This StorageClass cannot dynamically create volumes. Used when you manually create PVs (hostPath, local volumes, etc.).


2. StorageClass: local-storage (Local PV backend)

Used with local PVs that reference a directory on a specific node.

Important: This StorageClass works with local PVs, like:


3. Commands: List StorageClasses

List all storage classes:

Describe a StorageClass:


4. Set a StorageClass as the Default

Only one StorageClass should have the default annotation:

Remove default from another class:

Check which one is default:

You’ll see (default) in the output.


Does a PV have to specify a StorageClass?

Answer: No.

A PV may specify a StorageClass:

Behavior:

PV storageClassName
PVC storageClassName
Binding?

empty ("")

empty ("")

✔ YES

"local-storage"

"local-storage"

✔ YES

"local-storage"

"no-provisioner"

❌ NO

PV empty

PVC "local-storage"

❌ NO

PVC only binds when both have matching storageClassName (or both are empty).


Quick Summary Table

Topic
Key Point

no-provisioner SC

Used for static PVs (manual storage).

local-storage SC

Used with Local PVs on specific nodes.

List SCs

kubectl get storageclass

Set default SC

Patch annotation: is-default-class="true"

Does PV need a class?

❌ No — optional. But must match PVC to bind.

Last updated