CSI Driver Architecture in Kubernetes: Controller and Node Plugins

CSI Driver Architecture in Kubernetes: Controller and Node Plugins

How Kubernetes talks to any storage system through one standard interface, why every driver is split into a controller part and a node part, and how a simple claim for storage becomes a real disk mounted inside a running container.

Imagine moving into a new apartment and asking the building manager for a storage locker. The manager does not build the locker personally. A back-office team allocates one somewhere in the building and records the number. Then, when you actually arrive, a porter on your floor walks you to the locker, unlocks it and makes sure you can use it from your own front door. Two teams, two different jobs: one works from the back office and knows the whole building, the other works on your floor and handles the last few steps. Kubernetes storage works almost exactly this way, and the standard that describes it is called the Container Storage Interface, or CSI.

This post teaches CSI architecture from the very beginning. You do not need to be a storage expert or to have written a driver. We start with the problem that CSI solved, then meet the standard itself, then open the two halves of every driver, the controller plugin and the node plugin, and follow a volume from request to running container and back. After that we cover topology, snapshots, failure handling, security, monitoring and common mistakes. Every new term is defined, compared with something from daily life, and used again in the next section.

1The Problem: Storage Code Inside Kubernetes Itself

Before CSI existed, every storage system had to be built into Kubernetes. That created a painful bottleneck.

Containers forget, storage remembers

A container’s own filesystem disappears when the container is replaced. That is fine for a stateless web server, but a database needs its data to survive restarts, rescheduling and node failures. The answer is a volume: a piece of storage that lives outside the container and can be attached to whichever node runs the Pod. Volumes can be network disks from a cloud, shared file systems, local drives, or storage appliances in a data centre.

The in-tree era

In the early years, the code that knew how to talk to each storage system was part of the main Kubernetes source code. These were called in-tree volume plugins, because they lived inside the Kubernetes code tree. Support for a cloud disk, a file protocol or an appliance meant a new chunk of code inside Kubernetes itself, built and released together with everything else.

Simple Analogy

Imagine a phone manufacturer that must build every possible charger plug directly into the phone body. Every new plug shape means redesigning and re-shipping the phone. A far better design is a standard socket, so that any charger maker can build a compatible cable without touching the phone.

Pain 1

Release lock-step

A storage vendor fixing a bug had to wait for the next Kubernetes release and then for clusters to upgrade, which could take months.

Pain 2

Core code bloat

Vendor-specific code inside the main project made it larger, harder to test and harder to secure.

Pain 3

Shared fate

A crash or vulnerability in one storage plugin could affect core components such as the kubelet, since they ran in the same process.

Pain 4

No level playing field

Only vendors with code in the main project were first-class. Everyone else had weaker, awkward options.

!
Common Misconception

CSI is not a single storage product, and it is not part of the Kubernetes code. It is a specification, a contract written down so that Kubernetes, and other orchestrators, can talk to any storage system the same way. Vendors and communities implement the contract in drivers.

2Storage Objects Refresher: Claims, Volumes and Classes

A short tour of the Kubernetes objects that drivers serve, so the rest reads easily.

The three everyday objects

Object

PersistentVolumeClaim

A request for storage written by an application owner: “I need ten gigabytes, readable and writable by one node.” It does not say how or where.

Object

PersistentVolume

The cluster’s record of one real piece of storage, with its size, access mode and the identifier the storage system uses for it.

Object

StorageClass

A menu entry created by the platform team: it names a driver and a set of options, such as disk type, replication level or encryption.

Simple Analogy

A claim is your request form at the building office. A StorageClass is the price list showing “small locker, large locker, climate-controlled locker.” A PersistentVolume is the actual locker with its number written in the building register.

Dynamic provisioning

In the old manual style, an administrator pre-created volumes and users claimed them. In dynamic provisioning, nobody pre-creates anything. When a claim names a StorageClass, the system asks the driver named in that class to create a fresh volume on demand, and then registers it as a PersistentVolume that binds to the claim. This is what makes self-service storage possible, and it is the main workflow CSI drivers support.

Reclaim policy

Every dynamically created volume carries a rule for what happens when its claim is deleted. Delete means the real storage is destroyed too. Retain means the PersistentVolume and its data are kept for an administrator to deal with. Choosing between them is a data-safety decision, not a technical detail, and we revisit it in the anti-patterns chapter.

Binding mode

A StorageClass also chooses when a volume is created. With immediate binding, the volume is created as soon as the claim appears. With wait-for-first-consumer binding, creation is postponed until a Pod that uses the claim has been scheduled, so the volume can be created in the right place. Chapter 11 explains why this matters.

i
Who Writes What

Application teams write claims and rarely care about drivers. Platform teams write StorageClasses and choose drivers. Driver authors implement the CSI contract. CSI keeps these three groups from needing to know each other’s details.

3What CSI Actually Is

A written contract between an orchestrator and a storage driver, spoken over a simple local channel.

A specification shared across systems

The Container Storage Interface is an open specification that describes a small set of operations a storage driver must offer: create a volume, delete a volume, attach it to a machine, mount it at a path, take a snapshot, and so on. It was designed together by several container orchestrators and storage vendors, so a driver written once can in principle serve more than one orchestrator. Kubernetes is the most prominent user.

The language of the contract: gRPC

The operations are defined as gRPC calls, a widely used way for programs to call functions in other programs over a connection. On a single node, the program that asks and the driver that answers talk through a local file-like endpoint called a Unix domain socket. There is no network involved for that conversation, only a socket file on disk, which keeps it fast and limits who can talk to the driver.

Simple Analogy

CSI is like a standard menu of requests a customer can make to a courier company, written in a common language. Any courier that honours the menu can be hired by any customer. The internal vans, routes and warehouses of each courier stay private.

Three services in one contract

The specification groups its operations into three named services. A driver offers some or all of them, depending on what it can do.

Service 1

Identity

“Who are you and what can you do?” Reports the driver’s name, version, whether it offers controller features, and whether it is healthy.

Service 2

Controller

Operations that act on the storage system as a whole, such as creating, deleting, attaching, detaching, snapshotting and expanding volumes.

Service 3

Node

Operations that act on one specific machine, such as preparing a volume on that machine and making it appear at a path for a Pod.

i
The Key Insight

The split between Controller and Node services is the heart of the architecture. Some storage work can be done from anywhere in the cluster, for example asking a cloud API to create a disk. Other work can only be done on the very machine where the Pod runs, for example mounting a disk into the filesystem. CSI gives each kind its own service, and each service runs in the place where it makes sense.

Optional capabilities

Not every driver can do everything. A simple network file system may never need an attach step. A local disk driver may not offer snapshots. Each driver therefore reports a list of capabilities through the Identity and Controller and Node services, and Kubernetes only calls the operations that the driver says it supports. This keeps the contract small for simple drivers and rich for advanced ones.

