Storage Volume of Kubernetes

Keywords: Docker Kubernetes kubelet vim

In a series of virtualization solutions, data persistence is a problem that we need to be very concerned about, as is the case with dokcer and Kubernetes. But in Kubernetes, there's a concept of data volumes.

1, Volume introduction

We often say: container, pod are very short! What it means is that the life cycle of both the container and Pod is very short and will be destroyed and created frequently. When the container is destroyed, the data stored in the internal file system of the container will be cleared.

The life cycle of a Volume is independent of the container. The container in the Pod may be destroyed and restarted, but the Volume will be retained.

Kubernetes Volume mainly solves the following two problems:
1) Data persistence: generally, when a container is running, the files written to its file system are temporary. When the container crashes, kubelet will restart the container continuously. When the number of restarts is reached, the container is still unavailable. Then it will be kill ed and a new container will be generated. At this time, the new running container does not have the data in the original container, because the container is created by the image;
2) Data sharing: there is often a need to share files / folders between containers running in the same Pod;

Basically, a data volume is just a directory or file that can be accessed by Pod. How this directory comes from depends on the type of data volume. Two containers in the same Pod can mount a data volume to different directories.

Volume provides the abstraction of various backend. When using volume to read and write data, the container does not need to care whether the data is stored in the file system of the local node or on the cloud disk. For it, all types of volumes are just a directory.

2, emptyDir of Volume

1) About emptyDir

emptyDir is the most basic Volume type. As its name suggests, an emptyDir Volume is an empty directory on the Host.

emptyDir Volume is persistent for the container, not for the Pod. When a Pod is deleted from a node, the contents of the Volume are also deleted. But if only the container is destroyed and the Pod is still there, the Volume is not affected. Similar to docker manager volume in docker data persistence!

2) emptyDir usage example

[root@master yaml]# vim emptyDir.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: producer-consumer          #Define the name of the Pod
spec:
  containers:
  - image: busybox
    name: producer              #Define the name of the container
    volumeMounts:
    - mountPath: /producer_dir            #Specify the path within the container
      name: shared-volume                 #Indicates that the shared volume is mounted to the container
    args:               #When the container is finished, perform the following write operations
    - /bin/sh
    - -c
    - echo "hello k8s" > /producer_dir/hello; sleep 30000

  - image: busybox
    name: consumer             #Define the name of the container
    volumeMounts:
    - mountPath: /consumer_dir
      name: shared-volume                     #Same as last container
    args:
    - /bin/sh
    - -c
    - cat /consumer_dir/hello; sleep 30000

  volumes:
  - name: shared-volume           #Define the name of the data volume, which must be consistent with the name of the data volume mounted above
    emptyDir: {}             #Define a data volume of type emptyDir with the name shared volume
[root@master yaml]# kubectl apply -f emptyDir.yam        #Generate required Pod resources
[root@master yaml]# kubectl exec -it producer-consumer -c producer /bin/sh
#Enter the first container for verification
/ # cat /producer_dir/hello 
hello k8s
[root@master yaml]# kubectl exec -it producer-consumer -c consumer /bin/sh
#Second container for validation
/ # cat /consumer_dir/hello 
hello k8s

It can be seen that the contents of the directory specified by the two containers in this pod are the same. The local directory needs further verification.

[root@master yaml]# kubectl get pod -o wide           
NAME                READY   STATUS    RESTARTS   AGE     IP           NODE     NOMINATED NODE   READINESS GATES
producer-consumer   2/2     Running   0          7m58s   10.244.2.2   node02   <none>           <none>
#You can see that this pod is running on node02
[root@node02 ~]# docker ps | grep busybox          #Because there are many containers, filter according to the image name used
4fbd734e1763        busybox                "/bin/sh -c 'cat /co..."    8 minutes ago       Up 8 minutes                            k8s_consumer_producer-consumer_default_003a002d-caec-4202-a020-1ae8d6ff7eba_0
b441c2ff2217        busybox                "/bin/sh -c 'echo \"h..."   8 minutes ago       Up 8 minutes                            k8s_producer_producer-consumer_default_003a002d-caec-4202-a020-1ae8d6ff7eba_0
[root@node02 ~]# docker inspect 4fbd734e1763         #View container details based on its ID
#Locate the Mounts field as follows:
        "Mounts": [
            {
                "Type": "bind",
                "Source": "/var/lib/kubelet/pods/003a002d-caec-4202-a020-1ae8d6ff7eba/volumes/kubernetes.io~empty-dir/shared-volume",
                                #The local directory of docker host is specified here
                "Destination": "/consumer_dir",             #Contents in container
                "Mode": "",
                "RW": true,
                "Propagation": "rprivate"
            },
[root@node02 ~]# docker inspect b441c2ff2217
        "Mounts": [
            {
                "Type": "bind",
                "Source": "/var/lib/kubelet/pods/003a002d-caec-4202-a020-1ae8d6ff7eba/volumes/kubernetes.io~empty-dir/shared-volume",
                "Destination": "/producer_dir",
                "Mode": "",
                "RW": true,
                "Propagation": "rprivate"
            },
#It can be seen that the source directories of the two containers are the same, and the mounted directory is the same local directory of docker host                       
[root@node02 ~]# cd /var/lib/kubelet/pods/003a002d-caec-4202-a020-1ae8d6ff7eba/volumes/kubernetes.io~empty-dir/shared-volume
[root@node02 shared-volume]# cat hello 
hello k8s
#Verify content

Because it is a Kubernetes cluster environment, it is difficult to delete a container. Delete the pod directly and check whether the local data of docker host exists!

[root@master yaml]# kubectl delete -f emptyDir.yaml
#master node delete pod
[root@node02 ~]# cd /var/lib/kubelet/pods/003a002d-caec-4202-a020-1ae8d6ff7eba/volumes/kubernetes.io~empty-dir/shared-volume
-bash: cd: /var/lib/kubelet/pods/003a002d-caec-4202-a020-1ae8d6ff7eba/volumes/kubernetes.io~empty-dir/shared-volume: There is no file or directory
#node02 verifies that the directory has disappeared

3) emptyDir summary

emptyDir is a temporary directory created on Docker Host. Its advantage is that it can easily provide shared storage for containers in Pod without additional configuration. But it doesn't have persistence, and if the Pod doesn't exist, so does emptyDir. According to this feature, emptyDir is particularly suitable for the scenario where containers in Pod need to temporarily share storage space!

Simply put, if the container is deleted, the data still exists; if the Pod is deleted, the data will not exist!

3, HostPath of Volume

The function of the hostPath Volume is to mount the existing directory in the Docker Host file system to the Pod's container. Most applications will not use hostPath Volume, because it actually increases the coupling between Pod and node, and limits the use of Pod. However, applications that need access to Kubernetes or docker internal data (configuration files and binary libraries) need to use hostPath. Similar to bind mount in docker data persistence!

Of course, it can also be created. Here you can steal a lazy one and use the YAML file of Kubernetes cluster to introduce!

[root@master yaml]# kubectl edit --namespace=kube-system pod kube-apiserver-master 
#View yaml file of apiserver component

As shown in the picture:

If the Pod is destroyed, the directory corresponding to the hostPath will also be preserved. From this point of view, the persistence of hostPath is better than emptyDir. However, once the Host crashes, the hostPath cannot be accessed.

Because there are few use scenarios, the above two methods will not be described in detail here!

4, Persistent Volume of Volume

Overview of Persistent Volume

There is a static binding relationship between a normal volume and the Pod that uses it. In the file that defines the Pod, the volume that it uses is also defined. Volume is an accessory of Pod. We cannot create a volume alone because it is not a separate K8S resource object.

PV for short is a K8S resource object, so we can create a PV separately. It does not have a direct relationship with Pod, but realizes dynamic binding through Persistent Volume Claim (PVC for short). PVC is specified in the Pod definition, and then PVC will automatically bind appropriate PV to Pod according to the requirements of Pod.

Now that there is the concept of PV, the concept of PVC (persistent volume claim) has to be mentioned. PVC represents the user's request to use storage, and applies an application and declaration for PV persistence space. K8s cluster may have multiple PVS. You need to create multiple PVS for different applications.

As shown in the picture:

KubernetesVolume
1) PV is the storage resource in the cluster, which is usually created and managed by the Cluster Administrator;
2) StorageClass is used to classify PV. If the configuration is correct, Storage can also dynamically create PV according to the request of PVC;
3) PVC is a request to use this resource, which is usually made by the application program, and specifies the corresponding StorageClass and the required space size;
4) PVC can be used as a kind of data volume, which is attached to Pod;

The management process of PV and PVC is as follows:
1) A separate directory is divided on the host for PV use, and its available size is defined;
2) Create PVC as a resource object to apply for storage space of PV;
3) Add data volume to Pod, which is related to PVC;
4) Pod contains a container to mount data volume;

Here is a case to learn more about Persistent Volume!

Case realization process:
1) The bottom layer adopts NFS storage, and then divides 1G capacity under NFS directory for PV scheduling;
2) Create PVC to apply for storage space of PV;
3) Create Pod, use the storage space of PVC application to realize data persistence;

1) Set up NFS storage

This case directly creates NFS storage on the master node!

[root@master ~]# yum -y install nfs-utils rpcbind
[root@master ~]# vim /etc/exports
/nfsdata *(rw,sync,no_root_squash)
[root@master ~]# systemctl start nfs-server
[root@master ~]# systemctl start rpcbind
[root@master ~]# showmount -e
Export list for master:
/nfsdata *

2) Create PV resource object

[root@master ~]# vim test-pv.yaml 
apiVersion: v1
kind: PersistentVolume
metadata:
  name: test-pv
spec:
  capacity:
    storage: 1Gi          #Specify 1G as the container for this PV resource allocation
  accessModes:         #Specify access mode
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Recycle       #Specify recycling policy
  storageClassName: nfs           #Specify storage class name
  nfs:                          #Need to be consistent with the storage class name
    path: /nfsdata/test-pv                //Specify directory for NFS
    server: 192.168.1.4                  //Specify the IP address for NFS

In the above yaml file, the main fields are explained as follows:
1) Access modes:

  • ReadWriteOnce: mount to a single node in a read-write way;
  • ReadWriteMany: mount to multiple nodes in a read-write way;
  • ReadOnlyMany: mount to multiple nodes in read-only mode;
    2) Persistent volume reclaim policy:
  • Recycle: automatically clear the data in PV, and automatically recycle;
  • Retain: manual recycling is required;
  • Delete: delete cloud storage resources (dedicated for cloud storage);
[root@master ~]# kubectl apply -f test-pv.yaml
[root@master ~]# kubectl get pv         #View PV status
NAME      CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
test-pv   1Gi        RWO            Recycle          Available           nfs                     21s
#Note that the PV status must be Available for normal use

3) Create PVC resource object

[root@master ~]# vim test-pvc.yaml 
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: test-pvc
spec:
  accessModes:             #Define the access mode, which must be consistent with that defined by PV
  - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi            #Direct request i uses maximum capacity
  storageClassName: nfs           #The name of the definition should be the same as that of the PV definition
[root@master ~]# kubectl apply -f test-pvc.yaml
[root@master ~]# kubectl get pvc          #View the status of PVC
NAME       STATUS   VOLUME    CAPACITY   ACCESS MODES   STORAGECLASS   AGE
test-pvc   Bound    test-pv   1Gi        RWO            nfs            102s
[root@master ~]# kubectl get pv           #View PV status
NAME      CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM              STORAGECLASS   REASON   AGE
test-pv   1Gi        RWO            Recycle          Bound    default/test-pvc   nfs                     14m
#Note that the status of PV and PVC is Bound, indicating that the association between PV and PVC is successful

PV and PVC can be associated through storageClassName or accessModes!

Common states are:
1) Available - > idle, not bound to PVC;
2) Bound - > bound to PVC;
3) Released > PVC is deleted and resources are not used;
4) Failed - > auto recycle failed;

4) Create a Pod

[root@master ~]# vim test-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: test-pod
spec:
  containers:
  - name: test-pod
    image: busybox
    args:
    - /bin/sh
    - -c
    - sleep 300000
    volumeMounts:
    - mountPath: /testdata            #Define the directory in the container
      name: volumedata               #Ensure consistency with volume name
  volumes:
    - name: volumedata               #Define the name of the volume
      persistentVolumeClaim:
        claimName: test-pvc            #Specifies the PVC name for the logical volume
[root@master ~]# kubectl apply -f  test-pod.yaml 
[root@master ~]# kubectl get pod      #View the status of the pod
NAME       READY   STATUS              RESTARTS   AGE
test-pod   0/1     ContainerCreating   0         6m26s
#Note that its status is ContainerCreating, which means that the container is being created, but it has not been created for such a long time, which is not normal

When the pod status is abnormal, we can generally use the following three ways to troubleshoot:
1) Use "kubectl describe pod pod name" to view the details of the pod;
2) Use "kubectl logs pod name" to view the log information of the pod;
3) Use "cat /var/log/messages" to view the system log;

This time, the first way is used!

[root@master ~]# kubectl describe pod test-pod 
#The last message is as follows:
mount.nfs: mounting 192.168.1.4:/nfsdata/test-pv failed, reason given by server: No such file or directory
#According to the message prompt, the directory specified to be mounted locally does not exist
[root@master ~]# mkdir  -p  /nfsdata/test-pv
#After creating the directory, it is recommended to check the nodes of the container generated by the pod, restart the kubelet service on the node, and check the status of the pod again after the restart
[root@master ~]# kubectl get pod / / check the status of the pod again
NAME       READY   STATUS    RESTARTS   AGE
test-pod   1/1     Running   0          32m

5) Test the effect of data persistence

[root@master ~]# kubectl exec -it test-pod /bin/sh
/ # echo "test pv pvc" > /testdata/test.txt
#Enter the container and create a file for testing
[root@master ~]# cat /nfsdata/test-pv/test.txt 
test pv pvc
#Confirm that the file exists locally
[root@master ~]# kubectl delete -f test-pod.yaml 
#Delete pod
[root@master ~]# cat /nfsdata/test-pv/test.txt 
test pv pvc
#Check again and find that the test file of pod still exists
[root@master ~]# kubectl delete -f test-pvc.yaml 
#Delete PVC
[root@master ~]# cat /nfsdata/test-pv/tes
cat: /nfsdata/test-pv/tes: There is no file or directory
#Check again and find that the test file of pod is missing, because the PVC is deleted

Summary: when we create the PV resource object, the recycling strategy is to clear the data in the PV, and then recycle it automatically. The PV resource object is applied for by PVC, so whether it's a container or a pod, their destruction will not affect the data in the nfs local directory used for data persistence. However, once the PVC is deleted, then Then the local data will disappear with the destruction of PVC, that is to say, PV data volume is used to realize data persistence, and its data persistence life cycle is consistent with that of PVC.

——————————————Thank you for reading——————————————

Posted by r00tk1LL on Wed, 05 Feb 2020 19:30:15 -0800