Deep Dive into Kubernetes Volumes Part 2: Persistent Volumes and Claims with NFS and AWS EBS
Introduction
In the first part of our Kubernetes volume series, we explored EmptyDir and HostPath volumes. These volume types are useful for temporary storage and accessing host files, respectively. In this second part, we’ll delve into Persistent Volumes (PV) and Persistent Volume Claims (PVC), focusing on using Network File System (NFS) and Amazon Elastic Block Store (EBS) as storage solutions.
What are Persistent Volumes (PV) and Persistent Volume Claims (PVC)?
In Kubernetes, the Persistent Volume (PV) and Persistent Volume Claim (PVC) mechanism decouples storage provisioning from pod lifecycle management. This separation allows for better management of storage resources and provides a consistent way to manage persistent data.
Persistent Volume (PV): A PV is a piece of storage in the cluster that has been provisioned by an administrator or dynamically provisioned using storage classes. It is a resource in the cluster, similar to a node, and is independent of any individual pod.
Persistent Volume Claim (PVC): A PVC is a request for storage by a user. It is similar to a pod in that pods consume node resources and PVCs consume PV resources. PVCs are used to dynamically or statically bind to PVs and can specify the storage capacity and access modes required.
Using NFS for Persistent Storage
Network File System (NFS) is a distributed file system protocol that allows a user on a client computer to access files over a network in a manner similar to how local storage is accessed.
Step-by-Step Guide to Using NFS in Kubernetes
Set Up an NFS Server:
Ensure you have an NFS server running and accessible by your Kubernetes cluster. Install and configure NFS on a server (this can be on-premises or a cloud VM).
You can get the NFS details with your storage admin if you have specific storage team.
We need NFS server IP/Hostname and the path where we want to use k8s storage.
Create a Persistent Volume (PV):
Create a YAML file to define the NFS PV.
[root@k8s-master ~]# cat pv.yml apiVersion: v1 kind: PersistentVolume metadata: name: k8s-vol spec: capacity: storage: 2Gi accessModes: - ReadWriteMany persistentVolumeReclaimPolicy: Recycle nfs: path: /vol/my-vol server: nfs-server [root@k8s-master ~]#
Apply this configuration to your Kubernetes cluster:
[root@k8s-master ~]# kubectl apply -f pv.yml persistentvolume/k8s-vol created [root@k8s-master ~]# [root@k8s-master ~]# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE k8s-vol 2Gi RWX Recycle Available 14s [root@k8s-master ~]# [root@k8s-master ~]#
Let's see the description of the above pv created.
[root@k8s-master ~]# kubectl describe pv k8s-vol Name: k8s-vol Labels: <none> Annotations: <none> Finalizers: [kubernetes.io/pv-protection] StorageClass: Status: Available Claim: Reclaim Policy: Recycle Access Modes: RWX VolumeMode: Filesystem Capacity: 2Gi Node Affinity: <none> Message: Source: Type: NFS (an NFS mount that lasts the lifetime of a pod) Server: nfs-server Path: /vol/my-vol ReadOnly: false Events: <none> [root@k8s-master ~]#
Now we created the persistent volume, but to use this volume, now we need to create persistent volume claim.
Create a Persistent Volume Claim (PVC):
Create a YAML file to define the PVC.
[root@k8s-master ~]# cat pvclaim.yml apiVersion: v1 kind: PersistentVolumeClaim metadata: name: app1-vol1 spec: accessModes: - ReadWriteMany resources: requests: storage: 1Gi [root@k8s-master ~]#
In this yaml file, we are claiming 1Gi of storage from the existing PVs. As of now we have only one PV created, so this requirement can be fulfilled by volume
"k8s-vol".
Apply this configuration:
[root@k8s-master ~]# kubectl apply -f pvclaim.yml persistentvolumeclaim/app1-vol1 created [root@k8s-master ~]# [root@k8s-master ~]# kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE app1-vol1 Bound k8s-vol 2Gi RWX 10s [root@k8s-master ~]#
We can see from the above output is that this PVC is bounded from volume k8s-vol.
Use the PVC in a Pod:
Create a YAML file to define a pod that uses the PVC.
```bash [root@k8s-master ~]# cat deploy.yml apiVersion: apps/v1 kind: Deployment metadata: name: my-app-deploy spec: replicas: 2 selector: matchLabels: app: python-app template: metadata: labels: app: python-app spec: containers:
- name: c00
image: centos
command: ["/bin/bash", "-c", "sleep 1000000"]
volumeMounts:
- name: python-vol mountPath: "/tmp/pvdata" volumes:
- name: python-vol persistentVolumeClaim: claimName: app1-vol1
- name: c00
image: centos
command: ["/bin/bash", "-c", "sleep 1000000"]
volumeMounts:
[root@k8s-master ~]#
In the above deployment file, we are using our newly created pvc to use as a volume.
Apply this configuration:
```bash
[root@k8s-master ~]# kubectl apply -f deploy.yml
deployment.apps/my-app-deploy created
[root@k8s-master ~]#
[root@k8s-master ~]# kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
my-app-deploy 2/2 2 2 15s
[root@k8s-master ~]#
[root@k8s-master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
my-app-deploy-5db4bdf479-88jj5 1/1 Running 0 20s
my-app-deploy-5db4bdf479-hm495 1/1 Running 0 20s
[root@k8s-master ~]#
Let's do some operations on one of the pods, create some files inside the volume and then delete the pod. The new pod should come with the older data as we are using persistent volume here.
[root@k8s-master ~]# kubectl exec -it my-app-deploy-5db4bdf479-88jj5 -- /bin/bash
[root@my-app-deploy-5db4bdf479-88jj5 /]#
[root@my-app-deploy-5db4bdf479-88jj5 /]# cd /tmp/pvdata/
[root@my-app-deploy-5db4bdf479-88jj5 pvdata]# ls
[root@my-app-deploy-5db4bdf479-88jj5 pvdata]#
[root@my-app-deploy-5db4bdf479-88jj5 pvdata]# touch siddhartha
[root@my-app-deploy-5db4bdf479-88jj5 pvdata]# ls
siddhartha
[root@my-app-deploy-5db4bdf479-88jj5 pvdata]#
[root@my-app-deploy-5db4bdf479-88jj5 pvdata]# touch gaurav
[root@my-app-deploy-5db4bdf479-88jj5 pvdata]#
[root@my-app-deploy-5db4bdf479-88jj5 pvdata]# ls
gaurav siddhartha
[root@my-app-deploy-5db4bdf479-88jj5 pvdata]#
[root@my-app-deploy-5db4bdf479-88jj5 pvdata]# exit
command terminated with exit code 127
[root@k8s-master ~]#
[root@k8s-master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
my-app-deploy-5db4bdf479-88jj5 1/1 Running 0 3m4s
my-app-deploy-5db4bdf479-hm495 1/1 Running 0 3m4s
[root@k8s-master ~]#
[root@k8s-master ~]# kubectl delete pod my-app-deploy-5db4bdf479-88jj5
pod "my-app-deploy-5db4bdf479-88jj5" deleted
[root@k8s-master ~]#
[root@k8s-master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
my-app-deploy-5db4bdf479-fcfvp 1/1 Running 0 34s
my-app-deploy-5db4bdf479-hm495 1/1 Running 0 3m58s
[root@k8s-master ~]#
Now, let's login to the new pod and see if our previous created files are present or not.
[root@k8s-master ~]# kubectl exec -it my-app-deploy-5db4bdf479-fcfvp -- /bin/bash
[root@my-app-deploy-5db4bdf479-fcfvp /]#
[root@my-app-deploy-5db4bdf479-fcfvp /]# cd /tmp/pvdata/
[root@my-app-deploy-5db4bdf479-fcfvp pvdata]#
[root@my-app-deploy-5db4bdf479-fcfvp pvdata]# ls
gaurav siddhartha
[root@my-app-deploy-5db4bdf479-fcfvp pvdata]#
[root@my-app-deploy-5db4bdf479-fcfvp pvdata]#
Hurray! our files are present even after the pod deletion. So by using this we can make our data more persistent and this make our environment more stable.
Using AWS EBS for Persistent Storage
Amazon Elastic Block Store (EBS) provides block-level storage volumes for use with Amazon EC2 instances. These volumes are used in Kubernetes for persistent storage.
Step-by-Step Guide to Using AWS EBS in Kubernetes
Create an EBS Volume:
In the AWS Management Console, create an EBS volume in the same availability zone as your Kubernetes cluster.
Create a Persistent Volume (PV):
Create a YAML file to define the EBS PV.
apiVersion: v1 kind: PersistentVolume metadata: name: ebs-pv spec: capacity: storage: 10Gi accessModes: - ReadWriteOnce awsElasticBlockStore: volumeID: <YOUR_EBS_VOLUME_ID> fsType: ext4
Apply this configuration to your Kubernetes cluster:
kubectl apply -f ebs-pv.yaml
Create a Persistent Volume Claim (PVC):
Create a YAML file to define the PVC.
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: ebs-pvc spec: accessModes: - ReadWriteOnce resources: requests: storage: 10Gi
Apply this configuration:
kubectl apply -f ebs-pvc.yaml
Use the PVC in a Pod:
Create a YAML file to define a pod that uses the PVC.
apiVersion: v1 kind: Pod metadata: name: ebs-test-pod spec: containers: - name: busybox image: busybox command: ["/bin/sh", "-c", "sleep 1000"] volumeMounts: - mountPath: "/mnt/ebs" name: ebs-volume volumes: - name: ebs-volume persistentVolumeClaim: claimName: ebs-pvc
Apply this configuration:
kubectl apply -f ebs-test-pod.yaml
Conclusion
In this second part of our Kubernetes volume series, we explored how to use Persistent Volumes (PV) and Persistent Volume Claims (PVC) with NFS and AWS EBS. These storage solutions provide robust and scalable options for managing persistent data in Kubernetes. By understanding and implementing these concepts, you can ensure that your applications have reliable and consistent access to storage resources.
Stay tuned for more in-depth guides and tutorials on Kubernetes and other cloud-native technologies. Happy learning! 🌐💡
Subscribe to my newsletter
Read articles from Siddhartha Gaurav directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Siddhartha Gaurav
Siddhartha Gaurav
I'm a passionate DevOps engineer with a knack for streamlining development workflows and ensuring seamless deployment pipelines. With experience in managing cloud infrastructure, implementing DevOps best practices, and leveraging automation tools, I thrive on tackling complex challenges and driving efficiency in software delivery. Let's connect and explore how I can contribute to your projects!