4Architecture Overview: Controller Plugin and Node Plugin

Two kinds of running programs, placed in two different spots of the cluster.

Two halves of one driver

A CSI driver is usually delivered as two deployments of the same driver software. The controller plugin runs a small number of copies somewhere in the cluster, serves the Identity and Controller services, and talks to the storage system’s management interface, often a cloud API. The node plugin runs one copy on every node that can use the storage, serves the Identity and Node services, and performs the machine-level work of preparing and mounting volumes.

Simple Analogy

The controller plugin is the back-office team with access to the building register. It allocates lockers and records ownership. The node plugin is the porter on each floor. The back office never visits your floor, and the porter never changes the register. Each is only responsible for their part of the job.

flowchart LR
  subgraph CP["Control plane side of the driver"]
    PR["external-provisioner"]
    AT["external-attacher"]
    SN["external-snapshotter"]
    RS["external-resizer"]
    CD["Driver: Identity and Controller services"]
    PR --> CD
    AT --> CD
    SN --> CD
    RS --> CD
  end
  CD --> ST[("Storage system API")]
  subgraph ND["Every node"]
    KL["Kubelet"]
    RG["node-driver-registrar"]
    NDD["Driver: Identity and Node services"]
    KL --> NDD
    RG --> KL
  end
  NDD --> ST
        
FIG 1 — The controller plugin works with the storage system as a whole, the node plugin works on each machine

Why not one program?

It would seem simpler to ship one program that does everything. But the two halves have very different needs. Controller work needs credentials for the storage system and does not need access to any node’s filesystem. Node work needs deep access to the node’s filesystem and devices and should not carry broad cloud credentials. Separating them follows the principle of least privilege, scales the right part in the right way, and lets each half be upgraded or restarted independently.

Benefits of the split

  • Credentials for the storage system live only in the controller part
  • The node part gets only the filesystem power it needs
  • Controller work is done once per cluster, node work once per node
  • Each half scales and fails independently

Costs of the split

  • More moving parts to deploy and monitor
  • Problems can hide at the hand-off between the two halves
  • Versions of the halves and the helper programs must stay compatible
i
One Image, Two Roles

Many drivers use a single container image for both halves and switch roles through settings or startup options. What matters conceptually is not the image count but the two roles, the places they run and the privileges each one holds.

5The Services and Their Operations in Detail

What each service can be asked to do, in plain language.

Identity service

The Identity service answers three questions. Plugin info returns the driver’s name and version. The name is important because it must match the provisioner name written in StorageClasses. Plugin capabilities tells callers whether the driver offers controller features and whether volumes can be reached only from some parts of the cluster. Probe reports whether the driver is ready to work, and is used by health checks.

Controller service

Create and delete volume

Creating allocates real storage of a given size and options and returns the driver’s own volume identifier. Deleting destroys it. Both must be safe to repeat, because callers retry after failures.

Publish and unpublish at controller level

Often called attach and detach. These make a volume available to a specific node from the storage side, for example by attaching a cloud disk to a virtual machine. They exist only for storage that needs this step.

Snapshots

Create, delete and list point-in-time copies of a volume. A new volume can later be created from a snapshot.

Expand volume

Make an existing volume larger on the storage side. The filesystem on it may need separate expansion on the node.

Capacity and validation

Report how much room remains in a pool, and check that a volume can be used in a requested way.

Node service

Stage and unstage volume

Prepare the volume once on a node: find the device, create a filesystem if the volume is new, and mount it at a shared staging path. Unstage reverses this when no Pod on the node uses the volume any more.

Publish and unpublish at node level

Make the volume appear at a specific path for a specific Pod, usually by a bind mount from the staging path. Unpublish removes it when that Pod goes away.

Volume statistics and node expansion

Report how much space and how many files are used on the volume, and grow the filesystem after the storage side has been enlarged.

Node information

Return the node’s identity as the storage system knows it, its limits on the number of volumes, and where it sits in the topology of the cluster.

ServiceRuns whereActs onTypical examples
IdentityBoth pluginsThe driver itselfName, capabilities, health
ControllerController pluginThe storage system as a wholeCreate, delete, attach, detach, snapshot, expand
NodeNode plugin on each nodeOne machine’s filesystem and devicesStage, publish, unpublish, unstage, stats
!
Two Meanings of Publish

The word publish appears in both the Controller and Node services, with different meanings. At controller level it means making the volume reachable by a node from the storage side. At node level it means making the volume appear inside a Pod’s directory. Mixing these up is a common source of confusion when reading logs.

6The Controller Plugin and Its Sidecars

The driver does not watch Kubernetes. A set of helper programs do that on its behalf.

The sidecar idea

The CSI driver itself knows nothing about Kubernetes objects. It only answers CSI calls. To connect Kubernetes to the driver, the Kubernetes storage community provides a set of generic helper programs called sidecars. Each one is a small controller that watches certain Kubernetes objects and translates changes into CSI calls to the driver, over a local socket shared in the same Pod. Driver authors reuse these helpers instead of writing Kubernetes logic themselves.

Simple Analogy

The driver is a specialist craftsman who speaks only the language of the standard menu. Each sidecar is a translator who reads the customer’s paperwork in Kubernetes language and turns it into menu requests for the craftsman. The craftsman never needs to learn the paperwork language.

Sidecar

external-provisioner

Watches claims that name a class using this driver. Calls create volume, then creates the PersistentVolume record. Also handles deletion according to the reclaim policy.

Sidecar

external-attacher

Watches VolumeAttachment objects and calls controller publish and unpublish so volumes are attached and detached from nodes.

Sidecar

external-snapshotter

Watches snapshot objects and calls snapshot operations, creating the matching records for the real snapshot.

Sidecar

external-resizer

Watches claims whose requested size grows and calls the expand operation on the storage side.

Sidecar

liveness probe helper

Checks the driver’s health by calling the probe operation and reports to Kubernetes health checks so unhealthy drivers get restarted.

Sidecar

health monitor and others

Optional helpers can watch volume health on the storage side and raise events, depending on driver and version support.

Informers and queues again

If you have read about how Kubernetes controllers work, these sidecars will feel familiar. Each one uses informers to watch objects, a work queue to process changes, and a reconcile step that calls the driver and writes results back. The same list-and-watch pattern, the same retries with back-off and the same level-based thinking apply. A sidecar that restarts simply re-lists and carries on.

High availability and leader election

The controller plugin is usually run with several replicas for availability. Only one replica of each sidecar should act at a time, otherwise two copies might create the same volume twice. The sidecars therefore use leader election, so that one copy is active and the others stand by. Because leader election is per sidecar, the active provisioner and the active attacher may in principle be in different replicas.

flowchart TD
  K[("Kubernetes API objects")] -- "watch" --> S1["Sidecar: provisioner"]
  K -- "watch" --> S2["Sidecar: attacher"]
  S1 -- "CSI call over local socket" --> D["Driver container: Controller service"]
  S2 -- "CSI call over local socket" --> D
  D -- "management API call" --> X[("Storage system")]
  D -- "result" --> S1
  S1 -- "write PV and status" --> K
        
FIG 2 — A sidecar watches Kubernetes objects, calls the driver locally, and writes the result back
i
Where It Runs

The controller plugin is an ordinary workload, often a Deployment in a system namespace. It does not need to run on special nodes unless the storage system’s management interface is only reachable from certain networks, which is a real consideration for on-premises storage.

7The Node Plugin and the Kubelet

The part that touches the machine: devices, filesystems and mount points.

Deployed on every node

The node plugin runs as a DaemonSet, which means Kubernetes keeps exactly one copy on each eligible node. Because it must create mounts that are visible to the kubelet and to containers, it needs special privileges and special access to the node: it normally runs as a privileged container and shares parts of the node’s directory tree with the host.

The kubelet is the caller

On the node side the caller is not a sidecar but the kubelet, the agent that starts Pods on that node. When a Pod needs a CSI volume, the kubelet calls the node plugin’s stage and publish operations over a Unix socket that the plugin has created in a known folder under the kubelet’s directory.

Registration

How does the kubelet find the driver’s socket? A helper sidecar called the node-driver-registrar runs beside the node plugin. It announces the driver to the kubelet through a registration socket that the kubelet watches. The kubelet then calls the driver’s node information operation, learns the node’s identity and limits in the storage system’s language, and records the driver in a per-node Kubernetes object. From that point the kubelet knows the driver is available on this node.

1

The node plugin starts and opens its socket

The driver container creates its CSI socket in a plugin folder under the kubelet’s directory.

2

The registrar announces the driver

It places a registration socket in the folder that the kubelet watches, naming the driver and where its socket lives.

3

The kubelet asks for identity and node information

It calls the driver to confirm its name and to learn the node’s identifier, volume limit and topology labels.

4

The kubelet records the driver for this node

It creates or updates a per-node record and the node’s labels, so the scheduler and controllers know that this node can use the driver.

Mount propagation

A subtle but vital detail is how mounts made by the node plugin become visible to the application container. A container normally has its own view of the filesystem. For this to work, the node plugin’s container shares the kubelet’s Pod directory with the host using a setting called bidirectional mount propagation, so that a mount made inside the plugin appears on the host and therefore in the application’s Pod directory. Without it, the plugin would mount the volume in its own private view and the application would see an empty folder.

Simple Analogy

Imagine the porter sets up your locker contents on a shelf, but the shelf is inside a glass cabinet that only the porter can see. Mount propagation is the hole in the cabinet that lets the apartment owner see and use what the porter placed. Without the hole, the locker looks empty from your side.

!
Privileges Are Real

A node plugin with host-level mount access is powerful. It can see and change the node’s filesystem view. Treat its image, its configuration and its namespace as part of your trusted infrastructure, and never run untrusted drivers there.

8Kubernetes Objects That Describe a Driver

Besides claims and volumes, three more objects tell Kubernetes how a driver behaves.

CSIDriver: the driver’s settings

A CSIDriver object is a cluster-wide record that declares how Kubernetes should treat a driver. It is optional but very useful. It can say whether volumes need an attach step at all, whether the kubelet should pass Pod details to the driver when mounting, how file ownership should be applied to volumes, whether the driver supports tracking available capacity, and which lifecycle modes it supports, such as persistent volumes or short-lived ephemeral ones.

CSINode: what each node can do

A CSINode object exists for each node. It lists the drivers registered on that node, the node’s identifier in each driver’s world, the topology keys that describe where the node sits, and sometimes the maximum number of volumes the node can hold for each driver. The scheduler uses this to avoid placing a Pod on a node that has reached its volume limit.

VolumeAttachment: the attach request

A VolumeAttachment object records the intent to attach a particular volume to a particular node. It is created by Kubernetes when a Pod using a volume is scheduled to a node, and is watched by the attacher sidecar. Its status shows whether attachment succeeded, and any error. It is the single most useful object to inspect when a Pod is stuck waiting for its disk.

ObjectScopeCreated byUsed for
CSIDriverClusterDriver installer or administratorDeclares driver behaviour and options
CSINodeOne per nodeKubelet, after registrationTracks drivers, node identity, topology and limits
VolumeAttachmentOne per volume and nodeKubernetes attach logicRecords and reports attach and detach progress
CSIStorageCapacityPer class and locationDriver helperPublishes remaining capacity for smarter scheduling
Simple Analogy

The CSIDriver object is the porter agency’s service brochure. CSINode is each floor’s staff list and what they can carry. VolumeAttachment is the written work order: “move locker 42 contents to floor 7.”

Why the attach step may not exist

Not all storage needs attach and detach. A cloud block disk must be attached to a specific virtual machine before it can be used. A network file system, on the other hand, is simply mounted over the network by any node that knows the address. A driver declares which style it is. When no attach is needed, Kubernetes skips the VolumeAttachment step completely and goes straight to node-level stage and publish, which makes startup of such Pods faster.

i
Capacity Awareness

When capacity tracking is enabled, the driver side publishes how much room is left per class and location. The scheduler can then avoid nodes whose nearby storage is full, rather than discovering the shortage only after the Pod lands and provisioning fails.

9The Full Lifecycle: From Claim to Running Container

Follow one volume through every component, from the first request to a mounted folder.

The story in order

An application owner creates a claim naming a StorageClass. The provisioner sidecar sees it, asks the driver to create a volume, and records a PersistentVolume. Kubernetes binds the claim to that volume. When a Pod using the claim is scheduled to a node, Kubernetes creates a VolumeAttachment. The attacher sidecar asks the driver to attach the volume to that node. The kubelet then waits for attachment to finish, asks the node plugin to stage the volume, then to publish it into the Pod’s directory, and finally starts the containers with the folder in place.

sequenceDiagram
  participant U as User
  participant API as Kubernetes API
  participant PR as Provisioner sidecar
  participant CD as Controller driver
  participant AT as Attacher sidecar
  participant KL as Kubelet
  participant ND as Node driver
  U->>API: Create claim with a StorageClass
  PR->>API: Watch sees new claim
  PR->>CD: CreateVolume
  CD-->>PR: Volume ID
  PR->>API: Create PersistentVolume, claim binds
  U->>API: Create Pod that uses the claim
  API->>API: Scheduler picks a node
  API->>API: Attach logic creates VolumeAttachment
  AT->>CD: ControllerPublishVolume to that node
  CD-->>AT: Attached
  AT->>API: Mark VolumeAttachment attached
  KL->>ND: NodeStageVolume
  ND-->>KL: Staged at global path
  KL->>ND: NodePublishVolume
  ND-->>KL: Mounted into Pod directory
  KL->>KL: Start containers
        
