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:
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——————————————