挂载传播允许将Container挂载的卷共享到同一Pod中的其他Container,甚至可以共享到同一节点上的其他Pod。一个卷的挂载传播由Container.volumeMounts中的mountPropagation字段控制。它的值是:
None:这种卷挂载将不会收到任何后续由 host
创建的在这个卷上或其子目录上的挂载。同样的, 由容器创建的挂载在 host
上也是不可见的。这是默认的模式。这个其实很好理解, 就是容器内和 host
的后续挂载完全隔离
此模式等同于Linux内核文档中所述的 private 传播。
HostToContainer:此卷挂载将会接收到任何后续挂载到该卷或是挂载到该卷的子目录下的挂载。
换句话说,如果主机在卷挂载中挂载任何内容,则Container将看到它挂载在那里。类似地,如果任何具有 Bidirectional 挂载传播设置的Pod挂载到同一个卷中,那么具有HostToContainer挂载传播的Container将会看到它。此模式等同于Linux内核文档中描述的rslave挂载传播。
Bidirectional:此卷挂载的行为与HostToContainer挂载相同。此外,Container创建的所有卷挂载都将传播回主机和所有使用相同卷的Pod的所有容器。
此模式的典型用例是具有Flexvolume或CSI驱动程序的Pod需要使用hostPath 卷模式 在主机上挂载内容。此模式等同于Linux内核文档中描述的rshared安装传播。
**注意:**Bidirectional 挂载传播可能很危险。它可能会损坏主机操作系统,因此只允许在特权容器中使用它。强烈建议您熟悉Linux内核行为。此外,容器在容器中创建的任何卷装入必须在终止时由容器销毁(卸载)。
Bidirectional一些使用场景:
在不同的pod之间共享设备,其中挂载发生在pod中,但是在pod之间共享。
从容器内部附加设备。例如,从容器内部附加ISCSI设备。这时候因为如果容器死掉,主机将不能获得所需的信息(除非使用双向安装传播)来正确刷新写入和分离设备。
挂载传播流程图
1.mountPropagation: None
apiVersion: v1
kind: Pod
metadata:
name: mount-none
label:
app: mount
spec:
containers:
- name: main
image: nginx:latest
volumeMounts:
- name: testmount
mountPath: /home
mountPropagation: None
volumes:
- name: testmount
hostPath:
path: /mnt/
2.mountPropagation: HostToContainer
apiVersion: v1
kind: Pod
metadata:
name: mount-host
label:
app: mount
spec:
containers:
- name: main
image: nginx:latest
volumeMounts:
- name: testmount
mountPath: /home
mountPropagation: HostToContainer
volumes:
- name: testmount
hostPath:
path: /mnt/
3.mountPropagation: Bidirectional
apiVersion: v1
kind: Pod
metadata:
name: mount-bidir-a
labels:
app: mount
spec:
containers:
- name: main
image: nginx:latest
# Bidirectional 需要开启特权模式才可以使用
securityContext:
privileged: true
volumeMounts:
- name: testmount
mountPath: /home
mountPropagation: Bidirectional
volumes:
- name: testmount
hostPath:
path: /mnt/
---
apiVersion: v1
kind: Pod
metadata:
name: mount-bidir-b
labels:
app: mount
spec:
containers:
- name: main
image: nginx:latest
# Bidirectional 需要开启特权模式才可以使用
securityContext:
privileged: true
volumeMounts:
- name: testmount
mountPath: /home
mountPropagation: Bidirectional
volumes:
- name: testmount
hostPath:
path: /mnt/
上面介绍了 kubernetes 的挂载传播机制, 在 linux mount 中, 也有类似的概念。
mount 分为下面几种:
shared mount:
- 相当于上面所说的 Bidirectional 的挂载传播。slave mount:
- 每个 slave mount 都有一个 shared master mount, 挂载传播只能从 master -> slave
, 等同于上面的 HostToContainer, host 是 master,container 是 slave。private mount:
- 很明显, private 就是相当于 None,挂载不会向任何一方传播。unbindable mount:
- 其实就是 unbindable private mount, 也就是不允许使用 –bind 的挂载。究其深层次分析,该特性并不是k8s或是docker实现的。本质上是mount namespace 的特性。
mount namespace通过隔离文件系统挂载点对隔离文件系统提供支持,它是历史上第一个Linux namespace,所以它的标识位比较特殊,就是CLONE_NEWNS。隔离后,不同mount namespace中的文件结构发生变化也互不影响。你可以通过/proc/[pid]/mounts查看到所有挂载在当前namespace中的文件系统,还可以通过/proc/[pid]/mountstats看到mount namespace中文件设备的统计信息,包括挂载文件的名字、文件系统类型、挂载位置等等。
进程在创建mount namespace时,会把当前的文件结构复制给新的namespace。新namespace中的所有mount操作都只影响自身的文件系统,而对外界不会产生任何影响。这样做非常严格地实现了隔离,但是某些情况可能并不适用。比如父节点namespace中的进程挂载了一张CD-ROM,这时子节点namespace拷贝的目录结构就无法自动挂载上这张CD-ROM,因为这种操作会影响到父节点的文件系统。
2006 年引入的挂载传播(mount propagation)解决了这个问题,挂载传播定义了挂载对象(mount object)之间的关系,系统用这些关系决定任何挂载对象中的挂载事件如何传播到其他挂载对象(参考自:http://www.ibm.com/developerw…)。所谓传播事件,是指由一个挂载对象的状态变化导致的其它挂载对象的挂载与解除挂载动作的事件。
一个挂载状态可能为如下的其中一种:
在默认情况下,所有挂载都是私有的。可以用以下命令将挂载对象显式地标为共享挂载:
mount --make-shared <mount-object>
例如,如果 / 上的挂载必须是共享的,那么执行以下命令:
mount --make-shared /
从共享挂载克隆的挂载对象也是共享的挂载;它们相互传播挂载事件。
通过执行以下命令,可以显式地将一个共享挂载转换为从属挂载:
mount --make-slave <shared-mount-object>
从从属挂载克隆的挂载对象也是从属的挂载,它也从属于原来的从属挂载的主挂载对象。
通过执行以下命令,可以将挂载对象标为私有的:
mount --make-private <mount-object>
通过执行以下命令,可以将挂载对象标为不可绑定的:
mount --make-unbindable <mount-object>
最后,这些设置都可以递归地应用,这意味着它们将应用于目标挂载之下的所有挂载。
mount --make-rshared /
将 / 之下的所有挂载转换为共享挂载。