The Container Storage Interface (CSI) was one of the best things to happen to storage on Kubernetes. It gave every storage vendor a single, standard way to plug devices into the cluster, so a StorageClass and a PersistentVolumeClaim behave the same whether the volume lives on a cloud disk, a SAN, or a software-defined pool.
But CSI is a connection specification with a basic set of volume lifecycle features, not a data platform. To expose anything past the basics, vendors ship their own plugins that extend the spec, so capabilities like snapshots and backup vary from one driver to the next and you inherit a complex support matrix. More importantly, the way CSI connects storage to pods is built for simple cases. It is fine for small clusters and pinned workloads, and it quietly strains under the operations that define a real production platform. Put plainly: CSI tells you a volume will be there. It does not tell you the volume will stay fast, resilient, or cheap to operate at scale.
How CSI Actually Connects Storage to Pods
A CSI driver exposes block volumes from external storage directly to worker nodes, and it does so in a one-to-one relationship. Every time a pod makes a storage claim, the driver sets up a dedicated connection for it, and each connection is established sequentially.
Bringing a volume up on a new host, or moving it, is a four-step cycle. Two steps stand up the new connection, and two tear down the old one:
- Map: an API call to the array creates access for the new host and maps the volume.
- Attach: the host discovers the mapped device through bus scans and builds the multipath device.
- Detach: multipath devices and block devices are torn down on the original host.
- Unmap: another array call removes access from the original host.
For one volume on a quiet cluster, this is invisible. The problem is arithmetic: a single rolling upgrade can multiply that cycle across thousands of volumes, and each step is an array event. The control plane queues those events serially, so platform operations slow down exactly when you need them to be fast.
Where the 1:1 Connection Model Breaks at Scale
The connection overhead turns into real pain during the operations platform teams run constantly:
- Maintenance windows and rolling upgrades. Draining and re-homing volumes node by node generates a flood of map, attach, detach, and unmap calls that the array has to absorb.
- Failure recovery. Restoring service means re-mapping and re-attaching volumes on healthy hosts, and that cycle sits directly in your recovery time.
- Boot storms and bursty traffic. A sudden wave of new pods, holiday e-commerce load or a fleet of LLM inference endpoints spinning up, means a new storage connection per pod. The host has to discover and mount each one individually, flooding the array with API requests.
- Live migrations. Moving running workloads between nodes triggers the full teardown-and-rebuild cycle for every affected volume.
- Hard host connection limits. A host can sustain only so many storage connections. Run out, and the only way to add more pods is to add more hosts purely for their connection budget, which wastes compute you did not need.
None of this is a CSI bug. The spec was designed for portable, standardized volume lifecycle, not for absorbing connection pressure across hundreds of thousands of volumes. Closing that gap is an architecture decision.
What It Takes to Move Past the Bottleneck
The fix is to stop tying each pod to its own array mapping. Instead of one-to-one connections, you want a storage layer that aggregates devices into pools and lets pods claim capacity from the pool, so the layer absorbs the connection pressure that individual CSI drivers cannot. With data and its replicas distributed across nodes, a node failure means a volume is simply served from the nearest replica rather than re-mapped from scratch, which collapses recovery time. That same layer is where the data services CSI never standardized, thin provisioning, snapshots, encryption, and disaster recovery, naturally belong.
There is a catch worth naming. The most common way to build this pooled layer is to run it on the worker nodes themselves, as pods that replicate data and run data services using the same CPU, memory, and network as your applications. That solves the connection problem but trades it for a different tax:
- Worker-node overhead. Replication and data services compete with your workloads on every node. You pay for storage twice: once in disks, once in stolen compute.
- Write amplification. In-cluster replication writes every block two or three times across the cluster network, raising the latency floor for write-heavy databases.
- Coupled scaling. When storage lives inside the compute cluster, you cannot scale capacity and compute independently.
The three ways teams answer this gap line up cleanly across the dimensions that actually decide a production platform:
| Dimension | Standard CSI (1:1 connections) | In-cluster pooled layer | Disaggregated NVMe (simplyblock) |
|---|---|---|---|
| Connection model | One array mapping per pod, set up and torn down sequentially | Pods claim from a pool that runs on the worker nodes | Pods claim logical volumes from a shared NVMe fabric |
| Behavior at scale | Array API saturation on upgrades, boot storms, and migrations | Absorbs the pressure, but on worker-node CPU and RAM | Absorbs the pressure off the worker nodes |
| Node-failure recovery | Re-map and re-attach cycle sits in the recovery path | Restart near a replica on another node | Volume stays served from the pool; placement is distributed |
| Data services | Vary by driver; mostly out of scope for the spec | Bundled, but running on application nodes | Thin provisioning, snapshots, encryption, and QoS in the storage layer |
Table 1: How the three storage approaches handle connection scaling, recovery, and data services.
Scaling stateful Kubernetes and watching upgrades or failover drag because of storage connection overhead? Talk to us before you trade a 1:1 bottleneck for a worker-node tax that is hard to unwind later. Talk to a storage architect
So the real choice is not “minimal CSI” versus “feature-rich overlay.” It is whether the pooled layer lives on your application nodes or off them.
How simplyblock Solves It Without the Overlay Tax
Simplyblock keeps the CSI-native developer experience, then supplies the pooled fabric from a disaggregated storage layer instead of from the worker nodes.
The architecture is the point. Simplyblock pools NVMe devices into a shared, software-defined layer and serves logical volumes over NVMe/TCP (and NVMe/RoCE where the fabric supports it). Pods consume volumes through the standard CSI driver, but each pod claims a logical volume from the pool rather than triggering a fresh one-to-one array mapping. That removes the map, attach, detach, and unmap storm during upgrades, migrations, and recovery, and it sidesteps per-host connection limits, because the connection terminates at the simplyblock data plane, not at a finite array port budget.
Because data placement and replication are distributed across the storage layer, a lost node does not start a re-mapping cycle. The volume stays reachable from another copy, so recovery is fast and predictable. And because the layer is disaggregated rather than co-resident with your pods, you get the pooled behavior without the worker-node penalties:
- Connection pressure absorbed off your application nodes, so upgrades and boot storms do not saturate an array or burn host connection slots.
- Predictable, low latency with per-volume QoS, so a noisy neighbor cannot starve a latency-sensitive PostgreSQL primary. NVMe-first design keeps the latency floor low for write-heavy workloads.
- Cluster-wide thin provisioning, snapshots, clones, and encryption as platform features rather than per-array integration projects.
- Independent scaling of compute and storage, because storage is not stealing CPU and RAM from your workloads.
The result is the developer experience CSI promised, the connection-scaling behavior CSI never aimed for, and the data services it left out, without paying for them in worker-node compute or amplified writes. If you are choosing a storage standard for stateful workloads, see simplyblock for Kubernetes storage and the broader comparison of the best Kubernetes storage in 2026.
Questions and Answers
Why does standard CSI struggle at scale?
CSI connects storage to pods in a one-to-one relationship, and each connection is set up and torn down through a sequential map, attach, detach, and unmap cycle. For a few volumes this is invisible, but a single rolling upgrade can multiply that cycle across thousands of volumes, and the control plane queues the resulting array events serially. The overhead shows up as slow maintenance windows, slow recovery, and API saturation on the storage array, plus hard per-host connection limits that force you to add hosts just to gain more connections.
What happens to CSI storage connections during node failure or live migration?
Both trigger the full teardown-and-rebuild cycle. A failed or drained node requires re-mapping and re-attaching every affected volume on a healthy host, and that cycle sits directly inside your recovery time. Failover with plain CSI also tends to depend on custom scripting. A pooled storage layer avoids this by keeping replicas distributed across nodes, so a volume is served from the nearest copy instead of re-mapped from scratch.
How does a pooled storage layer avoid the connection bottleneck?
Instead of mapping each pod one-to-one to an array volume, a pooled layer aggregates storage devices into shared pools and lets pods claim capacity from the pool. The layer absorbs the connection pressure that individual CSI drivers cannot, parallelizes orchestration instead of queueing it serially, and keeps volumes immediately available through a software-defined fabric. That removes array API saturation during upgrades, boot storms, and migrations.
How does simplyblock go beyond CSI without taxing worker nodes?
Simplyblock stays CSI-native and supplies the pooled fabric from a disaggregated NVMe layer served over NVMe/TCP and NVMe/RoCE. Each pod claims a logical volume from the pool rather than a fresh array mapping, so the map, attach, detach, and unmap storm disappears and per-host connection limits stop being a ceiling. Replication, thin provisioning, snapshots, clones, encryption, and per-volume QoS run in the storage layer instead of on your worker nodes, so compute and storage scale independently and application nodes are not taxed by the data path.