k8s 中存储之 emptyDir 卷
目录
1 kubernets支持的卷的类型
2 emptyDir 卷介绍
2.1 emptyDir 的使用场景:
2.2 emptyDir 卷的功能:
3 emptyDir 卷实现容器间数据共享
3.1 实验介绍
3.2 创建 Pod 清单文件
3.3 修改 Pod 清单文件
3.4 声明清单文件并查看 Pod 是否正确创建
3.5 修改容器内的配置实现容器间数据共享性
3.6 测试同一个 Pod 之间数据是否共享
1 kubernets支持的卷的类型
官网:卷 | Kubernetes容器中的文件在磁盘上是临时存放的,这给在容器中运行较重要的应用带来一些问题。 当容器崩溃或停止时会出现一个问题。此时容器状态未保存, 因此在容器生命周期内创建或修改的所有文件都将丢失。 在崩溃期间,kubelet 会以干净的状态重新启动容器。 当多个容器在一个 Pod 中运行并且需要共享文件时,会出现另一个问题。 跨所有容器设置和访问共享文件系统具有一定的挑战性。Kubernetes 卷(Volume) 这一抽象概念能够解决这两个问题。阅读本文前建议你熟悉一下 Pod。背景 Kubernetes 支持很多类型的卷。 Pod 可以同时使用任意数目的卷类型。 临时卷类型的生命周期与 Pod 相同, 但持久卷可以比 Pod 的存活期长。 当 Pod 不再存在时,Kubernetes 也会销毁临时卷;不过 Kubernetes 不会销毁持久卷。 对于给定 Pod 中任何类型的卷,在容器重启期间数据都不会丢失。卷的核心是一个目录,其中可能存有数据,Pod 中的容器可以访问该目录中的数据。 所采用的特定的卷类型将决定该目录如何形成的、使用何种介质保存数据以及目录中存放的内容。使用卷时, 在 .spec.volumes 字段中设置为 Pod 提供的卷,并在 .spec.containers[*].volumeMounts 字段中声明卷在容器中的挂载位置。 容器中的进程看到的文件系统视图是由它们的容器镜像 的初始内容以及挂载在容器中的卷(如果定义了的话)所组成的。 其中根文件系统同容器镜像的内容相吻合。 任何在该文件系统下的写入操作,如果被允许的话,都会影响接下来容器中进程访问文件系统时所看到的内容。卷挂载在镜像中的指定路径下。 Pod 配置中的每个容器必须独立指定各个卷的挂载位置。卷不能挂载到其他卷之上(不过存在一种使用 subPath 的相关机制),也不能与其他卷有硬链接。卷类型 Kubernetes 支持下列类型的卷:awsElasticBlockStore (已弃用) 在 Kubernetes 1.31 中,所有针对树内 awsElasticBlockStore 类型的操作都会被重定向到 ebs.csi.aws.com CSI 驱动。https://kubernetes.io/zh/docs/concepts/storage/volumes/
k8s支持的卷的类型如下:
-
awsElasticBlockStore 、azureDisk、azureFile、cephfs、cinder、configMap、csi
-
downwardAPI、emptyDir、fc (fibre channel)、flexVolume、flocker
-
gcePersistentDisk、gitRepo (deprecated)、glusterfs、hostPath、iscsi、local、
-
nfs、persistentVolumeClaim、projected、portworxVolume、quobyte、rbd
-
scaleIO、secret、storageos、vsphereVolume
2 emptyDir 卷介绍
2.1 emptyDir 的使用场景:
-
缓存空间,例如基于磁盘的归并排序。
-
耗时较长的计算任务提供检查点,以便任务能方便地从崩溃前状态恢复执行。
-
在 Web 服务器容器服务数据时,保存内容管理器容器获取的文件。
2.2 emptyDir 卷的功能:
当Pod指定到某个节点上时,首先创建的是一个emptyDir卷,并且只要 Pod 在该节点上运行,卷就一直存在。卷最初是空的。 尽管 Pod 中的容器挂载 emptyDir 卷的路径可能相同也可能不同,但是这些容器都可以读写 emptyDir 卷中相同的文件。 当 Pod 因为某些原因被从节点上删除时,emptyDir 卷中的数据也会永久删除
emptyDir 用于在 Pod 中实现容器之间的数据共享。与Pod的生命周期一致,当 Pod 被删除时,这个目录页会被删除。
例如,如果在一个 Pod 中有两个容器,其中一个容器需要读取另一个容器中的数据,那么这可以使用emptyDir 卷来实现。容器之间的数据共享如下图所示
3 emptyDir 卷实现容器间数据共享
3.1 实验介绍
使用两个容器组成一个 Pod 用 emptyDir 卷 实现 同 Pod 之间的数据共享
使用 busybox 和 nginx 容器 组成一个Pod
3.2 创建 Pod 清单文件
命令只支持单一容器的Pod创建。对于多容器的Pod 只能手动添加第二个容器的部分。
[root@k8s-master volumes]# kubectl run emptydir \
--image busyboxplus:latest \
--dry-run=client -o yaml > emptydir.yml
3.3 修改 Pod 清单文件
同样的volumes卷也不支持使用命令创建 只能增加 volumes 卷相应配置
apiVersion: v1
kind: Pod
metadata:labels:run: emptydirname: emptydir
spec:volumes:# 这里定义了一个名为 cache-vol 的存储卷,并且指定了其类型为 emptyDir# emptyDir 类型的卷会在 Pod 被调度到节点上时自动创建,# 如果 Pod 重新调度到另一个节点,数据会被保留。- name: cache-volemptyDir:medium: "" # 这里可以指定存储介质,如 memory 或者默认的磁盘存储。留空表示使用默认设置。sizeLimit: 1Gi # 这里设置了卷的最大大小限制为 1GiBcontainers:# 第一个容器,使用 busyboxplus 镜像- image: busyboxplus:latestname: vm-1command: ["/bin/sh","-c","sleep 30000000"] # 这里设置了一个长延时命令,使得容器持续运行volumeMounts:# 将前面定义的 cache-vol 卷挂载到容器内的 /cache 路径- mountPath: /cachename: cache-vol# 第二个容器,使用 nginx 镜像- image: nginx:latestname: vm-2volumeMounts:# 同样的 cache-vol 卷也被挂载到第二个容器内的 /usr/share/nginx/html 路径# 这样两个容器就可以共享这个卷中的数据了- mountPath: /usr/share/nginx/htmlname: cache-vol
3.4 声明清单文件并查看 Pod 是否正确创建
[root@k8s-master volumes]# kubectl apply -f emptydir.yml [root@k8s-master volumes]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
emptydir 2/2 Running 0 100s 10.244.2.62 k8s-node2 <none> <none>
nginx-v1-dbd4bc45b-49hhw 1/1 Running 0 3d17h 10.244.2.54 k8s-node2 <none> <none>
nginx-v2-bd85b8bc4-nqpv2 1/1 Running 0 3d17h 10.244.1.35 k8s-node1 <none> <none>
testpod 0/1 Completed 0 3d4h 10.244.2.58 k8s-node2 <none> <none># 查看详细信息
[root@k8s-master volumes]# kubectl describe pods emptydir
Name: emptydir
Namespace: default
Priority: 0
Service Account: default
Node: k8s-node2/192.168.239.120
Start Time: Sun, 06 Oct 2024 15:36:13 +0800
Labels: run=emptydir
Annotations: <none>
Status: Running
IP: 10.244.2.62
IPs:IP: 10.244.2.62
Containers:vm-1:Container ID: docker://3753f0470e30bc30302cd6dbf6a53f7ad2d870a6b35a537816091b3c993441d4Image: busyboxplus:latestImage ID: docker-pullable://busyboxplus@sha256:9d1c242c1fd588a1b8ec4461d33a9ba08071f0cc5bb2d50d4ca49e430014ab06Port: <none>Host Port: <none>Command:/bin/sh-csleep 30000000State: RunningStarted: Sun, 06 Oct 2024 15:36:14 +0800Ready: TrueRestart Count: 0Environment: <none>Mounts:/cache from cache-vol (rw)/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-jnl6t (ro)vm-2:Container ID: docker://0596c82e0e086cf4cc2d668c271067332211d0d439695f2419f1385d03caaa09Image: nginx:latestImage ID: docker-pullable://nginx@sha256:127262f8c4c716652d0e7863bba3b8c45bc9214a57d13786c854272102f7c945Port: <none>Host Port: <none>State: RunningStarted: Sun, 06 Oct 2024 15:36:15 +0800Ready: TrueRestart Count: 0Environment: <none>Mounts:/usr/share/nginx/html from cache-vol (rw)/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-jnl6t (ro)
Conditions:Type StatusPodReadyToStartContainers True Initialized True Ready True ContainersReady True PodScheduled True
Volumes:cache-vol:Type: EmptyDir (a temporary directory that shares a pod's lifetime)Medium: SizeLimit: <unset>kube-api-access-jnl6t:Type: Projected (a volume that contains injected data from multiple sources)TokenExpirationSeconds: 3607ConfigMapName: kube-root-ca.crtConfigMapOptional: <nil>DownwardAPI: true
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300snode.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:Type Reason Age From Message---- ------ ---- ---- -------Normal Scheduled 118s default-scheduler Successfully assigned default/emptydir to k8s-node2Normal Pulling 117s kubelet Pulling image "busyboxplus:latest"Normal Pulled 117s kubelet Successfully pulled image "busyboxplus:latest" in 89ms (89ms including waiting). Image size: 12855024 bytes.Normal Created 117s kubelet Created container vm-1Normal Started 117s kubelet Started container vm-1Normal Pulling 117s kubelet Pulling image "nginx:latest"Normal Pulled 117s kubelet Successfully pulled image "nginx:latest" in 75ms (75ms including waiting). Image size: 187694648 bytes.Normal Created 117s kubelet Created container vm-2Normal Started 116s kubelet Started container vm-2# 测试 Pod 是否可以访问,由于是新的卷挂载上去会覆盖了原先的nginx里的index.html
[root@k8s-master volumes]# curl 10.244.2.62
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.27.1</center>
</body>
</html>
3.5 修改容器内的配置实现容器间数据共享性
# 进入 busyboxplus 容器
[root@k8s-master volumes]# kubectl exec -it pods/emptydir -c vm-1 -- /bin/sh
/ # ls
bin cache dev etc home lib lib64 linuxrc media mnt opt proc root run sbin sys tmp usr var
/ # cd cache/# 增加一个 index.html 文件
# 注意:在这里添加文件就相当于在 nginx 容器 /usr/share/nginx/html/ 中添加文件
# 因为选择的 emptyDir 卷是同一个,这样就实现了容器间数据的共享性
/cache # echo this is at vm-1 container write nginx html file apply to vm-2 container > index.html# ctrl + pq 退出这个容器
/cache # exec attach failed: error on attach stdin: read escape sequence
command terminated with exit code 126# 进入 nginx 容器
[root@k8s-master volumes]# kubectl exec -it pods/emptydir -c vm-2 -- /bin/sh
# ls
bin boot dev docker-entrypoint.d docker-entrypoint.sh etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var# 查看 nginx 容器中的 index.html 是否存在
# ls /usr/share/nginx/html
index.html
3.6 测试同一个 Pod 之间数据是否共享
# 查看 Pod 的IP地址
[root@k8s-master volumes]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
emptydir 2/2 Running 0 8m1s 10.244.2.62 k8s-node2 <none> <none>
nginx-v1-dbd4bc45b-49hhw 1/1 Running 0 3d17h 10.244.2.54 k8s-node2 <none> <none>
nginx-v2-bd85b8bc4-nqpv2 1/1 Running 0 3d17h 10.244.1.35 k8s-node1 <none> <none>
testpod 0/1 Completed 0 3d4h 10.244.2.58 k8s-node2 <none> <none># 访问 Pod
[root@k8s-master volumes]# curl 10.244.2.62
this is at vm-1 container write nginx html file apply to vm-2 container# 进入 busyboxplus 中访问本地发现去访问了 nginx ,这是因为同一个 Pod 之间的网络是共享的,
# 他们处于同一个网络栈中,实现了 Pod 之间的网络共享性
[root@k8s-master volumes]# kubectl exec -it pods/emptydir -c vm-1 -- /bin/sh/ # curl localhost
this is at vm-1 container write nginx html file apply to vm-2 container