5.5 Container Storage Interface (CSI) Architecture & Drivers
Key Takeaways
- The Container Storage Interface (CSI) replaces legacy in-tree volume plugins with an out-of-tree, gRPC-based standard that decouples storage vendor drivers from core Kubernetes release cycles.
- CSI architecture splits into Control Plane Controller Sidecars (csi-provisioner, csi-attacher, csi-resizer, csi-snapshotter, livenessprobe) and a Node Plugin DaemonSet.
- The CSI Node Plugin executes a two-phase mounting process: NodeStageVolume formats and mounts the volume to a global node staging directory, and NodePublishVolume bind-mounts it into the Pod container directory.
- CSIDriver and CSINode API objects register storage driver capabilities (fsGroupPolicy, attachRequired) and track node-specific topology and volume attachment limits.
- VolumeSnapshots enable point-in-time volume backups via VolumeSnapshotClass, VolumeSnapshot, and VolumeSnapshotContent resources, restorable into new PVCs via spec.dataSource.
5.5 Container Storage Interface (CSI) Architecture & Drivers
In early Kubernetes releases, all storage volume plugins (including AWS EBS, GCE Persistent Disk, Azure Disk, Cinder, Ceph, and GlusterFS) were in-tree. This meant that storage vendor driver code was compiled directly into the core Kubernetes binaries—kube-apiserver, kube-controller-manager, and kubelet. This monolithic architecture introduced severe operational liabilities:
- Release Coupling: A bug fix or feature enhancement in a third-party storage driver required upgrading the entire Kubernetes cluster.
- Security & Stability Risks: Vendor code executed with full cluster-level and host root privileges inside
kubeletandkube-controller-manager. - Code Bloat: Core Kubernetes maintenance was weighed down by dozens of proprietary storage SDKs.
To solve these challenges, the Kubernetes community co-developed the Container Storage Interface (CSI)—an industry-standard specification that establishes an out-of-tree, modular storage interface. Under CSI, storage plugins run as standard containerized workloads communicating with Kubernetes via gRPC over UNIX domain sockets.
1. The CSI Architectural Split: Controller vs. Node Plugin
A production CSI driver deployment is decoupled into two distinct operational planes:
+-----------------------------------------------------------------------------------------+
| CSI CONTROLLER PLUGIN (CLUSTER SCOPE) |
| Deployed as a Deployment / StatefulSet in kube-system with leader election |
| |
| +--------------------+ +--------------------+ +------------------+ +-------------+ |
| | csi-provisioner | | csi-attacher | | csi-resizer | |csi-snapshot | |
| | Watches PVCs -> | | Watches | | Watches PVC | |Watches Snap | |
| | CreateVolume / | | VolumeAttachment | | Expansion -> | |CreateSnap / | |
| | DeleteVolume | | -> Attach/Detach | | ExpandVolume | |DeleteSnap | |
| +---------+----------+ +---------+----------+ +--------+---------+ +------+------+ |
| | | | | |
| +-----------------------+----------------------+-------------------+ |
| | gRPC over UNIX domain socket |
| v |
| +--------------------------+ |
| | Vendor CSI Controller | |
| +-------------+------------+ |
+-------------------------------------|---------------------------------------------------+
| Cloud Storage API (AWS / GCP / Ceph)
+-------------------------------------|---------------------------------------------------+
| v Attaches physical disk to node VM |
| CSI NODE PLUGIN (NODE SCOPE) |
| Deployed as a DaemonSet on every worker node (Privileged SecurityContext) |
| |
| +--------------------+ gRPC +--------------------------+ |
| | kubelet | <--------> | Vendor CSI Node Plugin | |
| | Directs Volume | | - NodeStageVolume | |
| | Mount Operations | | - NodePublishVolume | |
| +--------------------+ +------------+-------------+ |
| | Formats & Bind-Mounts |
| v |
| +--------------------------+ |
| | Host Filesystem & PodDir | |
| +--------------------------+ |
+-----------------------------------------------------------------------------------------+
1. Control Plane Controller Sidecars
Maintained by the CNCF Kubernetes Storage SIG, these helper sidecars run alongside the vendor driver container:
csi-provisioner: WatchesPersistentVolumeClaimobjects. CallsCreateVolumeandDeleteVolumeon the storage provider.csi-attacher: WatchesVolumeAttachmentAPI objects created by Kubernetes. CallsControllerPublishVolumeandControllerUnpublishVolumeto physically attach/detach cloud disks to/from worker node virtual machines.csi-resizer: Watches PVC storage request increases. CallsControllerExpandVolumeto resize underlying cloud block storage.csi-snapshotter: WatchesVolumeSnapshotCRDs. CallsCreateSnapshotandDeleteSnapshot.livenessprobe: Monitors the health of the CSI plugin and exposes standard/healthzendpoints for Kubernetes probes.
2. CSI Node Plugin (DaemonSet)
Runs directly on each worker node with privileged: true and bidirectional mount propagation. The node's kubelet directly invokes the local node plugin over a UNIX domain socket (e.g., /var/lib/kubelet/plugins/ebs.csi.aws.com/csi.sock).
2. Two-Phase Node Mounting: NodeStageVolume vs. NodePublishVolume
When a scheduled Pod requires a persistent volume, the local kubelet orchestrates a two-phase mounting protocol via the CSI Node Plugin:
[ Attached Block Device on Node: /dev/xvdf ]
|
v
+-------------------------------------------------------------+
| STEP 1: NodeStageVolume |
| - Formats raw block device with ext4/xfs (if unformatted) |
| - Mounts device to global node staging directory: |
| /var/lib/kubelet/plugins/kubernetes.io/csi/pv-name/globalmount
+-------------------------------------------------------------+
|
v
+-------------------------------------------------------------+
| STEP 2: NodePublishVolume |
| - Executes a Linux bind-mount from global staging directory |
| into the target container's volume directory: |
| /var/lib/kubelet/pods/<pod-uid>/volumes/kubernetes.io~csi/|
+-------------------------------------------------------------+
Mounting and Teardown Sequences Compared:
| Operational Phase | gRPC Method | Technical Action |
|---|---|---|
| Phase 1: Stage | NodeStageVolume | Formats raw block device with specified filesystem (ext4, xfs) and mounts it to a global staging path on the node. Executed once per node for a given volume. |
| Phase 2: Publish | NodePublishVolume | Bind-mounts the staged filesystem into the specific Pod's volume directory. Executed for every Pod referencing the volume. |
| Phase 3: Unpublish | NodeUnpublishVolume | Unmounts the bind-mount from the Pod directory when the Pod terminates. |
| Phase 4: Unstage | NodeUnstageVolume | Unmounts the global node staging mount when no more pods on that node consume the volume. |
3. Kubernetes CSI API Objects: CSIDriver, CSINode & VolumeAttachment
Kubernetes introduces dedicated API resources to register drivers and monitor attachment state:
1. CSIDriver (Driver Capabilities)
A cluster-scoped object that informs Kubernetes how to interact with the CSI plugin:
apiVersion: storage.k8s.io/v1
kind: CSIDriver
metadata:
name: ebs.csi.aws.com
spec:
attachRequired: true
podInfoOnMount: false
volumeLifecycleModes:
- Persistent
fsGroupPolicy: File
2. CSINode (Node-Specific Driver Registration)
Created automatically for every worker node to record the node's storage identity and volume topology:
apiVersion: storage.k8s.io/v1
kind: CSINode
metadata:
name: worker-node-01
spec:
drivers:
- name: ebs.csi.aws.com
nodeID: i-0a1b2c3d4e5f6g7h8
topologyKeys:
- topology.ebs.csi.aws.com/zone
allocatable:
count: 28
3. VolumeAttachment (Attachment Lifecycle Debugging)
Represents the intent to attach a PV to a specific node. When a Pod is scheduled, the attachdetach-controller creates a VolumeAttachment object, which csi-attacher processes:
# Inspect active volume attachments across the cluster
kubectl get volumeattachments
# Describe attachment to diagnose why a volume is failing to attach to a node
kubectl describe volumeattachment csi-9a8b7c6d5e4f3a2b1
4. VolumeSnapshot Architecture & Restoration Workflows
Kubernetes provides a standardized Custom Resource Definition (CRD) framework (snapshot.storage.k8s.io/v1) to capture point-in-time copies of storage volumes.
+-----------------------------------------------------------------------------------------+
| VOLUMESNAPSHOT ARCHITECTURE |
| |
| [CLUSTER SCOPE] |
| +-------------------------------------+ +-----------------------------------------+ |
| | VolumeSnapshotClass | | VolumeSnapshotContent | |
| | - driver: ebs.csi.aws.com | | - snapshotHandle: snap-0123456789abcdef| |
| | - deletionPolicy: Delete / Retain | | - volumeSnapshotRef: prod/db-snap | |
| +------------------+------------------+ +--------------------+--------------------+ |
| | | (Bound 1-to-1) |
|=====================|===========================================|=======================|
| [NAMESPACE SCOPE] v v |
| +--------------------------------------------------------------+ |
| | VolumeSnapshot (e.g., db-snapshot) |
| | - spec.source.persistentVolumeClaimName: production-db-pvc |
| | - status.readyToUse: true |
| +--------------------------------------------------------------+ |
+-----------------------------------------------------------------------------------------+
Declarative Snapshot Manifests
1. Define VolumeSnapshotClass
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshotClass
metadata:
name: ebs-snapshot-class
driver: ebs.csi.aws.com
deletionPolicy: Delete
2. Create VolumeSnapshot from Existing PVC
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
name: postgres-backup-snapshot
namespace: production
spec:
volumeSnapshotClassName: ebs-snapshot-class
source:
persistentVolumeClaimName: postgres-data-pvc
3. Restore Snapshot into a New PVC via spec.dataSource
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: postgres-restored-pvc
namespace: production
spec:
accessModes:
- ReadWriteOnce
storageClassName: high-performance-ebs
resources:
requests:
storage: 50Gi
dataSource:
name: postgres-backup-snapshot
kind: VolumeSnapshot
apiGroup: snapshot.storage.k8s.io
5. CSI Troubleshooting & Diagnostic Playbook
# 1. Check health of CSI driver pods in kube-system
kubectl get pods -n kube-system -l app.kubernetes.io/name=aws-ebs-csi-driver
# 2. Inspect logs of csi-attacher sidecar when pods hang in ContainerCreating
kubectl logs -n kube-system deployment/ebs-csi-controller -c csi-attacher
# 3. Inspect logs of csi-provisioner sidecar when PVC stays Pending
kubectl logs -n kube-system deployment/ebs-csi-controller -c csi-provisioner
# 4. Check CSINode registration on worker nodes
kubectl get csinodes -o wide
# 5. Verify snapshot creation status
kubectl get volumesnapshot -n production
During the CSI volume mounting workflow on a worker node, what is the specific technical distinction between the NodeStageVolume and NodePublishVolume gRPC operations?
An administrator needs to restore a 100Gi production database from a point-in-time VolumeSnapshot named db-snap-2026 into a new PVC named db-restore-pvc. How must the new PVC manifest reference the snapshot?
Which CSI control plane sidecar container is exclusively responsible for watching VolumeAttachment API objects and executing ControllerPublishVolume calls against the cloud provider API to physically attach a disk to a worker node VM?