Lesson 01 of 7 · Modules
CSI architecture
How any storage system plugs into Kubernetes through CSI: the controller and node plugins, the sidecars that talk to the API, and the exact sequence from PVC to a mounted volume, which is how you debug 'my volume won't attach'.
CSI: one interface, any storage
The Container Storage Interface lets any storage system (cloud disks, SAN arrays, Ceph, Longhorn, NFS) plug into Kubernetes without changing Kubernetes itself. A CSI driver has two parts:
| Part | Runs as | Does |
|---|---|---|
| Controller plugin | Deployment (1–2 replicas) | Create/delete volumes, attach/detach, snapshots, resize |
| Node plugin | DaemonSet (every node) | Format and mount volumes on the node, bind-mount into pods |
Small sidecar containers bridge the Kubernetes API and the driver: external-provisioner, external-attacher, external-resizer, external-snapshotter (controller side), and node-driver-registrar (node side).
CSI is like a universal plug adapter for storage. Kubernetes has one kind of socket; every storage company builds an adapter for it. The controller part is the warehouse manager who orders a new box and puts it on the right lorry. The node part is the person at each house who unpacks the box and puts it on the right shelf.
From PVC to mounted volume
1. PVC created (storageClassName: fast)
2. (WaitForFirstConsumer) pod scheduled to node w2
3. external-provisioner → driver CreateVolume → PV created, PVC Bound
4. external-attacher → ControllerPublishVolume → VolumeAttachment (volume ↔ w2)
5. kubelet on w2 → NodeStageVolume → format if new, mount to a global path
6. kubelet on w2 → NodePublishVolume → bind-mount into the pod's directory
7. Container starts with the volume at its mountPath
The pod events tell you where it stopped:
| Event | Failed step | Look at |
|---|---|---|
PVC Pending, waiting for first consumer |
Nothing (normal until a pod uses it) | — |
PVC ProvisioningFailed |
3 | Provisioner sidecar logs, driver credentials and quotas |
Pod FailedAttachVolume / Multi-Attach error |
4 | VolumeAttachments, attacher logs; is the volume still attached elsewhere? |
Pod FailedMount |
5–6 | Node plugin logs on that node; filesystem, permissions, iSCSI/NFS clients |
Topology: volumes live somewhere
Many volumes are only reachable from part of the cluster: an EBS volume from one availability zone, a local disk from one node. CSI drivers report topology, and volumeBindingMode: WaitForFirstConsumer lets the scheduler pick the node first, then provision the volume where the pod will run. Without it, a volume can be created in zone A for a pod that can only run in zone B.
Expansion
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast
provisioner: driver.example.com # your CSI driver's name
allowVolumeExpansion: true
volumeBindingMode: WaitForFirstConsumer
reclaimPolicy: Delete
$ kubectl patch pvc data -p '{"spec":{"resources":{"requests":{"storage":"20Gi"}}}}'
$ kubectl get pvc data -w
The resizer grows the volume; the node plugin grows the filesystem (online for most drivers). You can't shrink.
Try it: watch the steps (kind + a CSI driver)
kind's default standard class isn't CSI, so install one: the csi-driver-host-path example driver (for learning) or Longhorn (next lesson).
kubectl get csidrivers,csinodesbefore and after installing.- Create a PVC and a pod; watch
kubectl get pvc,volumeattachments -w, then read the pod's events in order. - Find the controller pod's sidecar containers (
kubectl get pod -n <ns> <csi-controller> -o jsonpath='{.spec.containers[*].name}') and read the provisioner logs for your PVC. - Expand the PVC (if the class allows it) and check the new size inside the pod with
df -h.
Going deeper: CSI in production
- Nodes have attach limits per driver (reported in CSINode): the scheduler respects them, so pods may go Pending on "full" nodes even with CPU to spare.
- Keep CSI drivers upgraded with Kubernetes; they're node-critical DaemonSets and controllers with their own compatibility matrices.
- After a node dies, RWO volumes may stay attached until the attach-detach controller force-detaches them (with a delay) or the node is marked out-of-service. Know your driver's behaviour before the first incident.
- Ephemeral CSI volumes and generic ephemeral volumes give pods per-pod scratch volumes from a StorageClass.
Recap
- CSI = controller plugin (create, attach, snapshot, resize) + node plugin (stage, publish), with sidecars bridging the API.
- PVC → provision → attach (VolumeAttachment) → stage → publish → running pod; events tell you which step failed.
- WaitForFirstConsumer respects topology; allowVolumeExpansion enables online growth.
This site is a public version of my personal engineering knowledge hub. It intentionally excludes confidential company information and internal operational details.