FIG 3 — The full path: claim, create, bind, schedule, attach, stage, publish, run

Reading the diagram

The top half belongs to the cluster-wide side: creating the volume and binding it. The middle is the scheduler and the attach request. The bottom is the node’s own work. Notice that the controller driver is called twice, once to create and once to attach, while the node driver is called twice as well, to stage and to publish. Each call is a small, separate, retryable step, and failure at any point leaves the system in a state from which it can continue.

2
cluster-level driver calls on the happy path: create and attach
2
node-level driver calls on the happy path: stage and publish
4
sidecar and kubelet callers that drive those calls
i
What the User Sees

From the application owner’s view, all of this looks like a claim turning from Pending to Bound and a Pod moving from ContainerCreating to Running. The events on the claim and the Pod are the breadcrumb trail that shows which of the steps is currently active.

10Stage Versus Publish, and the Reverse Journey

Why the node side has two steps, and what happens when a Pod goes away.

Why two node steps

A single volume can be used by several Pods on the same node at the same time, for instance when a shared volume is used by two Pods. The expensive, once-per-volume work, such as finding the device and creating a filesystem, should be done once. The cheap, per-Pod work, which is placing the volume into one Pod’s directory, should be done for each Pod. So stage does the expensive part once per node and volume and mounts the volume at a shared staging path. Publish then makes a lightweight bind mount from the staging path into each Pod’s own directory.

Simple Analogy

Staging is the porter bringing a large cabinet up to your floor and unlocking it, which takes effort and is done once. Publishing is putting a labelled shelf of that cabinet in front of each flat that has a right to use it, which is quick and done per household.

The reverse journey

When a Pod is deleted, the order reverses. Unpublish removes the bind mount for that Pod. When the last Pod on the node using the volume is gone, unstage unmounts the staging path. If the volume is no longer needed on that node, the attach logic removes the VolumeAttachment and the attacher asks the driver to detach. Finally, if the claim itself is deleted and the reclaim policy is Delete, the provisioner asks the driver to delete the real volume.

1

Containers stop

The Pod’s processes finish and release the files they were using.

2

NodeUnpublish

The Pod’s own mount is removed from its directory.

3

NodeUnstage

If no other Pod on the node uses the volume, the shared staging mount is removed.

4

ControllerUnpublish

The volume is detached from the node on the storage side, so it can be used elsewhere.

5

DeleteVolume, only when the claim is gone and policy allows

The storage is destroyed if the reclaim policy is Delete, or left intact if it is Retain.

!
Order Matters for Data Safety

Detaching a disk before the node has cleanly unmounted it risks data corruption. The orderly sequence exists to flush data and release the device first. Forcing steps out of order, for example by deleting finalizers by hand, can skip that protection.

11Topology, Scheduling and Binding Modes

A volume’s location constrains where the Pod can run, and the Pod’s location constrains where the volume should be created.

Storage has a location

Many storage systems are tied to a place. A cloud block disk lives in one availability zone and can only be attached to machines in that same zone. A local disk lives on one specific node. If a volume is created in zone A and the Pod is later scheduled into zone B, the Pod can never mount it and will be stuck. CSI handles this with topology: drivers describe where nodes are and where volumes can be reached from, using labels such as zone.

The two binding modes revisited

With immediate binding, the volume is created as soon as the claim appears, before the scheduler has chosen a node for the Pod. The driver has no idea where the Pod will go, so it picks a location on its own. The scheduler is then forced to place the Pod where the volume is. This can leave a Pod unschedulable if that zone is full.

With wait-for-first-consumer binding, creation is postponed. The scheduler first picks a node considering everything else, such as CPU, memory and affinity, and also considering the topology that the driver’s storage supports. Only then is the volume created in the chosen node’s location, passed to the driver as a preferred topology. This is the recommended mode for location-bound storage.

flowchart TD
  C["Claim with wait-for-first-consumer class"] --> P["Claim stays pending, no volume yet"]
  P --> S["Pod created, scheduler evaluates nodes"]
  S --> N["Scheduler picks a node in zone B"]
  N --> T["Chosen node's topology sent to provisioner"]
  T --> V["Driver creates the volume in zone B"]
  V --> B["Claim binds, Pod proceeds to attach and mount"]
        
FIG 4 — With delayed binding the volume is created where the Pod will actually run
Simple Analogy

Immediate binding is like reserving a locker in a random wing of a huge campus before you know which office you will work in. Delayed binding waits until you know your office, then reserves a locker in the same wing.

Allowed topologies

A StorageClass can also restrict volumes to certain locations, for example only two of three zones. This is useful when storage exists only in some places or when data should stay in specific regions. The scheduler and provisioner both honour the restriction.

Volume limits per node

Machines can only hold so many attached volumes. A driver reports the limit through the node information call, and Kubernetes stores it in the node’s record. The scheduler then counts volumes per node and avoids exceeding the limit, so Pods are not sent to a node that has no room for another disk.

i
Rule of Thumb

For any storage that is bound to a zone, node or rack, use delayed binding unless you have a specific reason not to. It removes a whole class of Pods that never start because their disk is in the wrong place.

12Capabilities: Snapshots, Clones, Expansion and Access Modes

What a driver can offer beyond create and mount, and how each feature maps onto the two plugins.

Snapshots

A snapshot is a point-in-time copy of a volume. Kubernetes models it with separate objects: a request for a snapshot, a record of the real snapshot, and a class that names the driver. Snapshots are handled by a snapshot controller in the cluster together with the external-snapshotter sidecar in the controller plugin. A snapshot is a storage-side operation, so it needs only the controller service, and the node plugin takes no part.

Cloning and restoring

A new claim can name an existing snapshot or even an existing claim as its data source. The provisioner passes that source to the driver’s create operation, and the driver builds the new volume from it. This makes it quick to create test copies of databases or to restore after a mistake, depending on how efficiently the storage system implements copying.

Expansion

Growing a volume has two halves. The controller side makes the storage bigger. The node side then grows the filesystem inside it so the extra room is usable. Some drivers can do both while the volume stays mounted, called online expansion, while others need the Pod to be stopped first. Shrinking is not supported.

1

The owner edits the claim to a larger size

The class must allow expansion for this to be accepted.

2

The resizer sidecar calls expand on the controller service

The real storage is enlarged by the storage system.

3

The kubelet calls expand on the node service

The filesystem on the volume is grown to fill the new space.

4

The claim reports the new size

Applications can use the extra room, sometimes after a restart.

Access modes and volume modes

Access mode

Read-write once

One node may mount it for reading and writing. Typical for block disks.

Access mode

Read-write once Pod

Stricter: only a single Pod may use the volume at a time, even on one node.

Access mode

Read-only many

Many nodes may mount it read-only, useful for shared reference data.

Access mode

Read-write many

Many nodes may write at once. Needs storage designed for sharing, such as a network file system.

Separately, a volume can be presented as a filesystem, which is a mounted folder, or as a raw block device, which the application manages itself, common for databases that want direct control. The node plugin handles the difference at publish time.

!
Do Not Assume Sharing

A claim asking for read-write many on a driver that only supports single-node access will not be satisfied, or will behave unpredictably. Always check which access modes your driver and class really support before designing around them.

Ephemeral volumes

CSI also supports volumes that live and die with a single Pod. In the generic style, the Pod’s own definition carries a claim template, and a claim is created and removed along with the Pod, going through the normal provisioning path. Some drivers also support a lighter inline style, where the Pod names the driver directly and the node plugin does the work without any claim. These are useful for scratch space and for injecting data such as secrets from an external store.

13Idempotency, Retries and Failure Recovery

Distributed systems fail halfway through jobs. CSI is designed so that doing a step twice is always safe.

Idempotent by contract

An operation is idempotent when repeating it has the same effect as doing it once. The CSI specification requires this for most calls. If a create-volume request is repeated with the same name, the driver must return the same volume, not create a second one. If a delete is repeated for a volume that is already gone, it must succeed rather than fail. This rule makes retries safe, and retries are the main recovery tool in the whole system.

Simple Analogy

Pressing a lift call button five times does not summon five lifts. The system treats the repeated press as the same request. A good storage driver treats a repeated “create locker number 42” in the same way.

Names make idempotency possible

The provisioner gives each create request a stable name derived from the claim’s unique identity. If the provisioner crashes after the driver created the volume but before it saved the result, the next attempt uses the same name, and the driver can recognise that the volume already exists and return it. Without stable names, such a crash would leak an orphaned volume.

Timeouts and in-progress states

Storage operations can be slow. A sidecar sets a timeout on each call. If a call times out, the sidecar does not know whether the operation completed, so it retries, and the driver should answer with the current state, or with an “operation in progress” signal if the previous attempt is still running. Drivers protect themselves with locks so that two concurrent calls about the same volume do not collide.

Failure

Sidecar crash mid-operation

On restart it re-lists objects and retries, and idempotent calls make the retry safe.

Failure

Driver restart on a node

Existing mounts keep working because they are kernel mounts. New stage and publish calls wait until the driver is back and re-registered.

Failure

Node crash with attached disks

The disks remain attached to the lost node until the system decides it is safe to detach them, which can delay Pod recovery on another node.

Failure

Storage API outage

Calls fail and are retried with back-off. Running Pods are mostly unaffected, but new claims and attachments wait.

i
Running Pods Survive Driver Outages

Once a volume is mounted into a running Pod, the driver is not on the data path for most drivers. The kernel handles reads and writes directly. A driver outage mainly affects creating, attaching, mounting and resizing, not the files that Pods are already using.

The hard case: a node that disappears

If a node vanishes suddenly, its attached disks cannot be cleanly unmounted. Kubernetes waits for a safety period before force-detaching, because attaching a read-write disk to a second node while the first might still be writing risks serious corruption. This is a deliberate trade of availability for safety. Newer features allow an administrator to mark a node as truly shut down, which allows faster, safe recovery. Always follow the documented procedure for your version instead of removing objects by hand.

14Deployment Layout, High Availability and Upgrades

How the pieces are packaged in a real cluster, and how to change them without trouble.

The typical layout

PartWorkload typeReplicasMain containers
Controller pluginDeployment, sometimes a StatefulSetTwo or three for availability, with leader electionDriver, provisioner, attacher, snapshotter, resizer, liveness helper
Node pluginDaemonSetOne per eligible nodeDriver, node-driver-registrar, liveness helper
Snapshot controllerDeployment, one set per clusterTwo with leader electionCluster-wide snapshot controller, shared by drivers
Driver settingsCSIDriver objectOne per driverDeclarative options

Installation approaches

Most drivers are installed with a packaged bundle, such as a Helm chart, an operator or a set of manifests published by the driver’s maintainers. These bundle the workloads, the access rules, the CSIDriver object and the default StorageClasses. Managed Kubernetes services often offer the main cloud driver as an add-on that the provider installs and updates for you. Using the provider’s own add-on is generally the safest choice where available.

Upgrades

1

Read the release notes and compatibility table

Driver, sidecars and Kubernetes versions must be compatible. Skipping this step is the most common cause of upgrade trouble.

2

Test in a staging cluster

Run provisioning, attach, mount, snapshot and expansion tests with realistic workloads.

3

Upgrade the controller plugin first

Roll its replicas one at a time, so leader election keeps at least one copy active.

4

Roll the node plugin gradually

Use a conservative rolling strategy, so only a few nodes are without a registered driver at a time. Existing mounts keep working through the restart.

5

Verify and watch

Check claim binding times, attachment success and error rates, and keep a rollback path ready.

!
Snapshot API Definitions Are Cluster-Wide

The snapshot object definitions and the snapshot controller are shared by every driver in the cluster. Installing mismatched versions from two different driver bundles can break snapshots for all of them. Manage these shared pieces deliberately, once, not as part of each driver’s install.

15CSI Migration: Retiring the Old In-Tree Plugins

How Kubernetes moved existing users from built-in volume code to drivers without breaking their clusters.

The goal

Once CSI matured, the project set out to remove the old in-tree volume code. But thousands of clusters already had claims and volumes created through the old plugins, with old-style names in their specifications. Forcing everyone to rewrite them would have been disruptive. The solution was CSI migration: a translation layer inside Kubernetes that quietly redirects calls meant for an old in-tree plugin to the matching CSI driver.

Simple Analogy

Imagine a company replacing all its old phone extensions with a new system. Rather than asking everyone to learn new numbers, the old numbers are forwarded to the new system automatically. Callers keep dialling the same way, and the forwarding rule handles the rest.

How it works in practice

When migration is active for a volume type, the existing in-tree volume specification is translated on the fly into its CSI form, and the CSI driver does the actual work. Users do not edit their existing objects. For this to work, the matching CSI driver must be installed and healthy in the cluster. Over several releases, migration was enabled by default for the major cloud disk and file plugins, and most of the old in-tree code has since been removed from the project.

What this means for you

Install the driver before upgrading across the removal

If your Kubernetes upgrade crosses the version where an in-tree plugin was removed, the matching CSI driver must already be running, or volumes of that type will stop working.

Prefer the CSI provisioner name in new classes

New StorageClasses should name the CSI driver directly rather than the old in-tree provisioner name, so they do not depend on the translation layer.

Check feature differences

Some options available in the old plugin are named or handled differently in the CSI driver. Review class parameters and test snapshot, expansion and topology behaviour after the move.

i
Check Your Version

Which plugins are migrated, enabled by default or already removed depends on your Kubernetes version. Always consult the release notes and your provider’s documentation for the exact status in your environment.

16Real-World Driver Families and Use Cases

Where CSI drivers show up, and how the controller and node roles differ between them.

Cloud block disks

The most common type. The controller plugin calls the cloud provider’s API to create, attach and detach disks. The node plugin finds the attached device, formats it the first time, and mounts it. Disks are tied to a zone and normally allow single-node read-write access, so delayed binding and topology matter a lot.

Cloud and network file systems

Drivers for managed file shares allow many nodes to read and write at once. Often no attach step exists. The controller plugin creates shares or directories, and the node plugin simply mounts the network path. Good for shared content and for workloads that need read-write many.

Enterprise storage arrays

Vendors of on-premises arrays provide drivers that talk to the array’s management interface from the controller plugin and use block or file protocols on the node plugin. Network reachability from the controller plugin to the array is a key design concern.

Distributed storage systems running inside the cluster

Cluster-native storage systems provide their own driver, so that Pods get replicated volumes carved from the disks of the cluster’s own nodes. The storage system is itself a workload, which makes startup order and failure planning more subtle.

Local volume drivers

Drivers that manage disks on each node offer very high speed and low latency, with the cost that data is tied to a node. They rely on topology to keep Pods on the right node, and need a plan for node loss.

Secrets and configuration drivers

Some drivers use inline ephemeral volumes to present secrets from an external vault as files inside a Pod, with no claim and no persistent storage at all. Only the node plugin does the work.

Backup and data protection tools

Backup products rely on snapshot support in the driver to take consistent copies of volumes, and then move the copy off to separate storage.

FamilyNeeds attach step?Typical access modeTopology sensitivity
Cloud block diskYesRead-write onceHigh, zone bound
Network file systemUsually noRead-write manyLow
Local volumeNoRead-write onceVery high, node bound
Inline ephemeral secretsNoRead-onlyNone

17Performance and Scalability

Storage is rarely fast to create, so most tuning is about concurrency and avoiding pile-ups.

Where time goes

Creating a cloud disk may take several seconds. Attaching can take longer. Formatting a large volume adds more. Mounting is quick, but a volume with a huge number of files may be slow to apply ownership changes at mount time. Most delays are inside the storage system or the machine, not in Kubernetes itself, so it is important to know which stage is slow before you tune anything.

Tuning options

Lever 1

Sidecar concurrency

Each sidecar processes a limited number of items at once. Raising the worker count helps with large bursts, for instance creating hundreds of claims, but must be balanced against the storage API’s rate limits.

Lever 2

API rate limits

Cloud APIs throttle callers. Heavy parallel creates or attaches may be rejected and retried, so spread bursts out and watch throttling errors.

Lever 3

Ownership change cost

Applying file group ownership on mount can walk every file in a big volume. Newer options let the driver or kernel handle ownership more cheaply, so choose the policy that fits the driver.

Lever 4

Resource requests

Give the controller and node plugins enough CPU and memory. A starved plugin answers slowly and looks like a slow storage system.

Lever 5

Per-node volume limits

Set limits that match the machine’s real attachment capacity so the scheduler avoids placing Pods that can never attach their disks.

Scale effects

In a cluster with thousands of nodes, a node plugin on every node means thousands of registrations and thousands of per-node records. The records are small, but a rolling restart of the whole node plugin DaemonSet can briefly cause a storm of re-registrations. Pace rollouts, and make sure the API server and the driver’s own back-end can absorb the burst.

!
Provisioning Storms

When a large job or a StatefulSet creates many claims at once, the provisioner and the cloud API can become the bottleneck, leaving Pods waiting a long time. Stagger large rollouts or pre-provision volumes for predictable bursts.

18Security Considerations

Storage drivers hold keys to data and to hosts. They deserve careful hardening.

Two privilege profiles

The two plugins are powerful in different ways. The controller plugin holds credentials for the storage system, so a compromise could let an attacker create, read through snapshots, or delete volumes across the whole environment. The node plugin holds host-level filesystem access, so a compromise could expose or change other Pods’ data on that node. Treat both as high-value targets.

Control 1

Least-privilege credentials

Give the controller plugin only the storage permissions it needs, scoped to this cluster’s resources. Prefer short-lived workload identities over long-lived keys stored in the cluster.

Control 2

Protected namespace

Run driver workloads in a dedicated system namespace with tight access to edit them, and with explicit exemptions for the privileged settings the node plugin needs.

Control 3

Trusted images

Pin versions, verify image sources and scan images. A driver image runs with high privilege on every node.

Control 4

Narrow access rules for sidecars

Each sidecar needs only specific rights on specific objects. Review the access rules shipped in bundles instead of accepting broad ones.

Secrets in classes

Some drivers need extra credentials per class or per volume, for example for a storage array. A StorageClass can point to a Kubernetes Secret and the sidecars pass its contents to the driver. Keep these Secrets in a locked-down namespace, give the sidecars permission to read only those specific Secrets, and rotate them on a schedule.

Data at rest and in transit

Encryption on the storage side

Many drivers let a class request encryption, with keys managed by the storage system or a key service. Make this a standard class option for sensitive data, not an afterthought.

Isolation between tenants

A claim in one namespace should never reach a volume of another. Use namespaces, access rules and, where needed, separate classes and separate storage accounts per tenant.

Snapshot access

Snapshots contain full copies of data. Restrict who may create claims from snapshots, because restoring is a way to read data that the original owner protected.

File ownership policy

When a Pod mounts a volume, the group ownership of its files may need adjusting so the Pod’s user can read and write. The driver’s declared policy controls whether Kubernetes does this and how. Choosing the wrong policy can either block access or recursively change ownership on large volumes, which is slow and may surprise applications that expect existing ownership to remain.

!
Be Careful with Reclaim Policy and Deletion Rights

Anyone who can delete a claim with a Delete reclaim policy can destroy the underlying data. Limit deletion rights on claims that hold important data, and use Retain together with backups for volumes that must survive mistakes.

19Monitoring, Logging and Troubleshooting

How to see what the driver is doing, and how to find the stuck step when a Pod will not start.

Signals worth watching

Signal

Operation duration and errors by call

Sidecars and the kubelet expose timings and error counts for each CSI call. Watching them per call shows exactly which operation slows or fails.

Signal

Pending claims and their age

Claims that stay pending for long point to provisioning problems, topology mismatches or missing classes.

Signal

Stuck attachments

VolumeAttachment objects that stay unattached or are stuck terminating are a strong sign of storage-side or node-side trouble.

Signal

Volume usage

The kubelet reports used and free bytes and inodes for each volume. Alert before volumes fill, since a full disk causes application failures.

Signal

Plugin health and restarts

Liveness results and restart counts for controller and node plugins reveal crash loops and misconfiguration.

Signal

Capacity

Remaining capacity in the storage pool, so provisioning does not fail for lack of room.

A troubleshooting path for a Pod stuck waiting for its volume

1

Read the Pod and claim events

Events name the failing step and often quote the driver’s error message. Start here every time.

2

Is the claim bound?

If it is pending, look at the class name, the provisioner logs, topology constraints and storage capacity.

3

Does a VolumeAttachment exist and is it attached?

If missing, the Pod may not yet be scheduled. If present but unattached, check the attacher logs and the storage system.

4

Is the node plugin registered on that node?

Check the per-node record for the driver. A missing entry means the registrar or driver failed on that node.

5

Read the node plugin and kubelet logs

Errors from stage or publish, such as device not found, filesystem errors or mount failures, show up here.

6

Check the storage system itself

Quotas, throttling, permissions and outages on the storage side explain many failures that look like Kubernetes problems.

Common symptoms and likely causes

SymptomLikely causeWhere to look
Claim pending, no events from the provisionerClass names a driver that is not installed or the provisioner is downClass provisioner name, provisioner Pod logs
Claim pending with a topology errorNo zone satisfies both the Pod and the class restrictionsAllowed topologies, node labels, binding mode
Pod stuck in container creating, attach never completesStorage API failure or the disk is still attached elsewhereVolumeAttachment status, attacher logs, cloud console
Mount fails on one node onlyNode plugin unhealthy, missing tools or kernel support on that nodeNode plugin logs on that node, kubelet logs
Application sees an empty folderMount propagation misconfigured in the node pluginPlugin Pod volume mounts and propagation setting
Expansion shows new size on claim but not in the PodFilesystem expansion pending on the nodeClaim conditions, node plugin logs, Pod restart need
i
Logging with Purpose

Raise driver log levels only while investigating. Log each CSI call with the volume identifier, the node identifier and the outcome, so a single volume’s journey can be followed across sidecar, driver and kubelet logs.

20Design Patterns and Best Practices

Habits that make storage boring and reliable.

Patterns that work

A small, well-named set of classes

Offer a few clear classes, such as standard, fast, shared and encrypted, with documented behaviour and costs. Too many classes confuse teams and multiply testing.

Delayed binding for location-bound storage

Make wait-for-first-consumer the default for any class whose volumes are tied to a zone or node.

Expansion enabled by default

Allow volume expansion in classes from day one. Growing later is easy, but enabling it afterwards for existing classes requires care.

Snapshots plus tested restores

Schedule snapshots for important data and practise restoring them. A snapshot that has never been restored is only a hope.

Platform-owned driver lifecycle

Let one team own driver installation, upgrades and compatibility checks, with a published support matrix, rather than letting each team install their own.

Spread stateful Pods across failure domains

Use topology spread rules so replicas of a database land in different zones, each with its own zonal volume, so one zone’s failure does not take them all.

Do

  • Check driver, sidecar and Kubernetes version compatibility before upgrading
  • Use delayed binding for zone-bound or node-bound storage
  • Monitor pending claims, stuck attachments and volume usage
  • Back up data independently of the cluster
  • Run several controller replicas with leader election
  • Give plugins appropriate CPU and memory requests

Do not

  • Assume every driver supports every access mode or feature
  • Delete finalizers or attachments by hand to unstick Pods without understanding why
  • Restart all node plugins at once during maintenance
  • Give the controller plugin broader storage credentials than needed
  • Treat Delete reclaim policy as harmless for important data
  • Store critical data without a snapshot and restore plan

21Common Mistakes and Anti-Patterns

Failures that appear again and again in real clusters.

ANTI-PATTERN-01 Avoid
Problem

A zone-bound StorageClass uses immediate binding, so volumes are created before Pods are scheduled.

Why It’s Harmful

The volume may land in a zone that has no free capacity for the Pod, or where the Pod’s other constraints cannot be met. The Pod then stays pending permanently, and the volume cannot move.

Correct Approach

Use wait-for-first-consumer binding so the volume is created in the zone the scheduler chose for the Pod.

ANTI-PATTERN-02 Avoid
Problem

Important production data sits on volumes with the Delete reclaim policy and no backups.

Why It’s Harmful

Deleting a claim, a namespace or a whole StatefulSet by mistake destroys the real storage immediately and irrecoverably.

Correct Approach

Use Retain for critical data, restrict delete rights, schedule snapshots and keep backups outside the cluster.

ANTI-PATTERN-03 Avoid
Problem

Operators remove finalizers from stuck VolumeAttachment or volume objects to make errors disappear.

Why It’s Harmful

The objects vanish but the real disk may still be attached to the old node, or mounted there. A new Pod on another node may then fail, or worse, two nodes may write to one disk and corrupt it.

Correct Approach

Find out why detach is stuck, check the storage system and the node, and use the documented recovery procedure for your version.

ANTI-PATTERN-04 Avoid
Problem

The node plugin is deployed without the correct mount propagation or without the registrar sidecar, based on a trimmed-down sample.

Why It’s Harmful

Either the driver never registers on nodes, or mounts exist in the plugin’s private view and applications see empty folders, which looks like data loss.

Correct Approach

Use the maintainers’ published manifests or chart as the baseline, and change only the settings that you understand.

ANTI-PATTERN-05 Avoid
Problem

Teams request read-write many access on a block-disk driver, assuming it will behave like shared storage.

Why It’s Harmful

Either provisioning fails, or two Pods on different nodes cannot mount the volume, or an unsafe sharing arrangement leads to corruption in applications that do not coordinate writes.

Correct Approach

Use a shared file system driver when many writers are needed, and keep block disks for single-writer workloads.

ANTI-PATTERN-06 Avoid
Problem

Upgrading Kubernetes across the removal of an in-tree plugin without first installing the matching CSI driver.

Why It’s Harmful

Existing volumes of that type can no longer be attached or mounted, causing widespread Pod failures right after the upgrade.

Correct Approach

Read the release notes before every upgrade, install and verify the CSI driver beforehand, and test with a few volumes in a staging cluster.

ANTI-PATTERN-07 Avoid
Problem

Plugins run without resource requests or limits, and node plugin upgrades are rolled out across all nodes at once.

Why It’s Harmful

Starved plugins respond slowly and time out, and a simultaneous restart leaves many nodes unable to stage or publish volumes at the same moment, stalling Pod starts cluster-wide.

Correct Approach

Set sensible requests for both plugins, use a conservative rolling strategy for the node DaemonSet, and upgrade in small batches.

22Advantages, Disadvantages and Trade-offs

An honest balance sheet for the CSI approach.

Advantages

  • One standard way to use any storage system, without changing Kubernetes
  • Drivers ship, fix and upgrade independently of Kubernetes releases
  • Driver crashes are isolated from core components such as the kubelet
  • Clear division of privilege between cluster-level and node-level work
  • Rich shared features such as snapshots, clones, expansion and topology awareness
  • Reusable sidecars, so driver authors only write storage logic

Disadvantages / Trade-offs

  • More components to install, version, secure and monitor
  • Privileged node plugins widen the attack surface of every node
  • Feature support varies a lot between drivers, so portability is partial
  • Version compatibility between driver, sidecars and Kubernetes needs attention
  • Failures at hand-off points between sidecars, driver and kubelet can be hard to trace
  • Storage still has physical limits such as zones, attach counts and API rate limits

Choosing a storage style for a workload

WorkloadGood fitWhy
Single-instance database needing durable storageCloud block disk with delayed bindingFast, durable, single writer
Replicated database with its own replicationLocal volumes or block disks, spread across zonesApplication handles redundancy, storage focuses on speed
Shared content read and written by many PodsNetwork file system driverRead-write many by design
Scratch space during a jobGeneric ephemeral volumeCreated and cleaned with the Pod
Secrets from an external vaultInline ephemeral CSI volumeNo persistent storage needed
Data that needs point-in-time recoveryDriver with snapshot support plus tested restoresFast copies and clean restores

23Frequently Asked Questions

Questions that beginners and experienced engineers keep asking.

Q1Is CSI part of Kubernetes?

The specification is separate and shared with other orchestrators. Kubernetes includes the machinery that talks CSI, such as the kubelet’s volume handling and the API objects, but the drivers and most sidecars live outside the core code and are released on their own schedules.

Q2Why is every driver split into a controller plugin and a node plugin?

Because the work happens in two different places. Some actions affect the storage system as a whole and can run anywhere, others must run on the machine that will use the volume. Splitting them gives each the right privileges and scale, and keeps broad storage credentials away from every node.

Q3What do the sidecars do and why does the driver not watch Kubernetes itself?

Sidecars are generic helper controllers that watch Kubernetes objects and call the driver’s CSI operations. This keeps drivers free of Kubernetes-specific logic, so one driver can work with several orchestrators, and driver authors write only storage code.

Q4What is the difference between stage and publish?

Stage prepares a volume once per node, such as finding the device, formatting it and mounting it at a shared path. Publish makes it appear inside one Pod’s directory, usually by a bind mount from the staging path. This lets many Pods on one node share one prepared volume.

Q5Do all drivers need an attach step?

No. Block disks usually do, because they must be connected to a machine first. Network file systems typically do not, because nodes simply mount a network path. The driver declares which style it uses in its CSIDriver object.

Q6What happens to running Pods if the driver crashes?

Mounted volumes usually keep working because the kernel handles the data path. What stops is new work: creating, attaching, mounting, resizing and snapshotting. Once the driver returns and re-registers, those operations resume.

Q7Why does my Pod stay pending when the claim says bound?

Binding only means a volume exists for the claim. The Pod may still be waiting for scheduling constraints, for the attach to complete, or for the node plugin to stage and publish. Look at the Pod’s events and at the VolumeAttachment to see which step is active.

Q8Why is delayed binding recommended?

Because location-bound volumes must be created where the Pod will run. Delayed binding waits for the scheduler’s decision and then creates the volume in the chosen node’s zone, avoiding Pods that can never mount a volume created somewhere else.

Q9Can I move a claim’s volume to another zone?

Not directly. A zonal volume cannot be attached across zones. The usual approach is to take a snapshot and create a new volume from it in the target zone, if the driver supports snapshots and cross-zone restore.

Q10Is it safe to delete a stuck VolumeAttachment?

Not without understanding why it is stuck. Removing it hides the symptom while the real disk may still be attached or mounted elsewhere, which risks corruption. Investigate the node, the storage side and the documented recovery steps first.

Q11What is CSI migration and do I need to act on it?

It is a translation layer that redirects the old in-tree volume plugins to matching CSI drivers so existing objects keep working. You need to ensure the matching CSI driver is installed before your cluster version crosses the point where the old plugin is disabled or removed. Check the release notes for your version.

Q12Can one cluster run several CSI drivers?

Yes, and this is common. Each driver has its own name, its own controller and node plugins and its own classes, and claims pick one through the class. Shared pieces such as the snapshot controller and snapshot definitions must be installed once for the whole cluster.

24Summary and Key Takeaways

The Container Storage Interface replaced storage code built into Kubernetes with a standard contract spoken over local gRPC sockets. A driver offers up to three services: Identity for self-description, Controller for whole-system actions such as create, delete, attach, snapshot and expand, and Node for machine-level actions such as stage, publish, unpublish and unstage. In practice that becomes two deployments. The controller plugin runs a few replicas with generic sidecars that watch Kubernetes objects and call the driver, and holds the storage credentials. The node plugin runs on every node, is called by the kubelet, registers itself through a registrar sidecar, and holds host-level mount access. Supporting objects such as CSIDriver, CSINode and VolumeAttachment describe driver behaviour, node capabilities and attach progress.

Return to the apartment building from the start. The back office allocates your locker and records its number. The porter on your floor brings it to your door. Neither does the other’s job, each is repeatable and safe to ask twice, and a clear register lets anyone see where things stand. If you remember that picture, and choose delayed binding for location-bound storage, protect both privilege profiles, monitor each step and test your restores, CSI storage becomes predictable and quietly reliable.

Key Takeaways

  • CSI is a contract, not a product — one standard interface over local gRPC lets any storage system plug into Kubernetes without changing Kubernetes, ending the old in-tree model.
  • Controller plugin versus node plugin — cluster-level actions like create, attach and snapshot run in a few replicas with storage credentials, while machine-level stage and publish run on every node with host access.
  • Sidecars translate Kubernetes to CSI — provisioner, attacher, snapshotter, resizer and registrar watch objects or the kubelet and call the driver, so drivers contain only storage logic.
  • The lifecycle is a chain of small, idempotent steps — create, bind, schedule, attach, stage, publish and then the reverse, each safe to retry because stable names and idempotent calls prevent duplicates.
  • Location matters — use delayed binding and topology for zone-bound or node-bound storage, and respect per-node volume limits and access modes.
  • Protect both privilege profiles — least-privilege storage credentials for the controller, trusted images and a guarded namespace for the privileged node plugin, plus careful reclaim policies and deletion rights.
  • Operate it with evidence — monitor pending claims, stuck attachments, per-call durations and volume usage, follow the troubleshooting path from events to attachments to node logs, and never strip finalizers to hide a symptom.