quyennv.com

Senior DevOps Engineer · Healthcare, Fanance

Detecting…

Kubernetes PV, PVC, and How They Attach to Pods (Deployments, StatefulSets, DaemonSets)

#kubernetes#k8s#storage#pvc#pv#statefulset#deployment#devops

0

Persistent storage in Kubernetes is modeled with PersistentVolumes (PV) and PersistentVolumeClaims (PVC). Pods never “own” disk directly; they mount volumes that are backed by a bound PVC (or other volume types). This document explains how PVs and PVCs work, how they relate to StorageClass and dynamic provisioning, and how Deployments, StatefulSets, and DaemonSets interact with Pods and storage.


1. Core objects: PV, PVC, StorageClass

ObjectWhat it isWho creates it
PersistentVolume (PV)A piece of cluster storage (NFS share, cloud disk, CSI volume, etc.) with capacity, access modes, and reclaim policy.Admin (static) or dynamic provisioner (via StorageClass).
PersistentVolumeClaim (PVC)A request for storage: size, access mode, optionally StorageClass. Like a Pod “claiming” CPU/RAM, but for disk.User / workload YAML.
StorageClassDefines how storage is provisioned (provisioner, parameters, default class).Cluster admin.

Relationship:

Pod
  └─ volumeMounts → volume (name: data)
                        └─ persistentVolumeClaim:
                              claimName: my-pvc

PVC (my-pvc)  --binds-->  PV (actual disk / CSI volume)
  • The Pod references a volume of type persistentVolumeClaim with claimName.
  • The PVC binds to exactly one PV that satisfies its spec (size, access mode, StorageClass).
  • The kubelet on the node mounts the volume into the Pod’s containers at volumeMounts.mountPath.

2. Static vs dynamic provisioning

Static provisioning

  1. Admin creates a PV manually (points to an existing NFS export, EBS volume, etc.).
  2. User creates a PVC that matches the PV’s capacity, access mode, and (if set) StorageClass.
  3. Binder controller binds PVC → PV (one-to-one).

Dynamic provisioning

  1. User creates a PVC with storageClassName: fast-ssd (or uses default StorageClass).
  2. Provisioner (e.g. EBS CSI, NFS subprovisioner) creates a PV automatically and binds the PVC to it.
  3. The PV often has a generated name and may be deleted when the PVC is deleted (depending on reclaim policy and StorageClass reclaimPolicy).

Takeaway: Pods always consume storage through PVC (or inline volume types). They do not reference PV names directly in normal usage.


3. Binding lifecycle (simplified)

  1. Pending: PVC created; no matching PV yet (or provisioner still creating volume).
  2. Bound: PVC is linked to a PV; Pod can mount it once scheduled to a node that can attach the volume (for block volumes, node affinity matters).
  3. Released / Lost / Terminated: After Pod/PVC deletion, behavior depends on reclaim policy on the PV:
    • Retain: PV remains; data kept; admin must clean up.
    • Delete: PV and underlying volume removed (common with dynamic cloud disks).
    • Recycle (deprecated): wipe and make PV available again.

4. Access modes (how many nodes can mount)

Access modeMeaning (typical)
ReadWriteOnce (RWO)Single node can mount read-write. Most block volumes (EBS, GCE PD per node).
ReadOnlyMany (ROX)Many nodes read-only.
ReadWriteMany (RWX)Many nodes read-write (NFS, some file shares).
ReadWriteOncePodSingle Pod on a single node (K8s 1.22+), stricter than RWO for some volumes.

Pods and scheduling: For RWO block storage, all Pods that use the same PVC must be able to run on the same node (or you use one Pod). That is why Deployments with RWO often use one replica or you use ReadWriteMany / shared storage.


5. How a Pod uses a PVC (interaction)

  1. Pod spec declares a volumes entry:
volumes:
  - name: data
    persistentVolumeClaim:
      claimName: my-pvc
  1. Container mounts it:
volumeMounts:
  - name: data
    mountPath: /data
  1. kubelet (on the node) asks the attach/detach controller and CSI driver (if applicable) to attach the volume to the node, then mounts it into the container filesystem namespace.

  2. Multiple containers in the same Pod share the same volume mount (same namespace).

Important: The PVC is namespaced; the PV is cluster-scoped. Pods only see PVCs in their namespace.


6. Deployment + PVC

Deployment manages ReplicaSets and stateless-ish Pods (same spec, interchangeable).

