1. 卷
Container 中的文件在磁盘上是临时存放的,这给 Container 中运行的较重要的应用程序带来一些问题。
问题:
第一:是当容器崩溃时文件丢失。 kubelet 会重新启动容器,但容器会以干净的状态重启。
第二:在同一 Pod 中运行多个容器并共享文件时出现。
Kubernetes 卷(Volume) 这一抽象概念能够解决这两个问题。
2. 背景
Docker 也有卷(Volume) 的概念,但对它只有少量且松散的管理。 Docker 卷是磁盘上或者另外一个容器内的一个目录。 Docker 提供卷驱动程序,但是其功能非常有限。
Kubernetes 支持很多类型的卷。 Pod 可以同时使用任意数目的卷类型。 临时卷类型的生命周期与 Pod 相同,但持久卷可以比 Pod 的存活期长。 当 Pod 不再存在时,Kubernetes 也会销毁临时卷;不过 Kubernetes 不会销毁持久卷。 对于给定 Pod 中任何类型的卷,在容器重启期间数据都不会丢失。
卷的核心是一个目录,其中可能存有数据,Pod 中的容器可以访问该目录中的数据。 所采用的特定的卷类型将决定该目录如何形成的、使用何种介质保存数据以及目录中存放的内容。
使用卷时, 在 .spec.volumes 字段中设置为 Pod 提供的卷,并在 .spec.containers[*].volumeMounts 字段中声明卷在容器中的挂载位置。 容器中的进程看到的文件系统视图是由它们的容器镜像 的初始内容以及挂载在容器中的卷(如果定义了的话)所组成的。 其中根文件系统同容器镜像的内容相吻合。 任何在该文件系统下的写入操作,如果被允许的话,都会影响接下来容器中进程访问文件系统时所看到的内容。
卷挂载在镜像中的指定路径下。 Pod 配置中的每个容器必须独立指定各个卷的挂载位置。
卷不能挂载到其他卷之上(不过存在一种使用 subPath 的相关机制),也不能与其他卷有硬链接。
3. emptyDir
当 Pod 分派到某个节点上时,emptyDir 卷会被创建,并且在 Pod 在该节点上运行期间,卷一直存在。 就像其名称表示的那样,卷最初是空的。 尽管 Pod 中的容器挂载 emptyDir 卷的路径可能相同也可能不同,这些容器都可以读写 emptyDir 卷中相同的文件。 当 Pod 因为某些原因被从节点上删除时,emptyDir 卷中的数据也会被永久删除。
你可以通过为默认介质指定大小限制,来限制 emptyDir 卷的存储容量。 此存储是从节点临时存储中分配的。 如果来自其他来源(如日志文件或镜像分层数据)的数据占满了存储,emptyDir 可能会在达到此限制之前发生存储容量不足的问题。
4. emptyDir 配置示例
cat > emptyDir.yaml <<EOF
apiVersion: v1
kind: Pod
metadata:
name: emptydir-pod
spec:
containers:
- image: nginx:latest
name: emptydir-pod
imagePullPolicy: IfNotPresent
volumeMounts:
- mountPath: /cache
name: cache-volume
volumes:
- name: cache-volume
emptyDir:
sizeLimit: 500Mi
EOF
5. 进入容器验证
[root@k8s-master ~]# kubectl get pods -o wide #看到调度到k8s-master节点(因为我只有master节点)
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
emptydir-pod 1/1 Running 0 57s 10.244.235.250 k8s-master <none> <none>
[root@k8s-master ~]# kubectl get pods -o yaml|grep uid #过滤临时目录
uid: 472d7d09-71a5-4873-a080-be72695876dd
[root@k8s-master ~]# yum -y install tree #安装这个工具要用到
[root@k8s-master ~]# tree /var/lib/kubelet/pods/472d7d09-71a5-4873-a080-be72695876dd #用刚才查看到uid在固定的这个目录下查询
/var/lib/kubelet/pods/472d7d09-71a5-4873-a080-be72695876dd
├── containers
│ └── emptydir-pod
│ └── fd93bebf
├── etc-hosts
├── plugins
│ └── kubernetes.io~empty-dir
│ ├── cache-volume
│ │ └── ready
│ └── wrapped_default-token-vkfcz
│ └── ready
└── volumes
├── kubernetes.io~empty-dir
│ └── cache-volume
└── kubernetes.io~secret
└── default-token-vkfcz
├── ca.crt -> ..data/ca.crt
├── namespace -> ..data/namespace
└── token -> ..data/token
11 directories, 7 files
[root@k8s-master ~]# cd /var/lib/kubelet/pods/472d7d09-71a5-4873-a080-be72695876dd/volumes/kubernetes.io~empty-dir/cache-volume #进入pod临时目录
[root@k8s-master cache-volume]# echo "my 微信 is mqq759035366" > chat.txt #写一个文件,一会在宿主机的目录下查看
[root@k8s-master cache-volume]#
[root@k8s-master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
emptydir-pod 1/1 Running 0 26m
[root@k8s-master ~]# kubectl exec -it emptydir-pod -- /bin/bash #进入pod容器
root@emptydir-pod:/# ls
bin boot cache dev docker-entrypoint.d docker-entrypoint.sh etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
root@emptydir-pod:/# cd /cache #进入宿主机挂在目录下
root@emptydir-pod:/cache# ls #查看到了刚才的文件
chat.txt
root@emptydir-pod:/cache# cat chat.txt #文件内容和pod容器中的一致
my 微信 is mqq759035366
root@emptydir-pod:/cache#