Kubernetes Volume 数据卷

K8S Volume 概念

我们知道,容器中的磁盘文件是临时的,一旦容器运行结束,其文件也会丢失。如果数据需要长期存储,那就需要对容器数据做持久化支持,在就涉及到 Kubernetes 中的一个核心概念 Volume。 Kubernetes 和 Docker 类似,也是通过 Volume 的方式提供对存储的支持。Kubernetes 中 的 Volume 与 Docker 中的 Volume 类似,主要的区别如下:

  • 1、Kubernetes 中的 Volume 被定义到 Pod 层面,Volume 可以被 Pod 中的多个容器挂载到相同或不同的路径。
  • 2、Kubernetes 中的 Volume 与 Pod 的生命周期相同,但与容器的生命周期不相关。当容器终止或重启时,Volume 中的数据不会丢失
  • 3、当 Pod 被删除时,Volume 才会被清理。并且数据是否丢失取决于 Volume 的具体类型,比如:emptyDir 类型的 Volume 数据会丢失,而 PV 类型的数据则不会丢失。

Volume 的本质是一个目录,其中可以包含数据,Pod 中的容器可以访问该目录。该目录的形式,支持该目录的介质以及目录的内容取决于所使用的特定卷类型。 Kubernetes 目前支持多种 Volume 类型,我们按照使用环境来简单分类:

  • 本地卷:emptyDir, hostPath 等
  • 网络卷:NFS, Ceph, GlusterFS 等
  • 公有云对象存储:AWS, EBS, OSS等
  • K8S资源:configmap, secret 等

这里只提到了一些常用的Volume类型,更多详见官网文档

常见 Volume 类型1:emptyDir

什么是 emptyDir:

emptyDir 与 Pod 的生命周期完全一致,它在 Pod 分配到 node 上时被创建,Kubernetes 会在 node 上自动分配一个目录,因此无需指定 node 宿主机上对应的目录文件。这个目录的初始内容为空,当 Pod 从 node 上移除(Pod 被删除或者 Pod 发生迁移)时,emptyDir 中的数据会被永久删除。

emptyDir 的使用场景:

emptyDir Volume 主要用于某些应用程序无需永久保存的临时目录,或者在 Pod 中的多个容器之间共享数据等。

emptryDir 默认使用主机磁盘进行存储的,也可以使用其它介质作为存储,比如:网络存储、内存等,设置 emptyDir.medium 字段的值为 Memory 就可以使用内存进行存储。

Demo:Pod 中容器之间的数据共享

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
---
apiVersion: v1
kind: Pod
metadata:
name: pod-demo-emptydir
namespace: default
spec:
containers:
- name: write
image: nginx:1.16.1
command: ["bash","-c","for i in {1..100};do echo $i >> /data/hello;sleep 1;done"]
volumeMounts:
- name: data # 挂载卷名为 data 到容器内 /data 位置点
mountPath: /data

- name: read
image: nginx:1.16.1
command: ["bash","-c","tail -f /data/hello"]
volumeMounts:
- name: data # 挂载卷名为 data 到容器内 /data 位置点
mountPath: /data

# 创建一个 emptyDir 类型的‘本地临时数据卷’,卷名为 data
volumes:
- name: data
emptyDir: {}

Demo 中 Pod 内的两个容器同时挂载了 emptyDir 卷,使得两个容器内部数据共享。

emptyDir 对应宿主机文件系统的位置:

emptyDir 实际上是在 Pod 所在的 node 节点的宿主机上开辟一块磁盘空间,挂载到 Pod 供容器使用。

可以在 Pod 所在 node 的 /var/lib/kubelet/pods 路径下找到随机字符串目录,随机字符串就是 CONTAINER_NAME 后缀部分自动生成的串,可以通过 docker container ls 查看到

k8s将在1.23版本彻底弃用docker,改用containerd,但Docker 作为容器镜像构建工具的作用将不受影响,用其构建的容器镜像将一如既往地在集群中与所有容器运行时正常运转。

1
2
3
4
5
6
ctr -n k8s.io c ls

f4cfc3a54362dd1f26c63c67e7af1965df34e54cd17d91ed15d353e90c7b417b docker.io/library/nginx:1.16.1 io.containerd.runc.v2

ctr -n k8s.io container info f37f2fac3ff0f7ba6f6a43c06f7deb82387f3581c2f6607c133997f127b71119

1
2
3
4
5
6
7
8
# 得到串:f6da3004-314a-4fb2-b566-3886831fdc6c

# 看到宿主机外部的挂载点位置
$ pwd
/var/lib/kubelet/pods/f6da3004-314a-4fb2-b566-3886831fdc6c/volumes/kubernetes.io~empty-dir/data
$ ls -l
total 4
-rw-r--r--. 1 root root 1559 May 13 16:38 hello

常见 Volume 类型2:hostPath

Kubernetes Volumes hostPath

hostPath 类型的 Volume 允许挂载 node 节点上的文件或目录到 Pod 中,不过 hostPath 类型的 Volume 很少被使用,因为每个 node 节点上的文件可能不同,最终导致一组 Pod (如 Deployment )在不同 node 节点上的行为可能会有所不同,且 Pod 一旦被调度其他 node 节点会导致数据错乱。另外要在 node 节点上创建的文件或目录写入内容,需要在容器中以 root 身份运行进程,存在一定的安全隐患。

Demo:Pod 中容器需要访问宿主机文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
---
apiVersion: v1
kind: Pod
metadata:
name: pod-demo-hostpath
namespace: default
spec:
containers:
- name: pod-demo-hostpath
image: nginx:1.16.1
volumeMounts:
- name: data1 # volume名称
mountPath: /data # 容器内的位置

- name: data2
mountPath: /tmp/test.txt

volumes:
- name: data1 # volume名称
hostPath:
path: /data
type: Directory # 挂载类型为目录

- name: data2 # volume名称
hostPath:
path: /tmp/test.txt
type: File # 挂载类型为文件

常见 Volume 类型3:nfs

NFS 是一个主流的文件共享服务器。

nfs volume 提供对 NFS 挂载支持,可以自动将 NFS 共享路径挂载到 Pod 中。

Demo:Pod 挂载 nfs volume
NFS Server 配置:

1
2
3
4
5
6
7
8
# nfs-server 配置
$ vim /etc/exports
/ifs/kubernetes *(rw,no_root_squash)

# nfs client测试挂载nfs
$ yum install nfs-utils -y # 所有 node 安装
$ mount -t nfs 192.168.99.105:/ifs/kubernetes /mnt
$ umount /mnt # 卸载挂载测试

Pod 挂载 nfs 数据卷

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: volume-demo-nfs
namespace: default
spec:
replicas: 3
selector:
matchLabels:
app: volume-demo-nfs
template:
metadata:
labels:
app: volume-demo-nfs
spec:
containers:
- name: volume-demo-nfs
image: nginx:1.16.1
volumeMounts:
- name: wwwroot # volume名称
mountPath: /usr/share/nginx/html # 容器内路径

volumes:
- name: wwwroot # volume名称
nfs:
server: 192.168.99.105 # nfs server ip
path: /ifs/kubernetes # nfs 配置

参考资料