Pattern A: One shared PVC (multiple replicas) — usually wrong for RWO

  • If the PVC is RWO, only one node can attach the volume at a time.
  • Multiple replicas will conflict: second Pod may stay Pending or fail to mount.

Valid uses:

  • Single replica (replicas: 1) + RWO PVC (one writer).
  • RWX PVC (e.g. NFS) + multiple replicas (shared read-write — mind file locking and app design).

Pattern B: No PVC in Deployment template — use emptyDir or config

  • Stateless apps often use emptyDir for scratch, or ConfigMap/Secret mounts, not PVs.

Pattern C: Each Pod gets its own PVC — not a plain Deployment

  • A Deployment reuses the same Pod template for every replica; you cannot give each replica a different claimName without StatefulSet (or Operators / sidecar patterns).

Summary: Deployment + PVC is natural for one replica or RWX shared storage. For one PVC per Pod, use StatefulSet.


7. StatefulSet + PVC

StatefulSet gives stable identity (app-0, app-1, …) and ordered rollout/scale.

You define volumeClaimTemplates in the StatefulSet:

volumeClaimTemplates:
  - metadata:
      name: data
    spec:
      accessModes: ["ReadWriteOnce"]
      resources:
        requests:
          storage: 10Gi
      storageClassName: standard

Kubernetes creates one PVC per Pod with predictable names:

  • data-app-0, data-app-1, … (prefix + StatefulSet name + ordinal).

Each Pod’s volume references its PVC, so each replica gets its own disk (RWO safe).

Interaction:

StatefulSet
  ├─ Pod app-0 → PVC data-app-0 → PV (disk 0)
  ├─ Pod app-1 → PVC data-app-1 → PV (disk 1)
  └─ ...

Headless Service is often used for stable DNS (app-0.app.default.svc.cluster.local). Storage is per identity, ideal for databases, Kafka, etc.


8. DaemonSet + PVC

DaemonSet runs one Pod per (eligible) node (e.g. log collectors, monitoring agents).

Typical storage

  • Often hostPath, emptyDir, or local PV for node-local data.
  • PVC per DaemonSet Pod: each Pod could use a local or node-specific PV, but dynamic PVC per node is not as smooth as StatefulSet’s volumeClaimTemplates.

Caveats

  • If you mount one RWO PVC in a DaemonSet, only one node can attach that volume — invalid for “one Pod per node” across the cluster.
  • For local disks, patterns include Local PersistentVolume + one PV per node + DaemonSet Pod using a node-bound claim (advanced), or hostPath without PVC.

Summary: DaemonSet + PVC is uncommon for shared RWO volumes; prefer hostPath/local or one PVC per node with careful PV topology, or RWX if truly shared.


9. Comparison table: workload vs storage pattern

WorkloadTypical storage needPVC pattern
DeploymentStateless, scale outUsually no PV; or 1 replica + RWO, or RWX for shared data.
StatefulSetStable identity, own data per replicavolumeClaimTemplates → one PVC/PV per Pod ordinal.
DaemonSetNode-local or cluster-wide agentshostPath / local PV / or no PVC; avoid one RWO PVC for all nodes.

10. End-to-end flow (StatefulSet example)

  1. User applies StatefulSet with volumeClaimTemplates.
  2. For each ordinal, control plane creates a PVC; provisioner creates PV (dynamic) or binds to existing PV.
  3. Pod app-0 is scheduled; kubelet attaches volume to node; mounts /data.
  4. Scale up: app-1 gets new PVC + new PV.
  5. Scale down: Pod may be deleted; PVCs often retained (depending on policy) so data survives for scale-up later.

11. Quick checklist

  • Choose access mode (RWO vs RWX) to match replica count and scheduling.
  • Use StorageClass for portable dynamic provisioning.
  • Prefer StatefulSet + volumeClaimTemplates for one disk per replica.
  • Avoid multiple Deployment replicas on a single RWO PVC unless they share one node (usually not what you want).
  • Understand reclaim policy before deleting PVCs (data loss vs retain).

Summary

  • PV = actual storage resource; PVC = Pod’s claim on that storage.
  • Pods connect through volumes[].persistentVolumeClaim and volumeMounts.
  • Deployments work well with PVC only when replicas = 1 or storage is RWX.
  • StatefulSets are the standard way to get one PVC (and PV) per Pod with stable names.
  • DaemonSets usually use node-local paths or specialized local PV patterns, not one shared RWO PVC across all nodes.

This model keeps storage lifecycle (bind, retain, delete) separate from Pod lifecycle while giving workloads predictable data paths.

← All posts

Comments