> ## Documentation Index
> Fetch the complete documentation index at: https://notes.kodekloud.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Lab Solution Storage Class

> Hands-on Kubernetes lab for StorageClasses, PersistentVolumes and PersistentVolumeClaims including commands, examples, binding modes and creating PVCs and Pods

This lesson walks through a hands-on lab for StorageClasses, PersistentVolumes (PVs), and PersistentVolumeClaims (PVCs) in Kubernetes. Each step includes the exact commands and example outputs you can use to validate the cluster state. Links to relevant Kubernetes documentation are included at the end.

1. How many StorageClasses exist in the cluster?

List StorageClasses with either the short or full command:

```bash theme={null}
# short form
kubectl get sc

# or full
kubectl get storageclass
```

Example output when the cluster initially had only the default StorageClass:

```bash theme={null}
NAME                 PROVISIONER           VOLUMEBINDINGMODE        ALLOWVOLUMEEXPANSION   AGE
local-path (default) rancher.io/local-path  WaitForFirstConsumer    false                  15m
```

After creating additional StorageClasses, you might see multiple entries. Example consolidated output (trimmed for clarity):

```bash theme={null}
kubectl get sc

NAME                         PROVISIONER                      VOLUMEBINDINGMODE        ALLOWVOLUMEEXPANSION   AGE
local-path (default)         rancher.io/local-path            WaitForFirstConsumer     false                  15m
local-storage                kubernetes.io/no-provisioner    WaitForFirstConsumer     false                  6s
portworx-io-priority-high    kubernetes.io/portworx-volume   Immediate                false                  6s
```

Summary table (sample output columns):

| StorageClass Name | Provisioner | Volume Binding Mode | Allow Volume Expansion |
| - | - | - | - |
| local-path (default) | `rancher.io/local-path` | `WaitForFirstConsumer` | `false` |
| local-storage | `kubernetes.io/no-provisioner` | `WaitForFirstConsumer` | `false` |
| portworx-io-priority-high | `kubernetes.io/portworx-volume` | `Immediate` | `false` |

2. Which StorageClass does not support dynamic provisioning?

A StorageClass that uses the `kubernetes.io/no-provisioner` provisioner will not dynamically provision volumes. In the example output above, `local-storage` uses `kubernetes.io/no-provisioner`, so it does not support dynamic provisioning and relies on pre-provisioned PVs.

3. What is the volume binding mode for the `local-storage` StorageClass?

`local-storage` uses the `WaitForFirstConsumer` `volumeBindingMode`. This delays binding until a Pod that consumes the PVC is scheduled, ensuring the PV is bound on a node that actually has access to the underlying local storage.

4. What is the provisioner for the StorageClass named `portworx-io-priority-high`?

From the sample output, the provisioner for `portworx-io-priority-high` is `kubernetes.io/portworx-volume`.

5. Is there a PersistentVolumeClaim consuming the PersistentVolume named `local-pv`?

List PVs and PVCs:

```bash theme={null}
kubectl get pv
kubectl get pvc
```

Example output before creating any PVCs:

```bash theme={null}
kubectl get pv

NAME       CAPACITY  ACCESS MODES  RECLAIM POLICY  STATUS      CLAIM  STORAGECLASS   AGE
local-pv   500Mi     RWO           Retain          Available         local-storage  110s
```

```bash theme={null}
kubectl get pvc

No resources found in default namespace.
```

Initially there are no PVCs consuming `local-pv`; the PV is `Available` and unbound.

6. Create a PersistentVolumeClaim named `local-pvc` that should bind to `local-pv`

To bind a PVC to an existing PV:

* Request the same or smaller capacity than the PV.
* Use a compatible access mode (e.g., `ReadWriteOnce`).
* Specify the same `storageClassName` as the PV (`local-storage` in this example).

Create `pvc.yaml`:

```yaml theme={null}
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: local-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 500Mi
  storageClassName: local-storage
```

Apply the manifest:

```bash theme={null}
kubectl create -f pvc.yaml
# Output:
# persistentvolumeclaim/local-pvc created
```

Check the PVC status:

```bash theme={null}
kubectl get pvc
# Example:
# NAME        STATUS    VOLUME     CAPACITY  ACCESS MODES  STORAGECLASS    AGE
# local-pvc   Pending              500Mi     RWO           local-storage   4s
```

7. Why is the PVC in Pending even though the PV exists and matches?

Describe the PVC to view events:

```bash theme={null}
kubectl describe pvc local-pvc
```

Relevant events example:

```text theme={null}
Events:
  Type    Reason               Age                 From                         Message
  ----    ------               ----                ----                         -------
  Normal  WaitForFirstConsumer  6s (x4 over 49s)   persistentvolume-controller  waiting for first consumer to be created before binding
```

Because the StorageClass `local-storage` uses `volumeBindingMode: WaitForFirstConsumer`, binding is intentionally delayed until a Pod that consumes the PVC is created and scheduled. The PVC remains `Pending` until an associated Pod exists so the scheduler can ensure the Pod is placed on a node that can access the PV.

<Callout icon="lightbulb" color="#1CB2FE">
  StorageClasses with `WaitForFirstConsumer` delay binding (and dynamic provisioning) until a Pod uses the PVC. This is typical for local volumes to ensure the PV is bound on a node that actually has the storage.
</Callout>

8. Create a Pod that consumes `local-pvc`

Create `nginx-pod.yaml` that mounts the claim at `/var/www/html`:

```yaml theme={null}
apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    run: nginx
spec:
  containers:
  - name: nginx
    image: nginx:alpine
    volumeMounts:
    - name: local-pvc-volume
      mountPath: /var/www/html
  volumes:
  - name: local-pvc-volume
    persistentVolumeClaim:
      claimName: local-pvc
  restartPolicy: Always
```

Create the Pod:

```bash theme={null}
kubectl apply -f nginx-pod.yaml
# or
kubectl create -f nginx-pod.yaml
```

Verify Pod and PVC status:

```bash theme={null}
kubectl get pods
# Example:
# NAME    READY   STATUS    RESTARTS   AGE
kubectl get pvc
# Example:
# NAME        STATUS   VOLUME     CAPACITY  ACCESS MODES  STORAGECLASS    AGE
# local-pvc   Bound    local-pv   500Mi     RWO           local-storage   1m
```

When the Pod that uses the PVC is created, the PVC transitions from `Pending` to `Bound` and the PV becomes bound to the claim.

9. Create a new StorageClass `delayed-volume-sc` that uses `no-provisioner` and delayed binding

Create `delayed-volume-sc.yaml`:

```yaml theme={null}
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: delayed-volume-sc
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer
```

Create the StorageClass:

```bash theme={null}
kubectl create -f delayed-volume-sc.yaml
# Output:
# storageclass.storage.k8s.io/delayed-volume-sc created
```

Verify StorageClasses:

```bash theme={null}
kubectl get sc

# Example:
# NAME                         PROVISIONER                      VOLUMEBINDINGMODE        ALLOWVOLUMEEXPANSION   AGE
# local-path (default)         rancher.io/local-path            WaitForFirstConsumer     false                  26m
# local-storage                kubernetes.io/no-provisioner    WaitForFirstConsumer     false                  10m
# portworx-io-priority-high    kubernetes.io/portworx-volume   Immediate                false                  10m
# delayed-volume-sc            kubernetes.io/no-provisioner    WaitForFirstConsumer     false                  3s
```

The `delayed-volume-sc` StorageClass uses the `no-provisioner` provisioner and `WaitForFirstConsumer` binding, suitable for clusters that rely on pre-provisioned local PVs and want to delay binding until Pod scheduling.

Links and references

* [Kubernetes StorageClass docs](https://kubernetes.io/docs/concepts/storage/storage-classes/)
* [Persistent Volumes](https://kubernetes.io/docs/concepts/storage/persistent-volumes/)
* [Persistent Volume Claims](https://kubernetes.io/docs/concepts/storage/persistent-volumes/#persistentvolumeclaims)

***

<Frame>
  <img src="https://mintcdn.com/kodekloud-c4ac6d9a/iXPD-mlT91ZNL1uK/images/Certified-Kubernetes-Administrator-CKA/Storage/Lab-Solution-Storage-Class/kubernetes-persistent-volumes-docs-dockershim-banner.jpg?fit=max&auto=format&n=iXPD-mlT91ZNL1uK&q=85&s=30e523dfa01540140fc8d50acf877755" alt="A screenshot of the Kubernetes documentation webpage titled &#x22;Persistent Volumes,&#x22; showing the article content and an introduction about persistent volumes. The page includes a left navigation menu, a right sidebar of links, and a blue banner about Dockershim removal." width="1920" height="1080" data-path="images/Certified-Kubernetes-Administrator-CKA/Storage/Lab-Solution-Storage-Class/kubernetes-persistent-volumes-docs-dockershim-banner.jpg" />
</Frame>

<CardGroup>
  <Card title="Watch Video" icon="video" cta="Learn more" href="https://learn.kodekloud.com/user/courses/cka-certification-course-certified-kubernetes-administrator/module/883f0aa9-3aa9-45a6-bd26-3a87ded1e00e/lesson/77c85389-075e-49f3-bc26-69774bdbe46d" />
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.