From 308bbebb8353cc9cc23ebad8024b13a2da3619ab Mon Sep 17 00:00:00 2001 From: AdamDang Date: Fri, 28 Dec 2018 10:51:59 +0800 Subject: [PATCH] zh-trans: add /docs/concepts/storage/volumes.md (#11767) * zh-trans: add /docs/concepts/storage/volumes.md zh-trans: add /docs/concepts/storage/volumes.md * Update volumes.md * Update volumes.md * self-review * Update volumes.md --- content/zh/docs/concepts/storage/volumes.md | 2093 +++++++++++++++++++ 1 file changed, 2093 insertions(+) create mode 100644 content/zh/docs/concepts/storage/volumes.md diff --git a/content/zh/docs/concepts/storage/volumes.md b/content/zh/docs/concepts/storage/volumes.md new file mode 100644 index 0000000000..7288ac10a1 --- /dev/null +++ b/content/zh/docs/concepts/storage/volumes.md @@ -0,0 +1,2093 @@ +--- +reviewers: +- jsafrane +- saad-ali +- thockin +- msau42 +title: Volumes +content_template: templates/concept +weight: 10 +--- + +{{% capture overview %}} + + + +容器中的文件在磁盘上是临时存放的,这给容器中运行的特殊应用程序带来一些问题。 +首先,当容器崩溃时,kubelet 将重新启动容器,容器中的文件将会丢失——因为容器会以干净的状态重建。 +其次,当在一个 `Pod` 中同时运行多个容器时,常常需要在这些容器之间共享文件。 +Kubernetes 抽象出 `Volume` 对象来解决这两个问题。 + + + +阅读本文前建议您熟悉一下 [Pods](/docs/user-guide/pods)。 + +{{% /capture %}} + + +{{% capture body %}} + + + +## 背景 + +Docker 也有 [Volume](https://docs.docker.com/engine/admin/volumes/) 的概念,但对它只有少量且松散的管理。 +在 Docker 中,Volume 是磁盘上或者另外一个容器内的一个目录。 +直到最近,Docker 才支持对基于本地磁盘的 Volume 的生存期进行管理。 +虽然 Docker 现在也能提供 Volume 驱动程序,但是目前功能还非常有限(例如,截至 Docker 1.7,每个容器只允许有一个 Volume 驱动程序,并且无法将参数传递给卷)。 + + + +另一方面,Kubernetes 卷具有明确的生命周期——与包裹它的 Pod 相同。 +因此,卷比 Pod 中运行的任何容器的存活期都长,在容器重新启动时数据也会得到保留。 +当然,当一个 Pod 不再存在时,卷也将不再存在。也许更重要的是,Kubernetes 可以支持许多类型的卷,Pod 也能同时使用任意数量的卷。 + + + +卷的核心是包含一些数据的目录,Pod 中的容器可以访问该目录。 +特定的卷类型可以决定这个目录如何形成的,并能决定它支持何种介质,以及目录中存放什么内容。 + + + + +使用卷时, Pod 声明中需要提供卷的类型 (`.spec.volumes` 字段)和卷挂载的位置 (`.spec.containers.volumeMounts` 字段). + + + +容器中的进程能看到由它们的 Docker 镜像和卷组成的文件系统视图。 +[Docker 镜像](https://docs.docker.com/userguide/dockerimages/) 位于文件系统层次结构的根部,并且任何 Volume 都挂载在镜像内的指定路径上。 +卷不能挂载到其他卷,也不能与其他卷有硬链接。 +Pod 中的每个容器必须独立地指定每个卷的挂载位置。 + + + +## Volume 的类型 + +Kubernetes 支持下列类型的卷: + + + * [awsElasticBlockStore](#awselasticblockstore) + * [azureDisk](#azuredisk) + * [azureFile](#azurefile) + * [cephfs](#cephfs) + * [configMap](#configmap) + * [csi](#csi) + * [downwardAPI](#downwardapi) + * [emptyDir](#emptydir) + * [fc (fibre channel)](#fc) + * [flocker](#flocker) + * [gcePersistentDisk](#gcepersistentdisk) + * [gitRepo (deprecated)](#gitrepo) + * [glusterfs](#glusterfs) + * [hostPath](#hostpath) + * [iscsi](#iscsi) + * [local](#local) + * [nfs](#nfs) + * [persistentVolumeClaim](#persistentvolumeclaim) + * [projected](#projected) + * [portworxVolume](#portworxvolume) + * [quobyte](#quobyte) + * [rbd](#rbd) + * [scaleIO](#scaleio) + * [secret](#secret) + * [storageos](#storageos) + * [vsphereVolume](#vspherevolume) + + + +我们欢迎大家贡献其他的卷类型支持。 + +### awsElasticBlockStore {#awselasticblockstore} + + + +`awsElasticBlockStore` 卷将 Amazon Web服务(AWS)[EBS 卷](http://aws.amazon.com/ebs/) 挂载到您的 Pod 中。 +与 `emptyDir` 在删除 Pod 时会被删除不同,EBS 卷的内容在删除 Pod 时会被保留,卷只是被卸载掉了。 +这意味着 EBS 卷可以预先填充数据,并且可以在 Pod 之间传递数据。 + +{{< caution >}} + +您在使用 EBS 卷之前必须先创建它,可以使用 `aws ec2 create-volume` 命令进行创建;也可以使用 AWS API 进行创建。 +{{< /caution >}} + + + +使用 `awsElasticBlockStore` 卷时有一些限制: + +* Pod 正在运行的节点必须是 AWS EC2 实例。 +* 这些实例需要与 EBS 卷在相同的地域(region)和可用区(availability-zone)。 +* EBS 卷只支持被挂载到单个 EC2 实例上。 + + + +#### 创建 EBS 卷 + +在将 EBS 卷用到 Pod 上之前,您首先要创建它。 + +```shell +aws ec2 create-volume --availability-zone=eu-west-1a --size=10 --volume-type=gp2 +``` + + + +确保该区域与您的群集所在的区域相匹配。(也要检查卷的大小和 EBS 卷类型都适合您的用途!) + + + +#### AWS EBS 配置示例 + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: test-ebs +spec: + containers: + - image: k8s.gcr.io/test-webserver + name: test-container + volumeMounts: + - mountPath: /test-ebs + name: test-volume + volumes: + - name: test-volume + # This AWS EBS volume must already exist. + awsElasticBlockStore: + volumeID: + fsType: ext4 +``` + +### azureDisk {#azuredisk} + + + +`azureDisk` 用来在 Pod 上挂载 Microsoft Azure [数据盘(Data Disk)](https://azure.microsoft.com/en-us/documentation/articles/virtual-machines-linux-about-disks-vhds/) . +更多详情请参考[这里](https://github.com/kubernetes/examples/tree/{{< param "githubbranch" >}}/staging/volumes/azure_disk/README.md)。 + +### azureFile {#azurefile} + + + +`azureFile` 用来在 Pod 上挂载 Microsoft Azure 文件卷(File Volume) (SMB 2.1 和 3.0)。 +更多详情请参考[这里](https://github.com/kubernetes/examples/tree/{{< param "githubbranch" >}}/staging/volumes/azure_file/README.md)。 + +### cephfs {#cephfs} + + + +`cephfs` 允许您将现存的 CephFS 卷挂载到 Pod 中。不像 `emptyDir` 那样会在删除 Pod 的同时也会被删除,`cephfs` 卷的内容在删除 Pod 时会被保留,卷只是被卸载掉了。 +这意味着 CephFS 卷可以被预先填充数据,并且这些数据可以在 Pod 之间"传递"。CephFS 卷可同时被多个写者挂载。 + + +{{< caution >}} + +在您使用 Ceph 卷之前,您的 Ceph 服务器必须正常运行并且要使用的 share 被导出(exported)。 +{{< /caution >}} + + + +更多信息请参考 [CephFS 示例](https://github.com/kubernetes/examples/tree/{{< param "githubbranch" >}}/staging/volumes/cephfs/)。 + +### configMap {#configmap} + + + +[`configMap`](/docs/tasks/configure-pod-container/configure-pod-configmap/) 资源提供了向 Pod 注入配置数据的方法。 +`ConfigMap` 对象中存储的数据可以被 `configMap` 类型的卷引用,然后被应用到 Pod 中运行的容器化应用。 + + + +当引用 `configMap` 对象时,你可以简单的在 Volume 中通过它名称来引用。 +还可以自定义 ConfigMap 中特定条目所要使用的路径。 +例如,要将名为 `log-config` 的 ConfigMap 挂载到名为 `configmap-pod` 的 Pod 中,您可以使用下面的 YAML: + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: configmap-pod +spec: + containers: + - name: test + image: busybox + volumeMounts: + - name: config-vol + mountPath: /etc/config + volumes: + - name: config-vol + configMap: + name: log-config + items: + - key: log_level + path: log_level +``` + + + +`log-config` ConfigMap 是以卷的形式挂载的, +存储在 `log_level` 条目中的所有内容都被挂载到 Pod 的 "`/etc/config/log_level`" 路径下。 +请注意,这个路径来源于 Volume 的 `mountPath` 和 `log_level` 键对应的 `path`。 + +{{< caution >}} + +在使用 [ConfigMap](/docs/tasks/configure-pod-container/configure-pod-configmap/) 之前您首先要创建它。 +{{< /caution >}} + +{{< note >}} + +容器以 [subPath](#using-subpath) 卷挂载方式使用 ConfigMap 时,将无法接收 ConfigMap 的更新。 +{{< /note >}} + +### downwardAPI {#downwardapi} + + + +`downwardAPI` 卷用于使 downward API 数据对应用程序可用。 +这种卷类型挂载一个目录并在纯文本文件中写入请求的数据。 + +{{< note >}} + +容器以挂载 [subPath](#using-subpath) 卷的方式使用 downwardAPI 时,将不能接收到它的更新。 +{{< /note >}} + + +更多详细信息请参考 [`downwardAPI` 卷示例](/docs/tasks/inject-data-application/downward-api-volume-expose-pod-information/)。 + +### emptyDir {#emptydir} + + + +当 Pod 指定到某个节点上时,首先创建的是一个 `emptyDir` 卷,并且只要 Pod 在该节点上运行,卷就一直存在。 +就像它的名称表示的那样,卷最初是空的。 +尽管 Pod 中的容器挂载 `emptyDir` 卷的路径可能相同也可能不同,但是这些容器都可以读写 `emptyDir` 卷中相同的文件。 +当 Pod 因为某些原因被从节点上删除时,`emptyDir` 卷中的数据也会永久删除。 + +{{< note >}} + +容器崩溃并不会导致 Pod 被从节点上移除,因此容器崩溃时 `emptyDir` 卷中的数据是安全的。 +{{< /note >}} + + + +`emptyDir` 的一些用途: + +* 缓存空间,例如基于磁盘的归并排序。 +* 为耗时较长的计算任务提供检查点,以便任务能方便地从崩溃前状态恢复执行。 +* 在 Web 服务器容器服务数据时,保存内容管理器容器获取的文件。 + + + + +默认情况下, `emptyDir` 卷存储在支持该节点所使用的介质上;这里的介质可以是磁盘或 SSD 或网络存储,这取决于您的环境。 +但是,您可以将 `emptyDir.medium` 字段设置为 `"Memory"`,以告诉 Kubernetes 为您安装 tmpfs(基于 RAM 的文件系统)。 +虽然 tmpfs 速度非常快,但是要注意它与磁盘不同。 +tmpfs 在节点重启时会被清除,并且您所写入的所有文件都会计入容器的内存消耗,受容器内存限制约束。 + + + +#### Pod 示例 + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: test-pd +spec: + containers: + - image: k8s.gcr.io/test-webserver + name: test-container + volumeMounts: + - mountPath: /cache + name: cache-volume + volumes: + - name: cache-volume + emptyDir: {} +``` + + + +### fc (光纤通道) {#fc} + +`fc` 卷允许将现有的光纤通道卷挂载到 Pod 中。 +可以使用卷配置中的参数 `targetWWNs` 来指定单个或多个目标 WWN。 +如果指定多个 WWN,targetWWNs 期望这些 WWN 来自多路径连接。 + +{{< caution >}} + +您必须配置 FC SAN Zoning,以便预先向目标 WWN 分配和屏蔽这些 LUN(卷),这样 Kubernetes 主机才可以访问它们。 +{{< /caution >}} + + + +更多详情请参考 [FC 示例](https://github.com/kubernetes/examples/tree/{{< param "githubbranch" >}}/staging/volumes/fibre_channel)。 + + + +### flocker {#flocker} + +[Flocker](https://github.com/ClusterHQ/flocker) 是一个开源的、集群化的容器数据卷管理器。 +Flocker 提供了由各种存储后备支持的数据卷的管理和编排。 + + + +`flocker` 卷允许将一个 Flocker 数据集挂载到 Pod 中。 +如果数据集在 Flocker 中不存在,则需要首先使用 Flocker CLI 或 Flocker API 创建数据集。 +如果数据集已经存在,那么 Flocker 将把它重新附加到 Pod 被调度的节点。 +这意味着数据可以根据需要在 Pod 之间 "传递"。 + + +{{< caution >}} + +您在使用 Flocker 之前必须先安装运行自己的 Flocker。 +{{< /caution >}} + + + +更多详情请参考 [Flocker 示例](https://github.com/kubernetes/examples/tree/{{< param "githubbranch" >}}/staging/volumes/flocker)。 + + + +### gcePersistentDisk {#gcepersistentdisk} + +`gcePersistentDisk` 卷能将谷歌计算引擎 (GCE) [持久盘(PD)](http://cloud.google.com/compute/docs/disks) 挂载到您的 Pod 中。 +不像 `emptyDir` 那样会在删除 Pod 的同时也会被删除,持久盘卷的内容在删除 Pod 时会被保留,卷只是被卸载掉了。 +这意味着持久盘卷可以被预先填充数据,并且这些数据可以在 Pod 之间"传递"。 + +{{< caution >}} + +您在使用 PD 前,必须使用 `gcloud` 或者 GCE API 或 UI 创建它。 +{{< /caution >}} + + + +使用 `gcePersistentDisk` 时有一些限制: + +* 运行 Pod 的节点必须是 GCE VM +* 那些 VM 必须和持久盘属于相同的 GCE 项目和区域(zone) + + + +PD 的一个特点是它们可以同时被多个消费者以只读方式挂载。 +这意味着您可以用数据集预先填充 PD,然后根据需要并行地在尽可能多的 Pod 中提供该数据集。 +不幸的是,PD 只能由单个使用者以读写模式挂载——即不允许同时写入。 + + + +在由 ReplicationController 所管理的 Pod 上使用 PD 将会失败,除非 PD 是只读模式或者副本的数量是 0 或 1。 + + + +#### 创建持久盘(PD) + +在 Pod 中使用 GCE 持久盘之前,您首先要创建它。 + +```shell +gcloud compute disks create --size=500GB --zone=us-central1-a my-data-disk +``` + + + +#### Pod 示例 + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: test-pd +spec: + containers: + - image: k8s.gcr.io/test-webserver + name: test-container + volumeMounts: + - mountPath: /test-pd + name: test-volume + volumes: + - name: test-volume + # This GCE PD must already exist. + gcePersistentDisk: + pdName: my-data-disk + fsType: ext4 +``` + + +#### 区域持久盘(Regional Persistent Disks) + +{{< feature-state for_k8s_version="v1.10" state="beta" >}} + + + +[区域持久盘](https://cloud.google.com/compute/docs/disks/#repds) 功能允许您创建能在同一区域的两个可用区中使用的持久盘。 +要使用这个功能,必须以持久盘的方式提供卷;Pod 不支持直接引用这种卷。 + + + +#### 手动供应基于区域 PD 的 PersistentVolume + +使用 [为 GCE PD 定义的存储类](/docs/concepts/storage/storage-classes/#gce) 也可以动态供应。 +在创建 PersistentVolume 之前,您首先要创建 PD。 + +```shell +gcloud beta compute disks create --size=500GB my-data-disk + --region us-central1 + --replica-zones us-central1-a,us-central1-b +``` + + + +PersistentVolume 示例: + +```yaml +apiVersion: v1 +kind: PersistentVolume +metadata: + name: test-volume + labels: + failure-domain.beta.kubernetes.io/zone: us-central1-a__us-central1-b +spec: + capacity: + storage: 400Gi + accessModes: + - ReadWriteOnce + gcePersistentDisk: + pdName: my-data-disk + fsType: ext4 +``` + + + +### gitRepo (已弃用) + +{{< warning >}} + +gitRepo 卷类型已经被废弃。如果需要在容器中提供 git 仓库,请将一个 [EmptyDir](#emptydir) 卷挂载到 InitContainer 中,使用 git 命令完成仓库的克隆操作,然后将 [EmptyDir](#emptydir) 卷挂载到 Pod 的容器中。 +{{< /warning >}} + + + +`gitRepo` 卷是一个卷插件的例子。 +该卷类型挂载了一个空目录,并将一个 Git 代码仓库克隆到这个目录中供您使用。 +将来,这种卷可能被移动到一个更加解耦的模型中,而不是针对每个应用案例扩展 Kubernetes API。 + +下面给出一个 gitRepo 卷的示例: + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: server +spec: + containers: + - image: nginx + name: nginx + volumeMounts: + - mountPath: /mypath + name: git-volume + volumes: + - name: git-volume + gitRepo: + repository: "git@somewhere:me/my-git-repository.git" + revision: "22f1d8406d464b0c0874075539c1f2e96c253775" +``` + +### glusterfs {#glusterfs} + + + +`glusterfs` 卷能将 [Glusterfs](http://www.gluster.org) (一个开源的网络文件系统) 挂载到您的 Pod 中。 +不像 `emptyDir` 那样会在删除 Pod 的同时也会被删除,`glusterfs` 卷的内容在删除 Pod 时会被保存,卷只是被卸载掉了。 +这意味着 `glusterfs` 卷可以被预先填充数据,并且这些数据可以在 Pod 之间"传递"。GlusterFS 可以被多个写者同时挂载。 + +{{< caution >}} + +在使用前您必须先安装运行自己的 GlusterFS。 +{{< /caution >}} + + + +更多详情请参考 [GlusterFS 示例](https://github.com/kubernetes/examples/tree/{{< param "githubbranch" >}}/staging/volumes/glusterfs)。 + +### hostPath {#hostpath} + + + +`hostPath` 卷能将主机节点文件系统上的文件或目录挂载到您的 Pod 中。 +虽然这不是大多数 Pod 需要的,但是它为一些应用程序提供了强大的逃生舱。 + + + +例如,`hostPath` 的一些用法有: + +* 运行一个需要访问 Docker 引擎内部机制的容器;请使用 `hostPath` 挂载 `/var/lib/docker` 路径。 +* 在容器中运行 cAdvisor 时,以 `hostPath` 方式挂载 `/sys`。 +* 允许 Pod 指定给定的 `hostPath` 在运行 Pod 之前是否应该存在,是否应该创建以及应该以什么方式存在。 + + + +除了必需的 `path` 属性之外,用户可以选择性地为 `hostPath` 卷指定 `type`。 + +支持的 `type` 值如下: + + + + +| 取值 | 行为 | +|:------|:---------| +| | 空字符串(默认)用于向后兼容,这意味着在安装 hostPath 卷之前不会执行任何检查。 | +| `DirectoryOrCreate` | 如果在给定路径上什么都不存在,那么将根据需要创建空目录,权限设置为 0755,具有与 Kubelet 相同的组和所有权。 | +| `Directory` | 在给定路径上必须存在的目录。| +| `FileOrCreate` | 如果在给定路径上什么都不存在,那么将在那里根据需要创建空文件,权限设置为 0644,具有与 Kubelet 相同的组和所有权。| +| `File` | 在给定路径上必须存在的文件。| +| `Socket` | 在给定路径上必须存在的 UNIX 套接字。| +| `CharDevice` | 在给定路径上必须存在的字符设备。| +| `BlockDevice` | 在给定路径上必须存在的块设备。| + + + +当使用这种类型的卷时要小心,因为: + +* 具有相同配置(例如从 podTemplate 创建)的多个 Pod 会由于节点上文件的不同而在不同节点上有不同的行为。 +* 当 Kubernetes 按照计划添加资源感知的调度时,这类调度机制将无法考虑由 `hostPath` 使用的资源。 +* 基础主机上创建的文件或目录只能由 root 用户写入。您需要在 [特权容器](/docs/user-guide/security-context) 中以 root 身份运行进程,或者修改主机上的文件权限以便容器能够写入 `hostPath` 卷。 + + + +#### Pod 示例 + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: test-pd +spec: + containers: + - image: k8s.gcr.io/test-webserver + name: test-container + volumeMounts: + - mountPath: /test-pd + name: test-volume + volumes: + - name: test-volume + hostPath: + # directory location on host + path: /data + # this field is optional + type: Directory +``` + +### iscsi {#iscsi} + + + +`iscsi` 卷能将 iSCSI (基于 IP 的 SCSI) 挂载到您的 Pod 中。 +不像 `emptyDir` 那样会在删除 Pod 的同时也会被删除,持久盘 卷的内容在删除 Pod 时会被保存,卷只是被卸载掉了。 +这意味着 `iscsi` 卷可以被预先填充数据,并且这些数据可以在 Pod 之间"传递"。 + +{{< caution >}} + +在您使用 iSCSI 卷之前,您必须拥有自己的 iSCSI 服务器,并在上面创建卷。 +{{< /caution >}} + + + +iSCSI 的一个特点是它可以同时被多个用户以只读方式挂载。 +这意味着您可以用数据集预先填充卷,然后根据需要在尽可能多的 Pod 上提供它。不幸的是,iSCSI 卷只能由单个使用者以读写模式挂载——不允许同时写入。 + + + +更多详情请参考 [iSCSI 示例](https://github.com/kubernetes/examples/tree/{{< param "githubbranch" >}}/staging/volumes/iscsi)。 + + + +### local {#local} + +{{< feature-state for_k8s_version="v1.10" state="beta" >}} + +{{< note >}} + +alpha 版本的 PersistentVolume NodeAffinity 注释已被取消,将在将来的版本中废弃。 +用户必须更新现有的使用该注解的 PersistentVolume,以使用新的 PersistentVolume `NodeAffinity` 字段。 +{{< /note >}} + + + +`local` 卷指的是所挂载的某个本地存储设备,例如磁盘、分区或者目录。 + +`local` 卷只能用作静态创建的持久卷。尚不支持动态配置。 + + + +相比 `hostPath` 卷,`local` 卷可以以持久和可移植的方式使用,而无需手动将 Pod 调度到节点,因为系统通过查看 PersistentVolume 所属节点的亲和性配置,就能了解卷的节点约束。 + + + +然而,`local` 卷仍然取决于底层节点的可用性,并不是适合所有应用程序。 +如果节点变得不健康,那么`local` 卷也将变得不可访问,并且使用它的 Pod 将不能运行。 +使用 `local` 卷的应用程序必须能够容忍这种可用性的降低,以及因底层磁盘的耐用性特征而带来的潜在的数据丢失风险。 + +下面是一个使用 `local` 卷和 `nodeAffinity` 的持久卷示例: + +```yaml +apiVersion: v1 +kind: PersistentVolume +metadata: + name: example-pv +spec: + capacity: + storage: 100Gi + # volumeMode field requires BlockVolume Alpha feature gate to be enabled. + volumeMode: Filesystem + accessModes: + - ReadWriteOnce + persistentVolumeReclaimPolicy: Delete + storageClassName: local-storage + local: + path: /mnt/disks/ssd1 + nodeAffinity: + required: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/hostname + operator: In + values: + - example-node +``` + + + +使用 `local` 卷时,需要使用 PersistentVolume 对象的 `nodeAffinity` 字段。 +它使 Kubernetes 调度器能够将使用 `local` 卷的 Pod 正确地调度到合适的节点。 + + + +现在,可以将 PersistentVolume 对象的 `volumeMode` 字段设置为 "Block"(而不是默认值 "Filesystem"),以将 `local` 卷作为原始块设备暴露出来。 +`volumeMode` 字段需要启用 Alpha 功能 `BlockVolume`。 + + + +当使用 `local` 卷时,建议创建一个 StorageClass,将 `volumeBindingMode` 设置为 `WaitForFirstConsumer`。 +请参考 [示例](/docs/concepts/storage/storage-classes/#local)。 +延迟卷绑定操作可以确保 Kubernetes 在为 PersistentVolumeClaim 作出绑定决策时,会评估 Pod 可能具有的其他节点约束,例如:如节点资源需求、节点选择器、Pod 亲和性和 Pod 反亲和性。 + + + +您可以在 Kubernetes 之外单独运行静态驱动以改进对 local 卷的生命周期管理。 +请注意,此驱动不支持动态配置。 +有关如何运行外部 `local` 卷驱动的示例,请参考 [local 卷驱动用户指南](https://github.com/kubernetes-incubator/external-storage/tree/master/local-volume)。 + +{{< note >}} + +如果不使用外部静态驱动来管理卷的生命周期,则用户需要手动清理和删除 local 类型的持久卷。 +{{< /note >}} + +### nfs {#nfs} + + + +`nfs` 卷能将 NFS (网络文件系统) 挂载到您的 Pod 中。 +不像 `emptyDir` 那样会在删除 Pod 的同时也会被删除,`nfs` 卷的内容在删除 Pod 时会被保存,卷只是被卸载掉了。 +这意味着 `nfs` 卷可以被预先填充数据,并且这些数据可以在 Pod 之间"传递"。 + +{{< caution >}} + +在您使用 NFS 卷之前,必须运行自己的 NFS 服务器并将目标 share 导出备用。 +{{< /caution >}} + + + +要了解更多详情请参考 [NFS 示例](https://github.com/kubernetes/examples/tree/{{< param "githubbranch" >}}/staging/volumes/nfs)。 + +### persistentVolumeClaim {#persistentvolumeclaim} + + +`persistentVolumeClaim` 卷用来将[持久卷](/docs/concepts/storage/persistent-volumes/)(PersistentVolume)挂载到 Pod 中。 +持久卷是用户在不知道特定云环境细节的情况下"申领"持久存储(例如 GCE PersistentDisk 或者 iSCSI 卷)的一种方法。 + + + +更多详情请参考[持久卷示例](/docs/concepts/storage/persistent-volumes/) + +### projected {#projected} + + + +`projected` 卷类型能将若干现有的卷来源映射到同一目录上。 + +目前,可以映射的卷来源类型如下: + +- [`secret`](#secret) +- [`downwardAPI`](#downwardapi) +- [`configMap`](#configmap) +- `serviceAccountToken` + + + +所有的卷来源需要和 Pod 处于相同的命名空间。 +更多详情请参考[一体化卷设计文档](https://github.com/kubernetes/community/blob/{{< param "githubbranch" >}}/contributors/design-proposals/node/all-in-one-volume.md)。 + + + +服务帐户令牌的映射是 Kubernetes 1.11 版本中引入的一个功能,并在 1.12 版本中被提升为 Beta 功能。 +若要在 1.11 版本中启用此特性,需要显式设置 `TokenRequestProjection` [功能开关](/docs/reference/command-line-tools-reference/feature-gates/) 为 True。 + + + +#### 包含 secret、downwardAPI 和 configmap 的 Pod 示例如下: + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: volume-test +spec: + containers: + - name: container-test + image: busybox + volumeMounts: + - name: all-in-one + mountPath: "/projected-volume" + readOnly: true + volumes: + - name: all-in-one + projected: + sources: + - secret: + name: mysecret + items: + - key: username + path: my-group/my-username + - downwardAPI: + items: + - path: "labels" + fieldRef: + fieldPath: metadata.labels + - path: "cpu_limit" + resourceFieldRef: + containerName: container-test + resource: limits.cpu + - configMap: + name: myconfigmap + items: + - key: config + path: my-group/my-config +``` + + + +带有非默认许可模式设置的多个 secret 的 Pod 示例如下: + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: volume-test +spec: + containers: + - name: container-test + image: busybox + volumeMounts: + - name: all-in-one + mountPath: "/projected-volume" + readOnly: true + volumes: + - name: all-in-one + projected: + sources: + - secret: + name: mysecret + items: + - key: username + path: my-group/my-username + - secret: + name: mysecret2 + items: + - key: password + path: my-group/my-password + mode: 511 +``` + + +每个被投射的卷来源都在 spec 中的 `sources` 内列出。 +参数几乎相同,除了两处例外: + +* 对于 secret,`secretName` 字段已被变更为 `name` 以便与 ConfigMap 命名一致。 +* `defaultMode` 只能根据投射级别指定,而不是针对每个卷来源指定。不过,如上所述,您可以显式地为每个投射项设置 `mode` 值。 + + + +当开启 `TokenRequestProjection` 功能时,可以将当前 [服务帐户](/docs/reference/access-authn-authz/authentication/#service-account-tokens)的令牌注入 Pod 中的指定路径。 +下面是一个例子: + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: sa-token-test +spec: + containers: + - name: container-test + image: busybox + volumeMounts: + - name: token-vol + mountPath: "/service-account" + readOnly: true + volumes: + - name: token-vol + projected: + sources: + - serviceAccountToken: + audience: api + expirationSeconds: 3600 + path: token +``` + + + +示例 Pod 具有包含注入服务帐户令牌的映射卷。 +例如,这个令牌可以被 Pod 容器用来访问 Kubernetes API服务器。 +`audience` 字段包含令牌的预期受众。 +令牌的接收者必须使用令牌的受众中指定的标识符来标识自己,否则应拒绝令牌。 +此字段是可选的,默认值是 API 服务器的标识符。 + + + +`expirationSeconds` 是服务帐户令牌的有效期。 +默认值为 1 小时,必须至少 10 分钟(600 秒)。 +管理员还可以通过指定 API 服务器的 `--service-account-max-token-expiration` 选项来限制其最大值。 +`path` 字段指定相对于映射卷的挂载点的相对路径。 + +{{< note >}} + +使用投射卷源作为 [subPath](#using-subpath) 卷挂载的容器将不会接收这些卷源的更新。 +{{< /note >}} + +### portworxVolume {#portworxvolume} + + + +`portworxVolume` 是一个可伸缩的块存储层,能够以超聚合(hyperconverged)的方式与 Kubernetes 一起运行。 +Portworx 支持对服务器上存储的指纹处理、基于存储能力进行分层以及跨多个服务器整合存储容量。 +Portworx 可以以 in-guest 方式在虚拟机中运行,也可以在裸金属 Linux 节点上运行。 + + + +`portworxVolume` 类型的卷可以通过 Kubernetes 动态创建,也可以在 Kubernetes Pod 内预先供应和引用。 +下面是一个引用预先配置的 PortworxVolume 的示例 Pod: + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: test-portworx-volume-pod +spec: + containers: + - image: k8s.gcr.io/test-webserver + name: test-container + volumeMounts: + - mountPath: /mnt + name: pxvol + volumes: + - name: pxvol + # This Portworx volume must already exist. + portworxVolume: + volumeID: "pxvol" + fsType: "" +``` + +{{< caution >}} + +在 Pod 中使用 portworxVolume 之前,请确保有一个名为 `pxvol` 的 PortworxVolume 存在。 +{{< /caution >}} + + + +更多详情和示例可以在[这里](https://github.com/kubernetes/examples/tree/{{< param "githubbranch" >}}/staging/volumes/portworx/README.md)找到。 + +### quobyte {#quobyte} + + + +`quobyte` 卷允许将现有的 [Quobyte](http://www.quobyte.com) 卷挂载到您的 Pod 中。 + +{{< caution >}} + +在使用 Quobyte 卷之前,您首先要进行安装并创建好卷。 + +{{< /caution >}} + + + +更多详情请参考 [Quobyte 示例](https://github.com/kubernetes/examples/tree/{{< param "githubbranch" >}}/staging/volumes/quobyte)。 + +### rbd {#rbd} + + + +`rbd` 卷允许将 [Rados 块设备](http://ceph.com/docs/master/rbd/rbd/) 卷挂载到您的 Pod 中. +不像 `emptyDir` 那样会在删除 Pod 的同时也会被删除,`rbd` 卷的内容在删除 Pod 时会被保存,卷只是被卸载掉了。 +这意味着 `rbd` 卷可以被预先填充数据,并且这些数据可以在 Pod 之间"传递"。 + + +{{< caution >}} + +在使用 RBD 之前,您必须安装运行 Ceph。 +{{< /caution >}} + + + +RBD 的一个特点是它可以同时被多个用户以只读方式挂载。 +这意味着您可以用数据集预先填充卷,然后根据需要从尽可能多的 Pod 中并行地提供卷。 +不幸的是,RBD 卷只能由单个使用者以读写模式安装——不允许同时写入。 + +更多详情请参考 [RBD 示例](https://github.com/kubernetes/examples/tree/{{< param "githubbranch" >}}/staging/volumes/rbd)。 + +### scaleIO {#scaleio} + + + +ScaleIO 是基于软件的存储平台,可以使用现有硬件来创建可伸缩的、共享的而且是网络化的块存储集群。 +`scaleIO` 卷插件允许部署的 Pod 访问现有的 ScaleIO 卷(或者它可以动态地为持久卷申领提供新的卷,参见[ScaleIO 持久卷](/docs/concepts/storage/persistent-volumes/#scaleio))。 + +{{< caution >}} + +在使用前,您必须有个安装完毕且运行正常的 ScaleIO 集群,并且创建好了存储卷。 +{{< /caution >}} + + + +下面是配置了 ScaleIO 的 Pod 示例: + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: pod-0 +spec: + containers: + - image: k8s.gcr.io/test-webserver + name: pod-0 + volumeMounts: + - mountPath: /test-pd + name: vol-0 + volumes: + - name: vol-0 + scaleIO: + gateway: https://localhost:443/api + system: scaleio + protectionDomain: sd0 + storagePool: sp1 + volumeName: vol-0 + secretRef: + name: sio-secret + fsType: xfs +``` + + + +更多详情,请参考 [ScaleIO 示例](https://github.com/kubernetes/examples/tree/{{< param "githubbranch" >}}/staging/volumes/scaleio)。 + +### secret {#secret} + + + +`secret` 卷用来给 Pod 传递敏感信息,例如密码。您可以将 secret 存储在 Kubernetes API 服务器上,然后以文件的形式挂在到 Pod 中,无需直接与 Kubernetes 耦合。 +`secret` 卷由 tmpfs(基于 RAM 的文件系统)提供存储,因此它们永远不会被写入非易失性(持久化的)存储器。 + +{{< caution >}} + +使用前您必须在 Kubernetes API 中创建 secret。 +{{< /caution >}} + +{{< note >}} + +容器以 [subPath](#using-subpath) 卷的方式挂载 Secret 时,它将感知不到 Secret 的更新。 +{{< /note >}} + + + +Secret 的更多详情请参考[这里](/docs/user-guide/secrets)。 + +### storageOS {#storageos} + + + +`storageos` 卷允许将现有的 [StorageOS](https://www.storageos.com) 卷挂载到您的 Pod 中。 + + + +StorageOS 在 Kubernetes 环境中以容器的形式运行,这使得应用能够从 Kubernetes 集群中的任何节点访问本地或关联的存储。 +为应对节点失效状况,可以复制数据。 +若需提高利用率和降低成本,可以考虑瘦配置(Thin Provisioning)和数据压缩。 + + + +作为其核心能力之一,StorageOS 为容器提供了可以通过文件系统访问的块存储。 + +StorageOS 容器需要 64 位的 Linux,并且没有其他的依赖关系。 +StorageOS 提供免费的开发者授权许可。 + +{{< caution >}} + + +您必须在每个希望访问 StorageOS 卷的或者将向存储资源池贡献存储容量的节点上运行 StorageOS 容器。 +有关安装说明,请参阅 [StorageOS 文档](https://docs.storageos.com)。 + +{{< /caution >}} + +```yaml +apiVersion: v1 +kind: Pod +metadata: + labels: + name: redis + role: master + name: test-storageos-redis +spec: + containers: + - name: master + image: kubernetes/redis:v1 + env: + - name: MASTER + value: "true" + ports: + - containerPort: 6379 + volumeMounts: + - mountPath: /redis-master-data + name: redis-data + volumes: + - name: redis-data + storageos: + # The `redis-vol01` volume must already exist within StorageOS in the `default` namespace. + volumeName: redis-vol01 + fsType: ext4 +``` + + + +更多关于动态供应和持久卷申领的信息请参考 [StorageOS 示例](https://github.com/kubernetes/examples/blob/master/staging/volumes/storageos)。 + +### vsphereVolume {#vspherevolume} + +{{< note >}} + +前提条件:配备了 vSphere 云驱动的 Kubernetes。云驱动的配置方法请参考 [vSphere 使用指南](https://vmware.github.io/vsphere-storage-for-kubernetes/documentation/)。 +{{< /note >}} + + + +`vsphereVolume` 用来将 vSphere VMDK 卷挂载到您的 Pod 中。 +在卸载卷时,卷的内容会被保留。 +vSphereVolume 卷类型支持 VMFS 和 VSAN 数据仓库。 + +{{< caution >}} + +在挂载到 Pod 之前,您必须用下列方式之一创建 VMDK。 +{{< /caution >}} + + + +#### 创建 VMDK 卷 + +选择下列方式之一创建 VMDK。 + +{{< tabs name="tabs_volumes" >}} +{{% tab name="使用 vmkfstools 创建" %}} + + + + +首先 ssh 到 ESX,然后使用下面的命令来创建 VMDK: + +```shell +vmkfstools -c 2G /vmfs/volumes/DatastoreName/volumes/myDisk.vmdk +``` +{{% /tab %}} +{{% tab name="使用 vmware-vdiskmanager 创建" %}} + + + + +使用下面的命令创建 VMDK: + +```shell +vmware-vdiskmanager -c -t 0 -s 40GB -a lsilogic myDisk.vmdk +``` +{{% /tab %}} + +{{< /tabs >}} + + + + +#### vSphere VMDK 配置示例 + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: test-vmdk +spec: + containers: + - image: k8s.gcr.io/test-webserver + name: test-container + volumeMounts: + - mountPath: /test-vmdk + name: test-volume + volumes: + - name: test-volume + # This VMDK volume must already exist. + vsphereVolume: + volumePath: "[DatastoreName] volumes/myDisk" + fsType: ext4 +``` + + + +更多示例可以在[这里](https://github.com/kubernetes/examples/tree/master/staging/volumes/vsphere)找到。 + + + +## 使用 subPath + +有时,在单个 Pod 中共享卷以供多方使用是很有用的。 +`volumeMounts.subPath` 属性可用于指定所引用的卷内的子路径,而不是其根路径。 + + + +下面是一个使用同一共享卷的、内含 LAMP 栈(Linux Apache Mysql PHP)的 Pod 的示例。 +HTML 内容被映射到卷的 `html` 文件夹,数据库将被存储在卷的 `mysql` 文件夹中: + +```yaml +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 + - name: php + image: php:7.0-apache + volumeMounts: + - mountPath: /var/www/html + name: site-data + subPath: html + volumes: + - name: site-data + persistentVolumeClaim: + claimName: my-lamp-site-data +``` + + + +### 使用带有扩展环境变量的 subPath + +{{< feature-state for_k8s_version="v1.11" state="alpha" >}} + + + +`subPath` 的目录名也可以由 Downward API 环境变量构造。 +在使用此特性之前,必须启用 `VolumeSubpathEnvExpansion` 功能开关。 + + + +在这个示例中,Pod 基于 Downward API 中的 Pod 名称,使用 `subPath` 在 hostPath 卷 `/var/log/pods` 中创建目录 `pod1`。 +主机目录 `/var/log/pods/pod1` 挂载到了容器的 `/logs` 中。 + +```yaml +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 + subPath: $(POD_NAME) + restartPolicy: Never + volumes: + - name: workdir1 + hostPath: + path: /var/log/pods +``` + + + +## 资源 + +`emptyDir` 卷的存储介质(磁盘、SSD 等)是由保存 kubelet 根目录(通常是 `/var/lib/kubelet`)的文件系统的介质确定。 +`emptyDir` 卷或者 `hostPath` 卷可以消耗的空间没有限制,容器之间或 Pod 之间也没有隔离。 + + + +将来,我们希望 `emptyDir` 卷和 `hostPath` 卷能够使用 [resource](/docs/user-guide/computeresources) 规范来请求一定量的空间,并且能够为具有多种介质类型的集群选择要使用的介质类型。 + + + +## Out-of-Tree 卷插件 + +Out-of-Tree 卷插件包括容器存储接口(CSI)和 Flexvolume。 +它们使存储供应商能够创建自定义存储插件,而无需将它们添加到 Kubernetes 代码仓库。 + + + +在引入 CSI 和 Flexvolume 之前,所有卷插件(如上面列出的卷类型)都是 "in-tree" 的,这意味着它们是与 Kubernetes 的核心组件一同构建、链接、编译和交付的,并且这些插件都扩展了 Kubernetes 的核心 API。 +这意味着向 Kubernetes 添加新的存储系统(卷插件)需要将代码合并到 Kubernetes 核心代码库中。 + + + +CSI 和 Flexvolume 都允许独立于 Kubernetes 代码库开发卷插件,并作为扩展部署(安装)在 Kubernetes 集群上。 + +对于希望创建 out-of-tree 卷插件的存储供应商,请参考[这个 FAQ](https://github.com/kubernetes/community/blob/master/sig-storage/volume-plugin-faq.md)。 + +### CSI + +{{< feature-state for_k8s_version="v1.10" state="beta" >}} + + + +[容器存储接口](https://github.com/container-storage-interface/spec/blob/master/spec.md) (CSI) +为容器编排系统(如 Kubernetes)定义标准接口,以将任意存储系统暴露给它们的容器工作负载。 + + + +更多详情请阅读 [CSI 设计方案](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/storage/container-storage-interface.md)。 + +CSI 的支持在 Kubernetes v1.9 中作为 alpha 特性引入,并在 Kubernetes v1.10 中转为 beta 特性。 + + + +一旦在 Kubernetes 集群上部署了 CSI 兼容卷驱动程序,用户就可以使用 `csi` 卷类型来关联、挂载 CSI 驱动程序暴露出来的卷。 + +`csi` 卷类型不支持来自 Pod 的直接引用,只能通过 `PersistentVolumeClaim` 对象在 Pod 中引用。 + +存储管理员可以使用以下字段来配置 CSI 持久卷: + + +- + + `driver`:指定要使用的卷驱动程序名称的字符串值。 + 这个值必须与 CSI 驱动程序在 `GetPluginInfoResponse` 中返回的值相对应;该接口定义在 [CSI 规范](https://github.com/container-storage-interface/spec/blob/master/spec.md#getplugininfo)中。 + Kubernetes 使用所给的值来标识要调用的 CSI 驱动程序;CSI 驱动程序也使用该值来辨识哪些 PV 对象属于该 CSI 驱动程序。 + +- + + `volumeHandle`:唯一标识卷的字符串值。 + 该值必须与CSI 驱动程序在 `CreateVolumeResponse` 的 `volume_id` 字段中返回的值相对应;接口定义在 [CSI spec](https://github.com/container-storageinterface/spec/blob/master/spec.md#createvolume) 中。 + 在所有对 CSI 卷驱动程序的调用中,引用该 CSI 卷时都使用此值作为 `volume_id` 参数。 + +- + + `readOnly`:一个可选的布尔值,指示通过 `ControllerPublished` 关联该卷时是否设置该卷为只读。 + 默认值是 false。 + 该值通过 `ControllerPublishVolumeRequest` 中的 `readonly` 字段传递给 CSI 驱动程序。 + + +- + + `fsType`:如果 PV 的 `VolumeMode` 为 `Filesystem`,那么此字段指定挂载卷时应该使用的文件系统。 + 如果卷尚未格式化,并且支持格式化,此值将用于格式化卷。 + 此值可以通过 `ControllerPublishVolumeRequest`、`NodeStageVolumeRequest` 和 + `NodePublishVolumeRequest` 的 `VolumeCapability` 字段传递给 CSI 驱动。 + + +- + + `volumeAttributes`:一个字符串到字符串的映射表,用来设置卷的静态属性。 + 该映射必须与 CSI 驱动程序返回的 `CreateVolumeResponse` 中的 `volume.attributes` 字段的映射相对应;[CSI 规范](https://github.com/container-storage-interface/spec/blob/master/spec.md#createvolume) 中有相应的定义。 + 该映射通过`ControllerPublishVolumeRequest`、`NodeStageVolumeRequest`、和 `NodePublishVolumeRequest` 中的 `volume_attributes` 字段传递给 CSI 驱动。 + +- + + `controllerPublishSecretRef`:对包含敏感信息的 secret 对象的引用;该敏感信息会被传递给 CSI 驱动来完成 CSI `ControllerPublishVolume` 和 `ControllerUnpublishVolume` 调用。 + 此字段是可选的;在不需要 secret 时可以是空的。 + 如果 secret 对象包含多个 secret,则所有的 secret 都会被传递。 + +- + + `nodeStageSecretRef`:对包含敏感信息的 secret 对象的引用,以传递给 CSI 驱动来完成 CSI `NodeStageVolume` 调用。 + 此字段是可选的,如果不需要 secret,则可能是空的。 + 如果 secret 对象包含多个 secret,则传递所有 secret。 + +- + + `nodePublishSecretRef`:对包含敏感信息的 secret 对象的引用,以传递给 CSI 驱动来完成 CSI ``NodePublishVolume` 调用。 + 此字段是可选的,如果不需要 secret,则可能是空的。 + 如果 secret 对象包含多个 secret,则传递所有 secret。 + + +#### CSI 原始块卷支持 + +{{< feature-state for_k8s_version="v1.11" state="alpha" >}} + + + +从 1.11 版本开始,CSI 引入了对原始块卷的支持。该特性依赖于在 Kubernetes 的之前版本中引入的原始块卷(Raw Block Volume)功能。 +该特性将使具有外部 CSI 驱动程序的供应商能够在 Kubernetes 工作负载中实现原始块卷支持。 + + + +CSI 块卷支持是可选功能,并且默认关闭。 +为了在启用块卷支持的情况下运行 CSI,集群管理员必须使用以下特性开关参数为每个 Kubernetes 组件启用该特性: + +``` +--feature-gates=BlockVolume=true,CSIBlockVolume=true +``` + +学习怎样[安装您的带有块卷支持的 PV/PVC](/docs/concepts/storage/persistent-volumes/#raw-block-volume-support)。 + + +### Flexvolume + + +Flexvolume 是一个自 1.2 版本(在 CSI 之前)以来在 Kubernetes 中一直存在的 out-of-tree 插件接口。 +它使用基于 exec 的模型来与驱动程序对接。 +用户必须在每个节点(在某些情况下是主节点)上的预定义卷插件路径中安装 Flexvolume 驱动程序可执行文件。 + +Pod 通过 `flexvolume` in-tree 插件与 Flexvolume 驱动程序交互。 +更多详情请参考[这里](https://github.com/kubernetes/community/blob/master/contributors/devel/flexvolume.md)。 + + + +## 挂载卷的传播 + +挂载卷的传播能力允许将容器安装的卷共享到同一 Pod 中的其他容器,甚至共享到同一节点上的其他 Pod。 + +卷的挂载传播特性由 Container.volumeMounts 中的 `mountPropagation` 字段控制。 +它的值包括: + + * + `None` - 此卷挂载将不会感知到主机后续在此卷或其任何子目录上执行的挂载变化。 + 类似的,容器所创建的卷挂载在主机上是不可见的。这是默认模式。 + 该模式等同于 [Linux 内核文档](https://www.kernel.org/doc/Documentation/filesystems/sharedsubtree.txt)中描述的 `private` 挂载传播选项。 + + * + `HostToContainer` - 此卷挂载将会感知到主机后续针对此卷或其任何子目录的挂载操作。 + + 换句话说,如果主机在此挂载卷中挂载任何内容,容器将能看到它被挂载在那里。 + + 类似的,配置了 `Bidirectional` 挂载传播选项的 Pod 如果在同一卷上挂载了内容,挂载传播设置为 `HostToContainer` 的容器都将能看到这一变化。 + + 该模式等同于 [Linux 内核文档](https://www.kernel.org/doc/Documentation/filesystems/sharedsubtree.txt) 中描述的 `rslave` 挂载传播选项。 + + * + --`Bidirectional` - 这种卷挂载和 `HostToContainer` 挂载表现相同。 + + 另外,容器创建的卷挂载将被传播回至主机和使用同一卷的所有 Pod 的所有容器。 + + 该模式等同于 [Linux 内核文档](https://www.kernel.org/doc/Documentation/filesystems/sharedsubtree.txt) 中描述的 `rshared` 挂载传播选项。 + + +{{< caution >}} + + +`Bidirectional` 形式的挂载传播可能比较危险。 +它可以破坏主机操作系统,因此它只被允许在特权容器中使用。 +强烈建议您熟悉 Linux 内核行为。 +此外,由 Pod 中的容器创建的任何卷挂载必须在终止时由容器销毁(卸载)。 + +{{< /caution >}} + + +### 配置 + +在某些部署环境中,挂载传播正常工作前,必须在 Docker 中正确配置挂载共享(mount share),如下所示。 + + +编辑您的 Docker `systemd` 服务文件,按下面的方法设置 `MountFlags`: + +```shell +MountFlags=shared +``` + +或者,如果存在 `MountFlags=slave` 就删除掉。然后重启 Docker 守护进程: + +```shell +$ sudo systemctl daemon-reload +$ sudo systemctl restart docker +``` + +{{% capture whatsnext %}} + +参考[使用持久卷部署 WordPress 和 MySQL](/docs/tutorials/stateful-application/mysqlwordpress-persistent-volume/) 示例。 +{{% /capture %}}