Kubernetes Storage Classes and CSI Drivers

Storage Classes define how persistent storage is provisioned in Kubernetes, while Container Storage Interface (CSI) drivers enable dynamic provisioning with various storage backends. This guide covers StorageClass parameters, dynamic provisioning, NFS and Ceph CSI drivers, reclaim policies, and best practices for managing persistent volumes in your VPS and baremetal Kubernetes infrastructure.

Table of Contents

Storage Classes Fundamentals

What is a StorageClass?

A StorageClass is a Kubernetes object that describes the type and properties of storage that can be provisioned. It acts as a template for creating PersistentVolumes (PVs).

Benefits

  • Dynamic Provisioning: Automatically create PVs when PVCs are created
  • Multiple Storage Types: Support different storage backends in one cluster
  • Automation: Reduce manual volume creation
  • Flexibility: Different QoS levels for different applications

Default Storage Classes

Check existing storage classes:

kubectl get storageclass
kubectl describe storageclass standard

StorageClass Definition

Basic StorageClass

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: fast-ssd
provisioner: kubernetes.io/aws-ebs
parameters:
  type: gp3
  iops: "3000"
  throughput: "125"
  encrypted: "true"
allowVolumeExpansion: true
volumeBindingMode: WaitForFirstConsumer
reclaimPolicy: Delete

StorageClass Parameters

Common parameters vary by provisioner:

AWS EBS:

provisioner: kubernetes.io/aws-ebs
parameters:
  type: gp3        # Volume type
  iops: "3000"     # I/O operations per second
  throughput: "125" # MB/s
  encrypted: "true" # Enable encryption
  kmsKeyId: "arn:aws:kms:..." # Custom KMS key

vSphere:

provisioner: csi.vsphere.vmware.com
parameters:
  storagepolicyname: "gold"
  datastoreurl: "ds:///vmfs/volumes/.../"

Local Storage:

provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer

Volume Binding Modes

Immediate: Bind PVC immediately

volumeBindingMode: Immediate

WaitForFirstConsumer: Bind when pod uses PVC

volumeBindingMode: WaitForFirstConsumer

Topology-Aware Provisioning

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: topology-aware-storage
provisioner: ebs.csi.aws.com
parameters:
  type: gp3
  iops: "3000"
allowVolumeExpansion: true
volumeBindingMode: WaitForFirstConsumer
allowedTopologies:
- matchLabelExpressions:
  - key: topology.kubernetes.io/zone
    values:
    - us-east-1a
    - us-east-1b

Dynamic Provisioning

Creating PersistentVolumeClaim

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: app-data
  namespace: production
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: fast-ssd
  resources:
    requests:
      storage: 50Gi

Create the PVC:

kubectl apply -f pvc.yaml
kubectl get pvc -n production
kubectl describe pvc app-data -n production

Using PVC in Pod

apiVersion: v1
kind: Pod
metadata:
  name: app
  namespace: production
spec:
  containers:
  - name: app
    image: my-app:1.0
    volumeMounts:
    - name: data
      mountPath: /var/data
  volumes:
  - name: data
    persistentVolumeClaim:
      claimName: app-data

Expanding Volumes

PVCs can be expanded if StorageClass allows:

# Edit PVC to increase size
kubectl patch pvc app-data -n production -p '{"spec":{"resources":{"requests":{"storage":"100Gi"}}}}'

# Verify expansion
kubectl get pvc -n production

CSI Drivers

CSI Overview

CSI (Container Storage Interface) is a standard for storage plugins in Kubernetes.

Common CSI Drivers

  • AWS EBS: ebs.csi.aws.com
  • NFS: nfs.csi.k8s.io
  • Ceph: rbd.csi.ceph.com
  • iSCSI: iscsi.csi.alibabacloud.com
  • Local: local.csi.linode.com

Installing CSI Driver

Generic installation pattern:

# Add Helm repository
helm repo add driver-name https://charts.example.com
helm repo update

# Install CSI driver
helm install csi-driver driver-name/csi-driver \
  -n kube-system \
  -f values.yaml

Verify installation:

kubectl get daemonsets -n kube-system | grep csi
kubectl get statefulsets -n kube-system | grep csi

NFS CSI Driver

Installing NFS CSI

helm repo add nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner/
helm repo update

helm install nfs-subdir-external-provisioner \
  nfs-subdir-external-provisioner/nfs-subdir-external-provisioner \
  -n kube-system \
  --set nfs.server=nfs-server.example.com \
  --set nfs.path=/exports

NFS StorageClass

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: nfs-storage
provisioner: k8s.io/minikube-hostpath
parameters:
  server: nfs-server.example.com
  path: "/exports/kubernetes"
  fsType: "nfs4"
allowVolumeExpansion: true
reclaimPolicy: Delete
volumeBindingMode: Immediate

NFS PVC Example

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nfs-data
  namespace: production
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: nfs-storage
  resources:
    requests:
      storage: 100Gi

NFS Mounting

# Get NFS mount info
kubectl get pv -o yaml | grep -A5 nfs

# Mount on pod
kubectl run -it --rm debug --image=ubuntu -- mount -t nfs nfs-server.example.com:/exports/kubernetes /mnt

Ceph CSI Driver

Installing Ceph

First, ensure Ceph cluster is running:

# Check Ceph cluster status
ceph status
ceph osd tree
ceph pool ls

Installing Ceph CSI

helm repo add ceph-csi https://ceph.github.io/csi-charts
helm repo update

helm install ceph-csi-rbd ceph-csi/ceph-csi-rbd \
  -n ceph-csi-rbd \
  --create-namespace \
  --set configMapName=ceph-config

Ceph StorageClass

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: ceph-rbd-fast
provisioner: rbd.csi.ceph.com
parameters:
  clusterID: a7f64e5b-3b65-46eb-bdc2-6ce22c642d0e
  pool: kubernetes-fast
  imageFeatures: layering
  csi.storage.k8s.io/provisioner-secret-name: csi-rbd-secret
  csi.storage.k8s.io/provisioner-secret-namespace: ceph-csi-rbd
  csi.storage.k8s.io/controller-expand-secret-name: csi-rbd-secret
  csi.storage.k8s.io/controller-expand-secret-namespace: ceph-csi-rbd
  csi.storage.k8s.io/node-stage-secret-name: csi-rbd-secret
  csi.storage.k8s.io/node-stage-secret-namespace: ceph-csi-rbd
allowVolumeExpansion: true
reclaimPolicy: Delete
volumeBindingMode: Immediate

Creating Ceph Secret

# Get Ceph admin key
ceph auth get-key client.admin | base64

# Create secret
kubectl create secret generic csi-rbd-secret \
  -n ceph-csi-rbd \
  --from-literal=userID=admin \
  --from-literal=userKey=<base64-encoded-key>

Reclaim Policies

Delete Policy

Volume deleted when PVC is deleted:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: ephemeral
provisioner: kubernetes.io/aws-ebs
reclaimPolicy: Delete

Retain Policy

Volume retained after PVC deletion:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: archive
provisioner: kubernetes.io/aws-ebs
reclaimPolicy: Retain

Manually delete retained volume:

kubectl delete pv <pv-name>

Recycle Policy (Deprecated)

Clean volume before reuse:

reclaimPolicy: Recycle  # Deprecated - use Delete with manual cleanup

Practical Examples

Example: Multi-Tier Storage Setup

---
# High-performance SSD for databases
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: fast-ssd
provisioner: ebs.csi.aws.com
parameters:
  type: gp3
  iops: "5000"
  throughput: "250"
allowVolumeExpansion: true
volumeBindingMode: WaitForFirstConsumer
reclaimPolicy: Delete
---
# Standard storage for general use
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: standard
provisioner: ebs.csi.aws.com
parameters:
  type: gp3
  iops: "3000"
  throughput: "125"
allowVolumeExpansion: true
volumeBindingMode: Immediate
reclaimPolicy: Delete
---
# Archive storage with long retention
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: archive
provisioner: ebs.csi.aws.com
parameters:
  type: sc1
allowVolumeExpansion: false
volumeBindingMode: Immediate
reclaimPolicy: Retain

Example: Database with Persistent Volume

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: postgres-data
  namespace: databases
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: fast-ssd
  resources:
    requests:
      storage: 100Gi
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: postgres
  namespace: databases
spec:
  serviceName: postgres
  replicas: 1
  selector:
    matchLabels:
      app: postgres
  template:
    metadata:
      labels:
        app: postgres
    spec:
      containers:
      - name: postgres
        image: postgres:15
        ports:
        - containerPort: 5432
          name: postgres
        env:
        - name: POSTGRES_PASSWORD
          valueFrom:
            secretKeyRef:
              name: postgres-secret
              key: password
        volumeMounts:
        - name: data
          mountPath: /var/lib/postgresql/data
          subPath: postgres
  volumeClaimTemplates:
  - metadata:
      name: data
    spec:
      accessModes:
      - ReadWriteOnce
      storageClassName: fast-ssd
      resources:
        requests:
          storage: 100Gi

Example: Shared Storage with NFS

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: shared-documents
  namespace: collaboration
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: nfs-storage
  resources:
    requests:
      storage: 500Gi
---
apiVersion: v1
kind: Pod
metadata:
  name: editor-1
  namespace: collaboration
spec:
  containers:
  - name: editor
    image: myeditor:latest
    volumeMounts:
    - name: documents
      mountPath: /documents
  volumes:
  - name: documents
    persistentVolumeClaim:
      claimName: shared-documents
---
apiVersion: v1
kind: Pod
metadata:
  name: editor-2
  namespace: collaboration
spec:
  containers:
  - name: editor
    image: myeditor:latest
    volumeMounts:
    - name: documents
      mountPath: /documents
  volumes:
  - name: documents
    persistentVolumeClaim:
      claimName: shared-documents

Conclusion

Storage Classes and CSI drivers are fundamental to managing persistent data in Kubernetes. By implementing multiple storage classes for different performance requirements, properly configuring reclaim policies, and choosing appropriate CSI drivers for your infrastructure, you create a flexible and reliable storage layer. Start with a single default storage class, expand to multiple tiers as your needs grow, and regularly monitor storage usage and performance. Whether using cloud-native storage like AWS EBS, open-source solutions like Ceph, or NFS for shared storage, proper configuration ensures your applications have reliable, performant access to persistent data on your VPS and baremetal infrastructure.