Killercoda StorageClass and Dynamic Provisioning

CKA-LOGO I am planning to take the CKA exam in the near future. I work with Kubernetes daily at my job, but am mostly self taught, so it is probably realistic to say that I have some knowledge gaps. This blog is part of my preparation, where I go through all the scenarios on Killercoda.

StorageClass and Dynamic Provisioning

https://killercoda.com/course-cka/scenario/domain1-storageclass-dynamic-provisioning

Create StorageClasses and understand reclaim policies

Create StorageClass

There is an existing default StorageClass using the rancher.io/local-path provisioner. Create a new StorageClass named retain-storage using the same provisioner but with reclaimPolicy: Retain and volumeBindingMode: WaitForFirstConsumer .

StorageClasses describe the different types of storage that can be used and how they are provisioned (see here). The existing class uses the rancher.io/local-path provisioner, which uses the local nodes disk to provision volumes (see here):

$ k get storageclass
NAME                   PROVISIONER             RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
local-path (default)   rancher.io/local-path   Delete          WaitForFirstConsumer   false                  15h

Based on the documentation (see here) we can create a new StorageClass. The reclaimPolicy: Retain describes that if the PVC is deleted the PV provisioned stays in the Released state and has to be deleted manually. volumeBindingMode: WaitForFirstConsumer describes that the PV should only be provisioned as soon as a Pod is started which utilizes it.

cat <<EOF | kubectl apply -f -
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
    name: retain-storage
provisioner: rancher.io/local-path
reclaimPolicy: Retain
volumeBindingMode: WaitForFirstConsumer
EOF

Create PVC and Pod

In Namespace storage : Create a PVC named data-pvc requesting 1Gi with access mode ReadWriteOnce using the retain-storage StorageClass. Create a Pod named writer that mounts the PVC at /data . Exec into the Pod and create file /data/test.txt on the volume.

We create a PVC based on the docs (see here). The access mode ReadWriteOnce describes that the PVC can only be mounted for RW access by one node at a time. Alternatives would be ReadWriteMany or ReadOnlyMany which need to be supported by the used priovisioner.

$ cat << EOF | kubectl apply -f -
apiVersion: v1 
kind: PersistentVolumeClaim
metadata: 
    name: data-pvc
    namespace: storage
spec:
    accessModes:
    - ReadWriteOnce
    resources:
        requests: 
            storage: 1Gi
    storageClassName: retain-storage
EOF

A pod with the volume mounted can be created by using spec.volumes and spec.containers[].volumeMounts:

$ cat << EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
    name: writer
    namespace: storage
spec:
    containers:
    - name: writer
      image: nginx
      volumeMounts:
      - name: data
        mountPath: "/data"
    volumes:
    - name: data
      persistentVolumeClaim:
        claimName: data-pvc
EOF

To create the file we can just exec into the created Pod:

$ k exec -n storage writer -- touch /data/test.txt

Verify Data Persistence

Delete the Pod writer and the PVC data-pvc in Namespace storage . Then confirm that the PV still exists with status Released and the file test.txt is still on disk.

We delete the Pod and the PVC. If we then look at the PVs, we can see that the associated PV pvc-313e5161-749e-4d3c-a5ae-42c932cd8594 has the state Released:

$ k delete pod -n storage writer
pod "writer" deleted from storage namespace
$ k delete pvc data-pvc -n storage
persistentvolumeclaim "data-pvc" deleted from storage namespace
$ k get pv   
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS     CLAIM              STORAGECLASS     VOLUMEATTRIBUTESCLASS   REASON   AGE
pvc-313e5161-749e-4d3c-a5ae-42c932cd8594   1Gi        RWO            Retain           Released   storage/data-pvc   retain-storage   <unset>                          8m20s

Since the used provisioner uses local paths to provision the storage we can describe the PV to figure out where on the disk the volume is located:

$ k describe pv pvc-313e5161-749e-4d3c-a5ae-42c932cd8594
Name:              pvc-313e5161-749e-4d3c-a5ae-42c932cd8594
Labels:            <none>
Annotations:       local.path.provisioner/selected-node: controlplane
                   pv.kubernetes.io/provisioned-by: rancher.io/local-path
Finalizers:        [kubernetes.io/pv-protection]
StorageClass:      retain-storage
Status:            Released
Claim:             storage/data-pvc
Reclaim Policy:    Retain
Access Modes:      RWO
VolumeMode:        Filesystem
Capacity:          1Gi
Node Affinity:     
  Required Terms:  
    Term 0:        kubernetes.io/hostname in [controlplane]
Message:           
Source:
    Type:          HostPath (bare host directory volume)
    Path:          /opt/local-path-provisioner/pvc-313e5161-749e-4d3c-a5ae-42c932cd8594_storage_data-pvc
    HostPathType:  DirectoryOrCreate
Events:            <none>

Now we can check the path /opt/local-path-provisioner/pvc-313e5161-749e-4d3c-a5ae-42c932cd8594_storage_data-pvc to see if our file still exists:

$ ls -al /opt/local-path-provisioner/pvc-313e5161-749e-4d3c-a5ae-42c932cd8594_storage_data-pvc
total 8
drwxrwxrwx 2 root root 4096 May 17 12:31 .
drwxr-xr-x 4 root root 4096 May 17 12:29 ..
-rw-r--r-- 1 root root    0 May 17 12:31 test.txt

Updated: