CKA — StorageClasses

5 minute read

CKA Exam Domain

Storage — 10%

StorageClasses enable dynamic provisioning of PersistentVolumes. Instead of an admin manually creating PVs, a StorageClass tells Kubernetes how to create them on demand when a PVC is submitted.

What Is a StorageClass?

A StorageClass provides a way to describe the “classes” of storage available in your cluster. Different classes might map to different quality-of-service levels, backup policies, or provisioner types.

Without StorageClasses:

Admin creates PV → User creates PVC → Kubernetes binds them

With StorageClasses:

Admin creates StorageClass → User creates PVC → Kubernetes auto-creates PV → Binding happens

This is called dynamic provisioning — and it is how most production clusters operate.

StorageClass Spec

Here is a complete StorageClass definition:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: fast
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer
reclaimPolicy: Delete

Key fields:

Field Description
provisioner The volume plugin used to create PVs (e.g., CSI driver, cloud provider)
volumeBindingMode When PV binding and provisioning occur
reclaimPolicy What happens to dynamically provisioned PVs when PVCs are deleted
parameters Provisioner-specific settings (disk type, IOPS, etc.)

Exam tip: Note the API group — apiVersion: storage.k8s.io/v1, not v1. This is a common mistake on the exam.

Dynamic Provisioning

The dynamic provisioning flow:

  1. Admin creates a StorageClass with a provisioner
  2. User creates a PVC referencing the StorageClass
  3. Kubernetes calls the provisioner to create a PV matching the PVC request
  4. The PV is automatically bound to the PVC
# StorageClass
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: standard
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer
---
# PVC referencing the StorageClass
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: dynamic-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi
  storageClassName: standard

Note: kubernetes.io/no-provisioner does not support dynamic provisioning — it requires pre-created PVs. This provisioner is commonly used in CKA exam environments with hostPath volumes. For actual dynamic provisioning, you would use a CSI driver or cloud provisioner.

StorageClass Parameters

Parameters are specific to the provisioner. Here are some examples:

AWS EBS Example

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: gp3
provisioner: ebs.csi.aws.com
parameters:
  type: gp3
  fsType: ext4
  iops: "3000"
  throughput: "125"
volumeBindingMode: WaitForFirstConsumer
reclaimPolicy: Delete

GCE PD Example

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: ssd
provisioner: pd.csi.storage.gke.io
parameters:
  type: pd-ssd
volumeBindingMode: WaitForFirstConsumer
reclaimPolicy: Delete

Default StorageClass

A default StorageClass is used when a PVC does not specify a storageClassName. You mark a StorageClass as default using an annotation:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: standard
  annotations:
    storageclass.kubernetes.io/is-default-class: "true"
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer

Behavior:

  • PVCs without storageClassName → use the default StorageClass
  • PVCs with storageClassName: "" (empty string) → no StorageClass, only binds to PVs with no class
  • Only one StorageClass should be marked as default per cluster

Check the default StorageClass:

kubectl get storageclass

The default class shows (default) next to its name:

NAME                 PROVISIONER                    RECLAIMPOLICY   VOLUMEBINDINGMODE      AGE
standard (default)   kubernetes.io/no-provisioner   Delete          WaitForFirstConsumer   5d
fast                 kubernetes.io/no-provisioner   Delete          WaitForFirstConsumer   2d

volumeBindingMode

This field controls when PV binding and dynamic provisioning happen:

Mode Description When to Use
Immediate PV is bound as soon as PVC is created When storage is available from any node (e.g., network-attached storage)
WaitForFirstConsumer PV binding is delayed until a Pod using the PVC is scheduled When storage is topology-dependent (e.g., local disks, zone-specific volumes)

Why WaitForFirstConsumer matters:

  • Prevents PV from being provisioned in a different zone than where the Pod runs
  • Ensures the scheduler can consider storage constraints when placing the Pod
  • Recommended for most use cases

Exam tip: If you see a PVC stuck in Pending and the StorageClass has WaitForFirstConsumer, it might be waiting for a Pod to be created — this is expected behavior, not an error.

Provisioners Comparison

Provisioner Type Dynamic Provisioning Notes
kubernetes.io/no-provisioner Local No Requires pre-created PVs, common in CKA exam
kubernetes.io/aws-ebs AWS Yes (in-tree, deprecated) Use ebs.csi.aws.com instead
ebs.csi.aws.com AWS Yes (CSI) AWS EBS CSI driver
pd.csi.storage.gke.io GCP Yes (CSI) GCE Persistent Disk CSI driver
disk.csi.azure.com Azure Yes (CSI) Azure Disk CSI driver
rancher.io/local-path Local Yes Used in k3s, kind, and some CKA environments

kubectl Commands

Essential StorageClass commands for the exam:

# List all StorageClasses
kubectl get storageclass
kubectl get sc   # shorthand

# Describe a StorageClass
kubectl describe storageclass fast

# Get StorageClass in YAML format
kubectl get sc fast -o yaml

# Delete a StorageClass
kubectl delete sc fast

Practice Questions

Q1. Create a StorageClass named local-storage with provisioner kubernetes.io/no-provisioner and volumeBindingMode WaitForFirstConsumer.

Show Answer
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: local-storage
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer
kubectl apply -f local-storage.yaml
kubectl get sc local-storage

Q2. What is the difference between Immediate and WaitForFirstConsumer volume binding modes?

Show Answer
  • Immediate: PV is bound to the PVC as soon as the PVC is created, regardless of whether a Pod is using it. This can lead to topology issues if the PV is provisioned in a different zone than where the Pod runs.
  • WaitForFirstConsumer: PV binding is delayed until a Pod using the PVC is scheduled. This ensures the PV is provisioned in the correct topology (zone, node) for the Pod.

WaitForFirstConsumer is the recommended mode for most scenarios.

Q3. How do you set a StorageClass as the default?

Show Answer

Add the annotation storageclass.kubernetes.io/is-default-class: "true" to the StorageClass:

kubectl patch storageclass <name> -p '{"metadata":{"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'

Or in the YAML:

metadata:
  annotations:
    storageclass.kubernetes.io/is-default-class: "true"

Only one StorageClass should be marked as default per cluster.

Q4. A PVC with storageClassName: "" (empty string) is created. Which PVs can it bind to?

Show Answer

A PVC with storageClassName: "" will only bind to PVs that have no storageClassName set. It explicitly opts out of dynamic provisioning and will not use the default StorageClass.

This is different from omitting storageClassName entirely, which causes the PVC to use the default StorageClass.

Q5. Why does kubernetes.io/no-provisioner not support dynamic provisioning?

Show Answer

The no-provisioner is designed for local volumes and pre-created PVs. It tells Kubernetes that PVs using this StorageClass must be manually created by the admin — the provisioner will not automatically create them when a PVC is submitted.

This is commonly used in CKA exam environments where hostPath PVs are pre-created. The StorageClass still serves a purpose: it groups PVs and enables WaitForFirstConsumer binding mode.

Updated: