这几天阳了,坐一会儿就腰痛
K8S中的常用存储方案
背景
因为K8S的POD运行了最终的业务,而pod在控制器的管理下可能会出现重建,重建的pod是镜像的新实例,如果一些重要配置文件或者日志文件也会随着pod的重建丢失,因此需要将pod的重要文件放在物理机存储,或者网络存储上。
常见的存储方法有:emptyDir、hostPath、nfs、PV
emptyDir
emptyDir主要用于测试,一次性的。
当 Pod 分派到某个节点上时,emptyDir 卷会被创建,并且在 Pod 在该节点上运行期间,卷一直存在。 就像其名称表示的那样,卷最初是空的。 尽管 Pod 中的容器挂载 emptyDir 卷的路径可能相同也可能不同,这些容器都可以读写 emptyDir 卷中相同的文件。 当 Pod 因为某些原因被从节点上删除时,emptyDir 卷中的数据也会被永久删除。
用途
- 缓存空间,例如基于磁盘的归并排序。
- 为耗时较长的计算任务提供检查点,以便任务能方便地从崩溃前状态恢复执行。
- 在 Web 服务器容器服务数据时,保存内容管理器容器获取的文件。
[root@master-worker-node-1 storage]# cat pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-with-volume
spec:
containers:
- name: busybox
image: busybox
imagePullPolicy: IfNotPresent
command: ['/bin/sh','-c','sleep 1234']
volumeMounts:
- mountPath: /mnt
name: test-emptydir # 在容器中挂在之前创建的volume
volumes: # 先创建一个volume,
- name: test-emptydir
emptyDir:
sizeLimit: 200Mi
/ # df -Th
Filesystem Type Size Used Available Use% Mounted on
overlay overlay 20.0G 5.9G 14.1G 29% /
tmpfs tmpfs 64.0M 0 64.0M 0% /dev
tmpfs tmpfs 3.8G 0 3.8G 0% /sys/fs/cgroup
/dev/sda1 xfs 20.0G 5.9G 14.1G 29% /mnt # 挂载的卷,虽然限制的200M,但是显示还是主机的空间
/dev/sda1 xfs 20.0G 5.9G 14.1G 29% /etc/hosts
/dev/sda1 xfs 20.0G 5.9G 14.1G 29% /dev/termination-log
/dev/sda1 xfs 20.0G 5.9G 14.1G 29% /etc/hostname
/dev/sda1 xfs 20.0G 5.9G 14.1G 29% /etc/resolv.conf
shm tmpfs 64.0M 0 64.0M 0% /dev/shm
tmpfs tmpfs 7.5G 12.0K 7.5G 0% /var/run/secrets/kubernetes.io/serviceaccount
tmpfs tmpfs 3.8G 0 3.8G 0% /proc/acpi
tmpfs tmpfs 64.0M 0 64.0M 0% /proc/kcore
tmpfs tmpfs 64.0M 0 64.0M 0% /proc/keys
tmpfs tmpfs 64.0M 0 64.0M 0% /proc/timer_list
tmpfs tmpfs 64.0M 0 64.0M 0% /proc/sched_debug
tmpfs tmpfs 3.8G 0 3.8G 0% /proc/scsi
tmpfs tmpfs 3.8G 0 3.8G 0% /sys/firmware
# 确定pod的UID
[root@master-worker-node-1 storage]# kubectl get pods pod-with-volume -o yaml | grep uid
uid: 2b3d790e-8a8f-4b02-92c5-49716438c5a8
# 在pod所处的node上可以查看相应的路径
[root@only-worker-node-3 ~]# ls -l /var/lib/kubelet/pods/2b3d790e-8a8f-4b02-92c5-49716438c5a8/
containers/ etc-hosts plugins/ volumes/
[root@only-worker-node-3 ~]# ls -l /var/lib/kubelet/pods/2b3d790e-8a8f-4b02-92c5-49716438c5a8/volumes/
total 0
drwxr-xr-x. 3 root root 27 Dec 22 15:50 kubernetes.io~empty-dir
drwxr-xr-x. 3 root root 35 Dec 22 15:50 kubernetes.io~projected
[root@only-worker-node-3 ~]# ls -l /var/lib/kubelet/pods/2b3d790e-8a8f-4b02-92c5-49716438c5a8/volumes/kubernetes.io~empty-dir/test-emptydir/
total 0
# 从pod中创建file
[root@master-worker-node-1 storage]# kubectl exec -it pod-with-volume -- sh
/ # touch /mnt/file-from-pod
/ # ls -l /mnt/
-rw-r--r-- 1 root root 0 Dec 22 08:12 file-from-pod
/ # exit
# 也会在pod所在node目录下存在该文件
[root@master-worker-node-1 storage]# ssh node3
Last login: Thu Dec 22 16:09:05 2022 from 192.168.122.89
[root@only-worker-node-3 ~]# ls -l /var/lib/kubelet/pods/2b3d790e-8a8f-4b02-92c5-49716438c5a8/volumes/kubernetes.io~empty-dir/test-emptydir/
total 0
-rw-r--r--. 1 root root 0 Dec 22 16:12 file-from-pod
#使用emptyDir中的sizeLimit参数时需要注意,如果没有指定emptyDir.medium参数,默认是将使用node节点的块设备。
[root@master-worker-node-1 storage]# kubectl exec -it pod-with-volume -- df -Th | grep mnt
/dev/sda1 xfs 20G 5.9G 15G 30% /mnt
# 如果此时pod在容器中的volume目录下写入的问题超过200M时,将kill pod
[root@master-worker-node-1 storage]# kubectl exec -it pod-with-volume -- dd if=/dev/zero of=/mnt/test bs=1M count=300
300+0 records in
300+0 records out
314572800 bytes (315 MB, 300 MiB) copied, 0.468132 s, 672 MB/s
[root@master-worker-node-1 storage]# kubectl describe pods pod-with-volume | tail
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 112s default-scheduler Successfully assigned default/pod-with-volume to only-worker-node-3
Normal Pulled 111s kubelet Container image "centos" already present on machine
Normal Created 111s kubelet Created container centos
Normal Started 111s kubelet Started container centos
Warning Evicted 19s kubelet Usage of EmptyDir volume "test-emptydir" exceeds the limit "200Mi".
Normal Killing 19s kubelet Stopping container centos
Warning ExceededGracePeriod 9s kubelet Container runtime did not kill the pod within specified grace period.
# 如果指定medium参数为memory时,将占用pod的内存空间,而且主机重启也会造成数据丢失。
[root@master-worker-node-1 storage]# cat 1.yaml | tail -5
volumes:
- emptyDir:
medium: Memory
sizeLimit: 200Mi
name: test
[root@master-worker-node-1 storage]# kubectl apply -f 1.yaml
pod/pod-volume2 created
[root@master-worker-node-1 storage]# kubectl exec -it pod-volume2 -- df -Th | grep mnt
tmpfs tmpfs 200.0M 0 200.0M 0% /mnt
# 此时volume在POd中的目录不能大于200M
[root@master-worker-node-1 storage]# kubectl exec -it pod-volume2 -- dd if=/dev/zero of=/mnt/test bs=1M count=300
dd: error writing '/mnt/test': No space left on device
201+0 records in
200+0 records out
209715200 bytes (200.0MB) copied, 0.317512 seconds, 629.9MB/s
command terminated with exit code 1
[root@master-worker-node-1 storage]# kubectl exec -it pod-volume2 -- ls -lh /mnt
total 200M
-rw-r--r-- 1 root root 200.0M Dec 22 12:56 test
hostPath
hostPath是将主机节点文件系统上的文件或目录挂载到Pod 中,如果pod删除,hostpath中的文件不会被删除。
使用hostPath时需要注意安全问题。同时由于pod的数据存储在单node上,pod在其他node重建将无法访问,可以使用nfs或者其他共享文件系统解决。
type的取值
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
volumeMounts:
- name: index
mountPath: /usr/share/nginx/html/index.html
readOnly: true # 为了安全因素,可以按需开启是否只读
volumes:
- name: index
hostPath:
path: /tmp/index.html
type: File # type取值较多,可以参见上面的截图
[root@master-worker-node-1 storage]# kubectl apply -f hostpath-1.yaml
pod/nginx created
[root@master-worker-node-1 storage]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx 1/1 Running 0 27s 10.244.31.14 only-worker-node-3 <none> <none>
[root@master-worker-node-1 storage]# curl 10.244.31.14
111
NFS
nfs 卷能将 NFS (网络文件系统) 挂载到你的 Pod 中。 不像 emptyDir 那样会在删除 Pod 的同时也会被删除,nfs 卷的内容在删除 Pod 时会被保存,卷只是被卸载。 这意味着 nfs 卷可以被预先填充数据,并且这些数据可以在 Pod 之间共享。
#在node2先运行nfs,把/mnt目录共享出来
[root@master-worker-node-2 ~]# cat >> /etc/exports <<eof
> /mnt *(rw)
> eof
[root@master-worker-node-2 ~]# exportfs
/mnt <world>
apiVersion: v1
kind: Pod
metadata:
name: pod-nfs
spec:
containers:
- name: nginx
image: nginx:stable-alpine-perl
imagePullPolicy: IfNotPresent
volumeMounts:
- mountPath: /usr/share/nginx/html
name: nfs
volumes:
- name: nfs
nfs:
server: 192.168.122.106
path: /mnt
[root@master-worker-node-1 storage]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod-nfs 1/1 Running 0 3m15s 10.244.31.16 only-worker-node-3 <none> <none>
# 在nfs共享目录下添加一个index.html文件
[root@master-worker-node-2 ~]# echo node2-nfs > /mnt/index.html
# 测试发现可以正常访问
[root@master-worker-node-1 storage]# curl 10.244.31.16
node2-nfs
小结
1、emptyDir基本用于测试环境中
2、hostPath和NFS可以结合使用,比如node主机通过NFS挂载某个文件系统,然后将文件系统以hostPath的方式分享给POD,这样克服了hostPath是单个node范围的缺点