SubPath In Volumes

12 January 2022
Storage
volume
kubernetes

Understanding Subpath with Kubernetes Volumes

A pod in Kubernetes is the smallest deployable unit that has one or more containers in it and these containers include volumes that are used for storage purposes like to share files between containers, to store files from root filesystems, to use Network Attached File System such as NFS, EBS and many more. These volumes use volume mount which directs where to mount files.

But when working with volumes, we often encounter some problems like

  1. As we mount a Kubernetes volume at a mount-point and if we already have some content in it, then it would be hidden by our mount. But in some cases, we would not want to hide the existing content at the mount-point but want to add additional files/directories in parallel.
  2. While working with multiple configmaps/secrets, if one wants to mount multiple keys from different configmaps/secrets at the same or other location but cannot do it as it gets overwritten

To solve such types of problems, a subPath in volume comes to the rescue.

Basically, a volume is a directory, possibly with some data in it, which is accessible to the containers in a pod and the contents of it are determined by the particular volume type used.

To use a volume in the pod it is specified with .spec.volumes and volume mount for containers with .spec.containers[*].volumeMounts

Copy Code
Loading...

For each container defined within a Pod, you must independently specify where to mount each volume that the container uses with inside volumeMounts.mountPath

These volumes cannot be mounted within other volumes but can be shared for multiple uses in a pod which avoids creating multiple volume mounts and this is done with subpath in volume mounts.

The volumeMounts.subPath property specifies a sub-path inside the referenced volume instead of its root.

To make it more clear, in the below code snippet which has both mountPath and subPath inside volumeMounts name volume1.  

Copy Code
Loading...

As we know the path of volume on the host is created under the following path /var/lib/kubelet/pods/<pod uid>/volumes/<volume type>/<volume name>

And for the above example, İf we’re not using subPath (only mountPath) then at the host, volume is created at /var/lib/kubelet/pods/<pod uid>/volumes/kubernetes.io~empty-dir/volume1

On the other hand, if we’re using subPath as dataset1 then at the host,  its path looks like /var/lib/kubelet/pods/<pod uid>/volume-subpaths/volume1

From this we came to know, subPath will append the data to the existing volume mount point by creating a new directory and will not overwrite the existing content which makes the same volume to be mounted multiple times.

This is mostly useful when you want to mount a configuration file from a config map or want to mount credentials from secret but not to mount it as a volume. So, it can be done with the subpath.
NOTE: Click on the LAB SETUP button on the right-hand side to get the lab-ready for performing hands-on. This will set up a terminal and an IDE to perform the lab.

Lab for SubPath

In this hands-on lab, we will be seeing two examples for subpath in which the first one will give us a better understanding of subpath and help us to compare it with mountpath.

In the second example, we will be mounting keys from configmap through the subpath.

Example One

To see the difference between the mountPath and subPath more precisely, create an Nginx pod and deploy it using a service.

  • Create an Nginx pod with labels app=nginx  on it.
Copy Code
Loading...
kubectl apply -f nginx-app.yaml
kubectl get pods
  • Create a NodePort service for the same and access the app through app-port-30000 
Copy Code
Loading...
kubectl apply -f service.yaml
kubectl get svc

On accessing the application through app-port-30000 URL  you will see the welcomes page of Nginx

Now let's see the difference between mountpath and subpath by creating a new Nginx pod with mountpath and subpath specified in it.

  • Delete the existing Nginx pod
kubectl delete pod nginx-app
  • Create a directory at the host which will be used as a volume to be mounted
mkdir /data
  • And move the hello.html present at root directory to /data directory 
mv hello.html /data/
Copy Code
Loading...
  • Create another Nginx pod and use mountPath in volumeMounts  to mount /data volume along with labels app=nginx
Copy Code
Loading...
  • Now create the pod to expose it with the NodePort service.
kubectl apply -f pod1.yaml
kubectl get pods

On accessing the application again, will find that the Nginx welcome page is not there because in volumeMounts mountPath is /usr/share/nginx/html/ and the existing contents of this location has been overwritten by hello.html

This can be verified with the help of the following command.

kubectl exec -it nginx-pod1 -- ls /usr/share/nginx/html

  You can also run the curl localhost command to verify it.

kubectl exec nginx-pod1 -- curl localhost
  • Again delete the existing Nginx pod  
kubectl delete pod nginx-pod1
  •  Create another Nginx pod and use subPath as well inside volumeMounts
Copy Code
Loading...

Here subPath is hello.html and mountPath is /usr/share/nginx/html/hello.html

This will make the subPath value to be appended with the mountPath and will not overwrite the existing contents.

  • Now create the pod to expose it with the NodePort service.
kubectl apply -f pod2.yaml
kubectl get pods

On accessing the application again, will find that the Nginx welcome page comes there now because in volumeMounts subPath is also used along with mountPath  which appends new content along with the existing content at the location /usr/share/nginx/html/

This can be verified with the help of the following command.

kubectl exec -it nginx-pod2 -- ls /usr/share/nginx/html

  You can also run the curl localhost command to verify it.

kubectl exec nginx-pod2 -- curl localhost

Example Two

  • Create a config map with multiple key files in it and then will mount the keys from configmap inside Nginx pod using subpath at different locations.
Copy Code
Loading...
  • Apply the configmap
kubectl apply -f configmap.yaml
kubectl get configmaps
  • Create an Nginx pod and inside spec.containers.volumeMounts specify the name of the volume, mountPath, and subPath to mount one of the keys from configmap say nginx.conf  and use configmap as the volume inside .spec.volumes
Copy Code
Loading...
  • Now create the pod and exec into the pod for the keys.
kubectl apply -f config-volume.yaml
kubectl get pods
kubectl exec -it nginx -- cat /tmp/config/nginx.conf
kubectl exec -it nginx -- cat /mnt/virtualhost.conf

Here, we will see that nginx.conf and virtualhost.conf key from configmap, both are mounted at /tmp/config and /mnt location respectively  and if only mountPath is used then we will not be able to use the same volume mount to mount at different locations at the same time.  

NOTE : SubPaths are not automatically updated when a ConfigMap is modified. Changes to a ConfigMap will need a new deployment which would result in the pods being recreated with the updated ConfigMap content.

Conclusion

In this hands-on lab, we have seen about subpath in Kubernetes volumes and saw what problems it can solve if being used. 

About the Author

Oshi Gupta

Oshi Gupta

DevOps Engineer & Technical Writer, CloudYuga

Oshi Gupta is a final year undergraduate student and currently working as an Intern at CloudYuga. She is working on Kubernetes and different cloud-native technologies. She also has been a student mentor for the Google Cloud Career Readiness program.