Understanding Kubernetes CSI: Persistent Volume Lifecycle and Component Interaction
This article explains how Kubernetes CSI enables out‑of‑tree persistent storage by detailing the PV lifecycle—Create, Attach, Detach, Mount, Unmount, Delete—and describing the roles of core components such as apiserver, PVController, external‑provisioner, external‑attacher, and kubelet, with code examples and diagrams.
The article introduces the Container Storage Interface (CSI) as a standard that allows cloud storage vendors to expose storage to Kubernetes workloads. It explains why Kubernetes moved from in‑tree volume handling to out‑of‑tree CSI plugins to decouple core code and enable flexible, vendor‑specific storage solutions.
Core Terminology
Term
Definition
CSI
Container Storage Interface.
CNI
Container Network Interface.
CRI
Container Runtime Interface.
PV
Persistent Volume.
PVC
Persistent Volume Claim.
StorageClass
Defined by provisioner to assemble volume parameters.
Volume
A unit of storage made available inside a container via CSI.
Block Volume
A volume that appears as a block device inside the container.
Mounted Volume
A volume mounted as a directory inside the container.
CO
Container Orchestration system communicating with plugins via CSI RPCs.
SP
Storage Provider, the vendor of a CSI plugin implementation.
RPC
Remote Procedure Call.
Node
A host where workloads run, identified by a node ID.
Plugin
A gRPC endpoint implementing CSI services.
Plugin Supervisor
Process governing the lifecycle of a Plugin, may be the CO.
Workload
The atomic unit of work scheduled by a CO, usually a container.
The article then outlines the PV creation workflow, showing how apiserver creates a Pod, PVController adds annotations, and the external‑provisioner calls the CSI CreateVolume RPC. It describes the handling of StorageClass.volumeBindingMode (WaitForFirstConsumer vs Immediate) and the subsequent steps involving external‑attacher , AttachDetachController , and kubelet for attaching, mounting, and reconciling volumes.
Component Interaction
Key components include:
kube-controller-manager : runs PVController and AttachDetachController to bind PVC/PV and manage attachment.
CSI‑plugin : implements CSI interfaces and is the core of storage logic.
node‑driver‑registrar : sidecar that registers the CSI plugin with kubelet.
external‑provisioner : creates and deletes volumes via CSI CreateVolume / DeleteVolume RPCs.
external‑attacher : handles volume attach/detach via CSI ControllerPublishVolume / ControllerUnpublishVolume .
external‑snapshotter : provides snapshot and backup capabilities.
external‑resizer : supports volume expansion.
kubelet : runs on each node, mounts/unmounts volumes using CSI NodePublishVolume / NodeUnpublishVolume .
cloud‑storage‑provider : vendor‑specific CSI implementation.
Communication between components uses Unix sockets for plugin‑controller interactions and gRPC (HTTP/2) for communication with the storage service.
Code Examples
External provisioner entry point:
main() {
// Initialize controller that implements Volume create/delete
csiProvisioner := ctrl.NewCSIProvisioner(...)
provisionController := controller.NewProvisionController(...)
run := func(ctx context.Context) {
provisionController.Run(ctx)
}
}PVController initialization (simplified):
func NewController(p ControllerParameters) (*PersistentVolumeController, error) {
controller := &PersistentVolumeController{
volumes: newPersistentVolumeOrderedIndex(),
claims: cache.NewStore(cache.DeletionHandlingMetaNamespaceKeyFunc),
// ... other fields omitted for brevity
}
// Add event handlers for PV and PVC informers
p.VolumeInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{...})
p.ClaimInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{...})
return controller, nil
}AttachDetach reconciler logic (simplified):
func (rc *reconciler) reconcile() {
// Detach volumes that are no longer desired
for _, attachedVolume := range rc.actualStateOfWorld.GetAttachedVolumes() {
if !rc.desiredStateOfWorld.VolumeExists(attachedVolume.VolumeName, attachedVolume.NodeName) {
rc.attacherDetacher.DetachVolume(attachedVolume.AttachedVolume, verifySafeToDetach, rc.actualStateOfWorld)
}
}
// Attach desired volumes
rc.attachDesiredVolumes()
}Summary
By analyzing the creation, attachment, detachment, mounting, unmounting, and deletion processes of Persistent Volumes in Kubernetes, the article demonstrates how CSI implements these steps through a set of coordinated components and standard RPC interfaces, enabling cloud‑native storage extensibility and vendor‑specific features while keeping the core Kubernetes codebase clean.
Cloud Native Technology Community
The Cloud Native Technology Community, part of the CNBPA Cloud Native Technology Practice Alliance, focuses on evangelizing cutting‑edge cloud‑native technologies and practical implementations. It shares in‑depth content, case studies, and event/meetup information on containers, Kubernetes, DevOps, Service Mesh, and other cloud‑native tech, along with updates from the CNBPA alliance.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.