CSI Drivers
Summary
- The Container Storage Interface (CSI) is the standard plugin API that lets Kubernetes provision, attach, and mount storage from any vendor without vendor code in the core.
- Insight: Choosing a driver is really choosing an access pattern - single-writer block storage versus shared file storage - not just a cloud brand.
- Key Concepts: Block drivers (EBS, GCE PD, Azure Disk) are fast and single-node; file drivers (EFS, Filestore, Azure Files) are slower but ReadWriteMany.
- When to Use: Any dynamic storage on a managed cluster; the cloud-native driver is almost always the right default.
- Limitations: Block volumes are zonal and single-writer; shared filesystems trade latency and consistency for multi-node access.
Recipe
Install the driver (managed clusters ship one), define a StorageClass per tier, and let PVCs provision volumes dynamically.
# EKS: enable the managed EBS CSI driver add-on
eksctl create addon --name aws-ebs-csi-driver --cluster my-cluster
kubectl get pods -n kube-system -l app.kubernetes.io/name=aws-ebs-csi-driverThen expose a small, named menu of StorageClasses and point every PVC at the right one.
Working Example
A block class for databases and a shared-file class for multi-writer workloads on AWS.
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: block-fast
provisioner: ebs.csi.aws.com
parameters:
type: gp3
iops: "6000"
throughput: "250"
encrypted: "true"
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true
reclaimPolicy: Delete
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: shared-files
provisioner: efs.csi.aws.com
parameters:
provisioningMode: efs-ap
fileSystemId: fs-0123456789abcdef0
directoryPerms: "700"
mountOptions:
- tls
reclaimPolicy: RetainThe block class gives each PVC its own encrypted gp3 disk in the Pod's zone.
The EFS class provisions access points on a shared filesystem, so many Pods across zones mount the same data ReadWriteMany.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: uploads
spec:
storageClassName: shared-files
accessModes:
- ReadWriteMany
resources:
requests:
storage: 50GiDeep Dive
How a CSI driver is structured
A CSI driver runs as two logical pieces. A controller Deployment handles cluster-wide operations - create, delete, attach, snapshot - through sidecars like external-provisioner and external-attacher.
A node DaemonSet runs on every node and performs the actual mount into the Pod via NodePublishVolume.
The kubelet talks to the node plugin over a unix socket registered through the kubelet plugin registration mechanism.
Block versus file, per cloud
Block storage attaches one disk to one node. AWS EBS, GCP Persistent Disk, and Azure Disk are all zonal, single-writer, and low-latency - ideal for databases.
File storage is a network share. AWS EFS, GCP Filestore, and Azure Files are ReadWriteMany and cross-zone, at the cost of higher latency and NFS consistency semantics.
Object storage (S3, GCS) is not a filesystem; treat it as an app-level dependency, not a PV, unless you knowingly accept a FUSE CSI driver's quirks.
Choosing by access pattern
If exactly one Pod writes and you need speed, pick block with ReadWriteOncePod.
If many Pods must read and write the same files, you need a file driver with ReadWriteMany.
If many Pods only read static content, a file share or an init-container copy from object storage both work; pick by update frequency.
Encryption and topology
Set encrypted: "true" (or the cloud equivalent) at the StorageClass level so every volume is encrypted at rest by default.
Keep volumeBindingMode: WaitForFirstConsumer on all zonal block classes so the scheduler and provisioner agree on zone.
Gotchas
Marking ReadWriteMany on a block-backed class does nothing - the driver rejects multi-node mounts, and Pods that need shared access will fail to schedule together.
EFS throughput can bottleneck under many small-file workloads; use provisioned throughput or an access-point-per-app layout.
Forgetting WaitForFirstConsumer on EBS provisions the disk in a random zone, then the Pod cannot schedule there - a classic Pending deadlock.
The default StorageClass may be the slow generic tier; make performance-sensitive PVCs name their class explicitly.
CSI snapshots require the VolumeSnapshot CRDs and a snapshot controller, which are not always preinstalled on self-managed clusters.
Never point Kubernetes storage at the Docker Engine; on nodes the CSI node plugin plus containerd handle mounts, and dockershim no longer exists.
Alternatives
hostPath / local volumes: Bind a Pod to a physical node's disk for maximum performance, accepting that node loss means data loss. Suitable for scratch space and some tuned databases with app-level replication.
Ceph / Rook (software-defined storage): Run your own replicated block and file storage in-cluster for on-prem or hybrid, trading operational burden for portability.
Portworx / OpenEBS: Commercial and open-source storage layers that add replication, snapshots, and RWX on top of raw disks when the cloud driver is not enough.
Managed file service vs self-hosted NFS: Prefer EFS or Filestore over a hand-run NFS server; you avoid operating a single point of failure.
FAQs
Which driver should I use on EKS? The AWS EBS CSI driver for block and the EFS CSI driver for shared files; both are managed add-ons.
Can one cluster use multiple CSI drivers? Yes. Install several and expose one StorageClass per driver and tier.
Why does my ReadWriteMany PVC stay Pending? The chosen provisioner is block storage, which cannot satisfy RWX; switch to a file driver.
Do I need to install CSI drivers myself? On managed clusters usually not for the native driver; third-party drivers you install via Helm.
Is CSI required, or can I still use in-tree volumes? In-tree cloud plugins were removed; CSI is the supported path in current Kubernetes.
How do I get snapshots? Install the snapshot CRDs and controller, then create VolumeSnapshot objects against a snapshot-capable driver.
Related
- How Kubernetes Thinks About Storage
- K8s Storage Basics
- Stateful Data on Kubernetes
- Backup PVs
- Storage Architecture Best Practices
Stack versions: This page was written for Kubernetes 1.36.2, Docker Engine 29.6.1 (BuildKit default), containerd (CRI runtime on nodes), Helm 3, Compose v2, Argo CD (latest - verify at build), and Gateway API (GA - verify controller support at build).