挂载是指将定义在 Pod 中的数据卷关联到容器,同一个 Pod 中的同一个数据卷可以被挂载到该 Pod 中的多个容器上。
数据卷内子路径
有时候我们需要在同一个 Pod 的不同容器间共享数据卷。使用 volumeMounts.subPath
属性,可以使容器在挂载数据卷时指向数据卷内部的一个子路径,而不是直接指向数据卷的根路径。
下面的例子中,一个 LAMP(Linux Apache Mysql PHP)应用的 Pod 使用了一个共享数据卷,HTML 内容映射到数据卷的 html
目录,数据库的内容映射到了 mysql
目录:
apiVersion: v1
kind: Pod
metadata:
name: my-lamp-site
spec:
containers:
- name: mysql
image: mysql
env:
- name: MYSQL_ROOT_PASSWORD
value: "rootpasswd"
volumeMounts:
- mountPath: /var/lib/mysql
name: site-data
subPath: mysql
readOnly: false
- name: php
image: php:7.0-apache
volumeMounts:
- mountPath: /var/www/html
name: site-data
subPath: html
readOnly: false
volumes:
- name: site-data
persistentVolumeClaim:
claimName: my-lamp-site-data
apiVersion: v1
: 这指定了使用的 Kubernetes API 版本,表示该配置文件遵循的 Kubernetes API 的版本。kind: Pod
: 这表明我们正在定义一个 Pod 对象。metadata
: 这是 Pod 对象的元数据部分,包含关于该 Pod 的信息,比如名称(name
)。name: my-lamp-site
: 这是 Pod 对象的名称。在这个例子中,它命名为 "my-lamp-site"。spec
: 这是 Pod 对象的规范部分,定义了实际的 Pod 规则。containers
: 这是一个包含容器定义的列表。image: php:7.0-apache
: 这指定了该容器要使用的 Docker 镜像,这里使用的是带有 Apache 的 PHP 7.0 镜像。volumeMounts
: 这是一个挂载卷的列表。mountPath: /var/www/html
: 这是卷要挂载到容器中的路径,表示 PHP 代码将被存储在这个路径下。name: site-data
: 这是要挂载的卷的名称,与下面volumes
中的定义对应。subPath: html
: 这是卷在容器中挂载的子路径,表示 PHP 代码将存储在/var/www/html/html
路径下。readOnly: false
: 这表示卷是否以只读模式挂载。这里设置为 false,表示 PHP 容器可以对卷进行读写操作。image: mysql
: 这指定了该容器要使用的 Docker 镜像,这里使用的是 MySQL 官方镜像。env
: 这是一个环境变量列表。volumeMounts
: 这是一个挂载卷的列表。name: MYSQL_ROOT_PASSWORD
: 这是一个环境变量的名称,表示 MySQL 的 root 用户的密码。value: "rootpasswd"
: 这是MYSQL_ROOT_PASSWORD
环境变量的值,设置为 "rootpasswd"。mountPath: /var/lib/mysql
: 这是卷要挂载到容器中的路径,表示 MySQL 数据库文件将被存储在这个路径下。name: site-data
: 这是要挂载的卷的名称,与下面volumes
中的定义对应。subPath: mysql
: 这是卷在容器中挂载的子路径,表示 MySQL 数据将存储在/var/lib/mysql/mysql
路径下。readOnly: false
: 这表示卷是否以只读模式挂载。这里设置为 false,表示 MySQL 容器可以对卷进行读写操作。name: mysql
: 这是第一个容器的名称。name: php
: 这是第二个容器的名称。
volumes
: 这是一个包含持久化存储卷定义的列表。persistentVolumeClaim
: 这是一个持久卷声明(PersistentVolumeClaim)的定义,它将请求一个已经存在的持久化存储资源,该资源必须事先在 Kubernetes 中定义。claimName: my-lamp-site-data
: 这是持久卷声明的名称,它表示这个 Pod 请求使用名称为 "my-lamp-site-data" 的持久化存储卷。name: site-data
: 这是持久化存储卷的名称,与上面containers
中的volumeMounts
对应。
该 Pod 使用 subPathExpr
在 hostPath 数据卷 /var/log/pods
中创建了一个目录 pod1
(该参数来自于Pod的名字)。此时,宿主机目录 /var/log/pods/pod1
挂载到了容器的 /logs
路径:
apiVersion: v1
kind: Pod
metadata:
name: pod1
spec:
containers:
- name: container1
env:
- name: POD_NAME
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.name
image: busybox
command: [ "sh", "-c", "while [ true ]; do echo 'Hello'; sleep 10; done | tee -a /logs/hello.txt" ]
volumeMounts:
- name: workdir1
mountPath: /logs
subPathExpr: $(POD_NAME)
readOnly: false
restartPolicy: Never
volumes:
- name: workdir1
hostPath:
path: /var/log/pods
容器内路径
mountPath
数据卷被挂载到容器的路径,不能包含 :
权限
容器对挂载的数据卷是否具备读写权限,如果 readOnly
为 true
,则只读,否则可以读写(为 false
或者不指定)。默认为 false
挂载传播
数据卷的挂载传播(Mount Propagation)由 Pod 的 spec.containers[*].volumeMounts.mountPropagation
字段控制。可选的取值有:
- None: 默认值。在数据卷被挂载到容器之后,此数据卷不会再接受任何后续宿主机或其他容器挂载到该数据卷对应目录下的子目录的挂载。同样的,在容器中向该数据卷对应目录挂载新目录时,宿主机也不能看到。对应 Linux 的
private
mount propagation 选项 Linux内核文档(opens new window) - HostToContainer:在数据卷被挂载到容器之后,宿主机向该数据卷对应目录添加挂载时,对容器是可见的。对应 Linux 的
rslave
mount propagation 选项 Linux内核文档(opens new window) - Bidirectional:在数据卷被挂载到容器之后,宿主机向该数据卷对应目录添加挂载时,对容器是可见的;同时,从容器中向该数据卷创建挂载,同样也对宿主机可见。对应 Linux 的
rshared
mount propagation 选项 Linux内核文档
Bidirectional mount propagation 选项隐藏风险。如果在容器内进行不合适的挂载,可能影响宿主机的操作系统正常执行,因此,只有 privileged 容器才可以使用该选项。使用此选项时,建议对 Linux 内核的行为有所熟悉。此外,使用 Bidirectional 选项时,任何由 Pod 中容器在对应数据卷目录创建的挂载必须在容器终止时销毁(umounted)。
额外配置
在部分系统中(CoreOS、RedHat/Centos、Ubuntu),Docker 的 mount share 选项必须事先配置好,步骤如下:
- 编辑 Docker 的
systemd
service 文件,将MountFlags
设定如下: MountFlags=shared 或者移除MountFlags=slave
- 重启 Docker 守护进程: sudo systemctl daemon-reload sudo systemctl restart docker