CSI Persistent Volumes

The Container Storage Interface (CSI) is the standard way to provide persistent storage to Kubernetes clusters. CSI decouples Kubernetes from storage-specific implementations, allowing storage vendors to develop drivers without modifying Kubernetes core code. Think of CSI as a universal adapter that lets Kubernetes work with any storage system that provides a CSI driver.

What is CSI?

CSI is a specification that defines a standard interface between container orchestrators (like Kubernetes) and storage systems. Before CSI, storage drivers were built directly into Kubernetes (in-tree), making it difficult to add new storage types or update drivers independently.

graph TB A[Kubernetes] --> B[CSI Interface] B --> C[CSI Driver] C --> D[Storage System] D --> E[AWS EBS] D --> F[GCE Persistent Disk] D --> G[Azure Disk] D --> H[NFS] D --> I[GlusterFS] D --> J[Custom Storage] style A fill:#e1f5ff style B fill:#fff4e1 style C fill:#e8f5e9 style D fill:#f3e5f5

Why CSI?

CSI provides several advantages over the old in-tree volume plugins:

  • Independence - Storage drivers can be developed and updated independently of Kubernetes
  • Standardization - All storage systems use the same interface
  • Flexibility - Easy to add new storage types without Kubernetes changes
  • Extensibility - Supports advanced features like snapshots, cloning, and volume expansion
  • Portability - Same driver interface works across different orchestrators

CSI Architecture

CSI drivers run as separate components in your Kubernetes cluster. They consist of several components:

graph TB A[Kubernetes Components] --> B[External Provisioner] A --> C[External Attacher] A --> D[External Resizer] A --> E[External Snapshotter] B --> F[CSI Driver] C --> F D --> F E --> F F --> G[Storage System API] style A fill:#e1f5ff style F fill:#fff4e1 style G fill:#e8f5e9

CSI Components

  • CSI Driver - The main driver that communicates with the storage system
  • External Provisioner - Provisions volumes when PVCs are created
  • External Attacher - Attaches volumes to nodes when pods are scheduled
  • External Resizer - Expands volumes when PVC size is increased
  • External Snapshotter - Creates and manages volume snapshots

How CSI Works

Here’s the flow when using a CSI volume:

sequenceDiagram participant User participant K8s as Kubernetes API participant Prov as External Provisioner participant Driver as CSI Driver participant Storage as Storage System participant Node participant Attach as External Attacher User->>K8s: Create PVC with StorageClass K8s->>Prov: Provision volume Prov->>Driver: CreateVolume Driver->>Storage: Create storage volume Storage->>Driver: Volume ID Driver->>Prov: Volume created Prov->>K8s: Create PV User->>K8s: Create Pod with PVC K8s->>Node: Schedule pod Node->>Attach: Attach volume Attach->>Driver: ControllerPublishVolume Driver->>Storage: Attach to node Storage->>Driver: Attached Driver->>Attach: Attached Attach->>Node: Volume attached Node->>Driver: NodePublishVolume Driver->>Node: Mount volume

Common CSI Drivers

Cloud Storage Drivers

AWS EBS CSI Driver

  • Provisions EBS volumes
  • Supports gp2, gp3, io1, io2 volume types
  • Automatic volume expansion
  • Multi-attach support

GCE Persistent Disk CSI Driver

  • Provisions GCE Persistent Disks
  • Supports pd-standard, pd-ssd, pd-balanced
  • Regional persistent disks
  • Snapshots and cloning

Azure Disk CSI Driver

  • Provisions Azure Managed Disks
  • Supports Standard and Premium storage
  • Zone-redundant storage
  • Volume snapshots

Network Storage Drivers

NFS CSI Driver

  • Network File System support
  • ReadWriteMany access mode
  • Multiple NFS implementations

GlusterFS CSI Driver

  • Distributed file system
  • High availability
  • Shared storage across nodes

Using CSI Volumes

CSI volumes are used through StorageClasses, just like other volume types. The StorageClass references the CSI driver:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: fast-ssd
provisioner: pd.csi.storage.gke.io  # CSI driver name
parameters:
  type: pd-ssd
  replication-type: regional-pd
volumeBindingMode: WaitForFirstConsumer
reclaimPolicy: Delete
allowVolumeExpansion: true

Then create a PVC that references the StorageClass:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: csi-pvc
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: fast-ssd
  resources:
    requests:
      storage: 100Gi

CSI Driver Installation

CSI drivers are typically installed via DaemonSets and StatefulSets. Here’s a simplified example structure:

# CSI Driver Deployment
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: csi-driver-node
spec:
  selector:
    matchLabels:
      app: csi-driver
  template:
    metadata:
      labels:
        app: csi-driver
    spec:
      containers:
      - name: driver
        image: csi-driver:latest
        # CSI driver container
---
# External Provisioner
apiVersion: apps/v1
kind: Deployment
metadata:
  name: csi-provisioner
spec:
  replicas: 1
  selector:
    matchLabels:
      app: csi-provisioner
  template:
    metadata:
      labels:
        app: csi-provisioner
    spec:
      containers:
      - name: provisioner
        image: external-provisioner:latest
        # Provisioner container

Note: In practice, most CSI drivers are installed via Helm charts or operators provided by storage vendors.

CSI Features

Volume Expansion

CSI supports dynamic volume expansion:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: my-pvc
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: fast-ssd  # Must support expansion
  resources:
    requests:
      storage: 50Gi  # Start with 50Gi

To expand, edit the PVC and increase the size:

resources:
  requests:
    storage: 100Gi  # Expanded to 100Gi

The volume will be expanded automatically (if the StorageClass has allowVolumeExpansion: true).

Snapshots

CSI supports volume snapshots:

apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
  name: my-snapshot
spec:
  source:
    persistentVolumeClaimName: my-pvc
  volumeSnapshotClassName: csi-snapshot-class

Cloning

CSI supports cloning volumes from snapshots:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: cloned-pvc
spec:
  dataSource:
    name: my-snapshot
    kind: VolumeSnapshot
    apiGroup: snapshot.storage.k8s.io
  accessModes:
    - ReadWriteOnce
  storageClassName: fast-ssd
  resources:
    requests:
      storage: 100Gi

Best Practices

  1. Use CSI drivers - Prefer CSI over in-tree volume plugins (most in-tree plugins are deprecated)
  2. Keep drivers updated - Update CSI drivers regularly for bug fixes and new features
  3. Test driver compatibility - Verify CSI drivers work with your Kubernetes version
  4. Monitor driver health - Watch for driver pod failures or errors
  5. Use WaitForFirstConsumer - For better pod scheduling, especially with zone-aware storage
  6. Enable volume expansion - Set allowVolumeExpansion: true in StorageClasses when possible
  7. Document driver versions - Keep track of which CSI driver versions are installed

Troubleshooting

PVC Stuck in Pending

If a PVC is stuck in Pending:

  1. Check if the CSI driver is running: kubectl get pods -n kube-system | grep csi
  2. Verify StorageClass exists: kubectl get storageclass
  3. Check driver logs: kubectl logs -n kube-system <csi-driver-pod>
  4. Verify provisioner matches StorageClass: kubectl get storageclass <name> -o yaml

Volume Attachment Issues

If volumes don’t attach:

  1. Check external attacher logs
  2. Verify node has necessary permissions
  3. Check storage system connectivity
  4. Verify volume limits haven’t been exceeded

Volume Expansion Fails

If volume expansion fails:

  1. Verify StorageClass has allowVolumeExpansion: true
  2. Check if the CSI driver supports expansion
  3. Review external resizer logs
  4. Verify storage system supports expansion

See Also