Dynamic vs Static Volume Provisioning in Kubernetes

In Kubernetes, if you store some data (create a file, write to it, modify a file, etc.) in a container running inside your pod, the changes won’t persist once the container stops running (crashes, stops normally or restarts). For better data persistence, Kubernetes provides the following options:

  • Ephemeral Volumes – Specified inline in the pod’s spec, these follow the pod’s lifecycle, i.e., get created and deleted along with the pod. Hence, they survive across pod restarts (or stop and start) but not when the pod is deleted. The volume itself is backed by the node’s storage or separate disks.
  • Persistent Volumes – Independent of the pod lifecycle, these are separately created via the PersistentVolume object and used with the PersistentVolumeClaim object. The volume itself is backed by separate disks that you create in your cloud provider or on-prem.

Now when specifically working with Persistent Volumes, they can be provisioned statically/manually or dynamically. Ephemeral volumes are sort of always provisioned dynamically. The purpose of this article is to understand how static and dynamic provisioning differ through some examples that work with Persistent Volumes.

Static Volume Provisioning

When provisioning a volume manually, we first create a storage backend (or a disk) in our cloud provider (GCP, AWS, Azure, etc.) or on-prem. Of course, we could also use a pre-existing disk. Then we create a PersistentVolume resource in our K8S cluster that points to that disk.

For example in the case of GCP/GKE, say we created a disk (Compute Engine) called my-disk, then a PV with the following manifest would have to be created:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: PV_NAME
spec:
  storageClassName: "STORAGE_CLASS_NAME"
  capacity:
    storage: DISK_SIZE
  accessModes:
    - ReadWriteOnce
  csi:
    driver: pd.csi.storage.gke.io
    volumeHandle: projects/PROJECT_NAME/zones/ZONE/disks/my-disk
    fsType: ext4

For other CSI drivers, to figure out the right values for spec.csi, follow the relevant driver link from here where you will all the information. For instance, here’s how you do it for AWS:

spec:
  ...
  csi:
    driver: ebs.csi.aws.com
    fsType: ext4
    volumeHandle: {EBS volume ID}

For In-tree volume plugins, the right configuration manifests can be found in the K8S documentation.

Now, in order to use the PV above, a PVC pointing to it must be created. This PVC will be used by a pod later:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: PVC_NAME
spec:
  storageClassName: "STORAGE_CLASS_NAME"
  volumeName: PV_NAME
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: DISK_SIZE

Feel free to use the PVC in a pod then:

apiVersion: v1
kind: Pod
metadata:
  name: POD_NAME
spec:
  volumes:
    - name: pv-storage
      persistentVolumeClaim:
        claimName: PVC_NAME
  containers:
    - name: web
      image: nginx
      ports:
        - containerPort: 80
          name: "http-server"
      volumeMounts:
        - mountPath: "/usr/share/nginx/html"
          name: pv-storage

Dynamic Volume Provisioning

Compared to statically provisioning volumes, where the disk on the cloud provider (or on-prem) and PersistentVolume object in the K8S cluster has to be created manually, with dynamic volume provisioning we just have to create our PVC using the right storage class and both the disk in the cloud provider (or on-prem) and the PV object are automatically created by the volume plugin (if supported).

With dynamic volume provisioning, you will most likely be using one of the CSI (out-of-tree) volume plugins. Refer to this list to find out whether your plugin supports dynamic provisioning or not.

Assuming we have a StorageClass that looks like this:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: standard
parameters:
  type: pd-standard
provisioner: pd.csi.storage.gke.io
reclaimPolicy: Delete
volumeBindingMode: Immediate
allowVolumeExpansion: true

Let’s discuss a few fields first:

  • provisioner specifies which volume plugin to use, in this case, it is the GCP persistent disk CSI volume plugin that does support dynamic volume provisioning.
  • parameters are passed to the plugin for configuration. Follow your driver documentation to learn more about supported parameters.

Now let’s create a PVC with the storage class above:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: myclaim
spec:
  storageClassName: standard
  accessModes:
    - ReadWriteOnce
  volumeMode: Filesystem
  resources:
    requests:
      storage: 10Gi

Let’s look at all the resources now:

# Create a PVC from the manifest above
$ k apply -f pvc.yaml
persistentvolumeclaim/myclaim created

$ k get pvc
NAME      STATUS   VOLUME                                     CAPACITY   STORAGECLASS
myclaim   Bound    pvc-5fbffcf5-e417-4591-96b3-1cd6bd099709   10Gi        standard

# Automatically created PersistentVolume via the standard StorageClass
$ k get pv
NAME                                       CAPACITY   RECLAIM POLICY   STATUS   CLAIM          STORAGECLASS
pvc-5fbffcf5-e417-4591-96b3-1cd6bd099709   10Gi        Delete           Bound    test/myclaim   standard

# Automatically created disk in GCP Compute Engine
$ gcloud compute disks list
NAME                                       LOCATION       LOCATION_SCOPE  SIZE_GB   TYPE         STATUS
pvc-5fbffcf5-e417-4591-96b3-1cd6bd099709   us-west1-b     zone            10        pd-standard  READY

As you can see, we created the PVC resource that automatically created:

  1. A disk in GCP Compute Engine.
  2. A PV resource pointing to the disk.

This was done by the CSI plugin specified in the SC’s provisioner field. The PVC also bound itself to the PV. Now any pod can claim the PVC just like we saw in the static provisioning section (pod manifest) above.

Leave a Reply

Your email address will not be published. Required fields are marked *