Skip to main content
RunBook Academy

KubernetesLII · CSICSI

The CSI controller plugin — Create, Delete, Attach, Snapshot, Expand

Advanced⏱ ~17 minkubectl

What you'll learn

  • Describe the controller plugin's responsibilities in detail
  • Identify the gRPC operations: CreateVolume, DeleteVolume, ControllerPublishVolume, CreateSnapshot, ControllerExpandVolume
  • Explain the deployment topology (Deployment with leader election)
  • Apply the production pattern for controller plugin HA

Prerequisites

Verified against Kubernetes 1.34.x · kubeadm 1.34.x · kubectl 1.34.x · etcd 3.6.x · CoreDNS 1.11.x · containerd 1.7.x / 2.x · 2026-08-16

Not yet marked complete on this device.

The CSI controller plugin is the cluster-wide operator that creates, deletes, attaches, snapshots, and expands volumes. This lesson walks the operations, the deployment topology, and the production discipline.

Controller plugin responsibilities

The controller plugin implements the CSI Controller Service:

OperationPurposeWhen called
CreateVolumeCreate a volume on the backendWhen a PVC is bound (dynamic provisioning)
DeleteVolumeDelete a volume on the backendWhen a PV is reclaimed (Delete policy)
ControllerPublishVolumeAttach a volume to a nodeWhen a Pod is scheduled to a node
ControllerUnpublishVolumeDetach a volume from a nodeWhen a Pod is removed from a node
CreateSnapshotCreate a snapshotWhen a VolumeSnapshot is created
DeleteSnapshotDelete a snapshotWhen a VolumeSnapshot is deleted
ControllerExpandVolumeExpand a volumeWhen a PVC’s capacity request is increased
ValidateVolumeCapabilitiesCheck if a volume supports the requested capabilitiesWhen the kubelet queries
sequenceDiagram
    participant CM as Controller manager
    participant CP as Controller plugin
    participant BE as Backend
    Note over CM,CP: Provisioning
    CM->>CP: CreateVolume (name, capacity, params)
    CP->>BE: create volume
    BE-->>CP: volumeHandle
    CP-->>CM: PV created
    Note over CM,CP: Attaching
    CM->>CP: ControllerPublishVolume (volumeHandle, nodeId)
    CP->>BE: attach volume to node
    BE-->>CP: attached
    CP-->>CM: publishInfo (devicePath)
    Note over CM,CP: Snapshotting
    CM->>CP: CreateSnapshot (volumeHandle, snapshotId)
    CP->>BE: create snapshot
    BE-->>CP: snapshotId
    CP-->>CM: snapshot created
    Note over CM,CP: Expanding
    CM->>CP: ControllerExpandVolume (volumeHandle, newSize)
    CP->>BE: expand volume
    BE-->>CP: expanded
    CP-->>CM: expansion confirmed

The CreateVolume operation

CreateVolume is the operation that creates a volume on the backend. The request includes:

message CreateVolumeRequest {
  string name = 1;             // PVC name (used for idempotency)
  CapacityRange capacity_range = 2;  // min and max capacity
  map<string, string> parameters = 3; // StorageClass parameters
  VolumeCapabilities volume_capabilities = 4; // access mode, fsType
  map<string, string> secrets = 5;  // credentials
  Topology topology_requirement = 6; // topology constraints
}

The controller plugin:

  1. Validates the parameters against the backend’s capabilities.
  2. Calls the backend’s API to create the volume (e.g., EBS CreateVolume, Ceph RBD create).
  3. Returns the volumeHandle (a backend-specific identifier) to the kube-controller-manager.

The operation is idempotent: calling CreateVolume with the same name returns the same volumeHandle.

The ControllerPublishVolume operation

ControllerPublishVolume attaches the volume to a node (for cloud-block storage). The request includes:

message ControllerPublishVolumeRequest {
  string volume_handle = 1;
  string node_id = 2;
  VolumeCapability volume_capability = 3;
  bool readonly = 4;
  map<string, string> secrets = 5;
}

The controller plugin calls the backend to attach the volume to the node:

  • EBS: ec2:AttachVolume API call.
  • GCE PD: disks.attach API call.
  • Ceph RBD: map the RBD image to the node.

The operation returns a publishInfo (the device path on the node) that the kubelet uses for mount.

The CreateSnapshot operation

CreateSnapshot creates a snapshot of an existing volume. The request includes:

message CreateSnapshotRequest {
  string name = 1;             // VolumeSnapshot name (idempotency)
  string source_volume_handle = 2;
  map<string, string> parameters = 3;
  map<string, string> secrets = 4;
}

The controller plugin calls the backend to create the snapshot:

  • EBS: ec2:CreateSnapshot API call.
  • Ceph RBD: rbd snap create command.
  • NFS: depends on the implementation (not all NFS backends support snapshots).

The operation is idempotent: calling CreateSnapshot with the same name returns the same snapshot.

The ControllerExpandVolume operation

ControllerExpandVolume expands a volume’s capacity. The request includes:

message ControllerExpandVolumeRequest {
  string volume_handle = 1;
  int64 capacity_range = 2;
  string node_id = 3;  // for online resize coordination
}

The controller plugin calls the backend to expand the volume. After the backend confirms the expansion, the kubelet resizes the filesystem.

Deployment topology

The controller plugin is a Deployment with leader election:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: ebs-csi-controller
  namespace: kube-system
spec:
  replicas: 2    # HA: one active, one standby
  template:
    spec:
      containers:
      - name: ebs-csi-controller
        image: amazon/aws-ebs-csi-driver:latest
        args:
        - --leader-election=true
        - --leader-election-namespace=kube-system

With leader election:

  • One replica is the leader; it processes all CSI operations.
  • Other replicas are standby; they watch for leader health.
  • If the leader fails, a standby takes over.

The external sidecar pattern

For CSI drivers, the controller-manager-side operations (CreatVolume, etc.) are typically implemented in a sidecar container that runs alongside the actual driver:

flowchart LR
    A[kube-controller-manager] -->|gRPC| B[External sidecar<br/>csi-provisioner]
    B -->|gRPC| C[CSI driver container]
    C --> D[Storage backend]

The external sidecar (e.g., csi-provisioner from the Kubernetes CSI external-provisioner project) handles the watching of PVCs and the calling of the CSI driver. The driver container implements the CSI specification.

This pattern is widely used because it separates concerns: the sidecar handles Kubernetes-specific watching logic; the driver implements the CSI spec.

Quiz

Knowledge check · 4 questions

  1. Q1. Which CSI operation is responsible for creating a snapshot of a volume?

  2. Q2. The CSI controller plugin should be deployed with at least 2 replicas with leader election for HA.

  3. Q3. Your team observes that CreateSnapshot operations are failing with `DeadlineExceeded`. Walk through the diagnostic.

    VolumeSnapshot creation has been failing for 30 minutes. The CSI controller plugin is running. Existing volumes are functioning. The error is `DeadlineExceeded` (gRPC code 4).

  4. Q4. Explain why the CSI controller plugin is deployed with leader election and what the HA pattern is.

Passing score: 75%. Answers are checked in this browser.

Production discipline

  • At least 2 controller plugin replicas with leader election. A single replica is a SPOF.
  • Monitor controller plugin latency and error rate. The controller is on the critical path for PVC provisioning.
  • Test every CSI operation the workload uses. Provision, attach, mount, snapshot, expand, delete.
  • Configure appropriate rate limits. Some CSI drivers have internal rate limits to avoid backend throttling.
  • Document the controller’s deployment in the cluster bootstrap. HA, scaling, monitoring.