
Table of Contents
By Khimananda Oli | Last reviewed: August 2026
If you are managing stateful workloads on Kubernetes, understanding how storage is attached and mounted is non-negotiable. CSI Drivers Explained provides the technical depth needed to move beyond basic PersistentVolumeClaims and troubleshoot real storage failures in production. Before the Container Storage Interface (CSI) became the standard in 2018, storage vendors had to embed their code directly into the Kubernetes core binary, creating a fragile coupling that slowed innovation and made upgrades risky. Today, CSI decouples storage logic from the orchestrator, allowing vendors to ship updates independently and enabling platform engineers to manage storage with the same declarative rigor as compute.
What is the Container Storage Interface and why does it matter?
The Container Storage Interface (CSI) is an industry-standard specification that defines how storage systems expose volumes to container orchestration platforms. In practice, this means your Kubernetes cluster communicates with a storage backend—whether AWS EBS, Ceph, or Longhorn—through a well-defined gRPC API rather than proprietary in-tree code. For teams running Kubernetes Persistent Volumes and Storage, CSI is the mechanism that makes dynamic provisioning possible without recompiling kubelet.
This decoupling matters because it shifts storage reliability from a Kubernetes release cycle problem to a vendor maintenance problem. When I audit clusters for SOC 2 compliance, I look for CSI drivers that are actively maintained, signed, and version-pinned. In-tree volume plugins like kubernetes.io/aws-ebs are deprecated; if you are still using them in 2026, you are accumulating technical debt that will block future cluster upgrades. The CSI model also enables advanced features like volume snapshots, cloning, and topology-aware scheduling that were impossible or inconsistent under the old FlexVolume system.
How do CSI controller and node plugins handle volume lifecycle?
A common mistake when learning CSI is treating the driver as a single monolithic process. In reality, every CSI driver consists of two distinct components with different deployment models and responsibilities. Understanding this split is critical for debugging mount failures and capacity issues.
Controller Plugin responsibilities
The Controller plugin typically runs as a Deployment with one or more replicas for high availability. It handles cluster-wide operations that do not require access to a specific node's filesystem:
- CreateVolume / DeleteVolume: Provisions or destroys storage assets on the backend (e.g., creates an EBS volume or Ceph RBD image).
- ControllerPublishVolume / ControllerUnpublishVolume: Attaches or detaches the volume to/from a specific node at the infrastructure level (e.g., attaches an EBS volume to an EC2 instance via AWS API).
- CreateSnapshot / DeleteSnapshot: Manages point-in-time snapshots for backup or cloning workflows.
- ControllerExpandVolume: Resizes the underlying storage asset before the node performs filesystem expansion.
Node Plugin responsibilities
The Node plugin runs as a DaemonSet on every node (or a subset via node selectors). It handles filesystem-level operations that require direct host access:
- NodeStageVolume: Formats the device (if needed) and mounts it to a global staging path on the node. This step is idempotent and shared across pods.
- NodePublishVolume: Bind-mounts the staged volume to the pod-specific target path inside the container's mount namespace.
- NodeExpandVolume: Expands the filesystem after the controller has resized the underlying block device.
This two-phase mount pattern (Stage then Publish) exists to prevent race conditions and duplicate format operations when multiple pods on the same node share a ReadWriteMany volume. If you see a pod stuck in ContainerCreating with a mount timeout, check both the controller logs (for attach/provision errors) and the node plugin logs (for format/mount errors). My guide on debugging CrashLoopBackOff in Kubernetes covers similar diagnostic patterns for storage-related pod failures.
How do you configure dynamic provisioning with StorageClasses?
Dynamic provisioning is where CSI delivers its primary operational value. Instead of pre-creating volumes and manually binding them, you define a StorageClass that tells Kubernetes which CSI driver to use and what parameters to pass during provisioning. Here is a production-grade example for AWS EBS:
<!-- storageclass-gp3.yaml -->
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: ebs-gp3-encrypted
provisioner: ebs.csi.aws.com
parameters:
type: gp3
encrypted: "true"
kmsKeyId: "arn:aws:kms:us-east-1:123456789012:key/mrk-abc123"
tagSpecification_1: "Environment={{ .Values.env }}"
reclaimPolicy: Retain
allowVolumeExpansion: true
volumeBindingMode: WaitForFirstConsumer Three settings here deserve explicit attention based on incidents I have resolved in production:
- volumeBindingMode: WaitForFirstConsumer — Always use this for cloud block storage. The default
Immediatebinds the PV as soon as the PVC is created, which can place the volume in an availability zone that doesn't match your pod's scheduled node.WaitForFirstConsumerdelays binding until a pod is scheduled, ensuring topology alignment. - reclaimPolicy: Retain — For stateful databases, never use
Deletein production unless you have automated backups verified. Accidental PVC deletion withDeletepolicy permanently destroys data. I cover safe backup strategies in PostgreSQL backup and restore with pg_dump. - allowVolumeExpansion: true — Enables online resizing without pod restarts. Without this flag, users must delete and recreate PVCs to grow storage, causing unnecessary downtime.
After applying the StorageClass, create a PVC referencing it. The external-provisioner sidecar watches for new PVCs, calls CreateVolume on the CSI controller, and binds the resulting PV automatically. Monitor provisioning latency with Prometheus metrics exposed by the CSI driver; p99 provision times above 30 seconds often indicate backend throttling or API rate limits.
Which CSI drivers should you choose for production in 2026?
Selecting a CSI driver is an architectural decision with long-term operational consequences. Below is a comparison of widely-used drivers based on real deployment experience across AWS, on-prem, and hybrid environments.
| Driver | Best For | Key Strengths | Operational Risks | SOC 2 / Compliance Notes |
|---|---|---|---|---|
| AWS EBS CSI | Pure AWS workloads | Native integration, gp3/io2 support, snapshot APIs | AZ-bound, no multi-attach for RWX | KMS encryption enforced, CloudTrail audit logs |
| Ceph RBD (ceph-csi) | On-prem / hybrid block storage | RWX block, snapshots, clones, mature ecosystem | Complex to operate, requires dedicated OSD nodes | Self-hosted = full data residency control |
| Longhorn | Lightweight distributed block storage | Built-in UI, replica management, backup to S3 | Higher write amplification, smaller community | Encryption at rest supported, audit logging limited |
| NFS-Ganesha / nfs-subdir-external-provisioner | Shared file storage (RWX) | Simple setup, POSIX compliant | No snapshots, performance degrades at scale | Not suitable for PII/compliance-sensitive data |
| Portworx Enterprise | Mission-critical multi-cloud stateful apps | Replication, disaster recovery, encryption, STORK scheduler | Licensing cost, vendor lock-in | FIPS mode, comprehensive audit trails, SOC 2 Type II certified |
For Nepal-based teams or organizations with strict data residency requirements, self-managed options like Ceph or Longhorn provide sovereignty that cloud-native drivers cannot. However, the operational overhead is significant. If your team lacks dedicated storage engineers, consider managed services or enterprise-supported distributions. I have seen too many startups burn engineering cycles maintaining Ceph clusters when they should be shipping product features. Match your storage choice to your team's actual operational capacity, not theoretical best practices.
Implementing CSI Drivers Explained for reliable stateful workloads
Getting CSI right in production requires more than installing a Helm chart. Treat your storage layer with the same discipline as your application code. Pin driver versions explicitly in your GitOps repository; never rely on latest tags. Enable and test volume snapshots as part of your backup strategy—snapshots are not backups until you verify restoration. Monitor CSI-specific metrics (csi_operations_seconds, csi_storage_capacity) alongside application SLOs. Finally, document your storage topology constraints so developers understand why a pod might pend in one AZ but schedule in another.
If you are designing storage for compliance-sensitive workloads or need help evaluating CSI drivers for your specific infrastructure, reach out to discuss your architecture. Storage mistakes are expensive and often irreversible; getting the foundation right early saves months of migration pain later.