diff --git a/content/zh/docs/concepts/storage/_index.md b/content/zh/docs/concepts/storage/_index.md index 3f2371fcb4..c6accc5314 100644 --- a/content/zh/docs/concepts/storage/_index.md +++ b/content/zh/docs/concepts/storage/_index.md @@ -2,10 +2,3 @@ title: "存储" weight: 70 --- - - \ No newline at end of file diff --git a/content/zh/docs/concepts/storage/dynamic-provisioning.md b/content/zh/docs/concepts/storage/dynamic-provisioning.md new file mode 100644 index 0000000000..12c808053a --- /dev/null +++ b/content/zh/docs/concepts/storage/dynamic-provisioning.md @@ -0,0 +1,203 @@ +--- +title: 动态卷供应 +content_template: templates/concept +weight: 40 +--- + +{{% capture overview %}} + + +动态卷供应允许按需创建存储卷。 +如果没有动态供应,集群管理员必须手动地联系他们的云或存储提供商来创建新的存储卷, +然后在 Kubernetes 集群创建 [`PersistentVolume` 对象](/docs/concepts/storage/persistent-volumes/)来表示这些卷。 +动态供应功能消除了集群管理员预先配置存储的需要。 相反,它在用户请求时自动供应存储。 + +{{% /capture %}} + +{{% capture body %}} + + +## 背景 + + +动态卷供应的实现基于 `storage.k8s.io` API 组中的 `StorageClass` API 对象。 +集群管理员可以根据需要定义多个 `StorageClass` 对象,每个对象指定一个*卷插件*(又名 *provisioner*), +卷插件向卷供应商提供在创建卷时需要的数据卷信息及相关参数。 + + +集群管理员可以在集群中定义和公开多种存储(来自相同或不同的存储系统),每种都具有自定义参数集。 +该设计也确保终端用户不必担心存储供应的复杂性和细微差别,但仍然能够从多个存储选项中进行选择。 + + +点击[这里](/docs/concepts/storage/storage-classes/)查阅有关存储类的更多信息。 + + +## 启用动态卷供应 + + +要启用动态供应功能,集群管理员需要为用户预先创建一个或多个 `StorageClass` 对象。 +`StorageClass` 对象定义在进行动态卷供应时应使用哪个卷供应商,以及应该将哪些参数传递给该供应商。 +以下清单创建了一个存储类 "slow",它提供类似标准磁盘的永久磁盘。 + +```yaml +apiVersion: storage.k8s.io/v1 +kind: StorageClass +metadata: + name: slow +provisioner: kubernetes.io/gce-pd +parameters: + type: pd-standard +``` + + +以下清单创建了一个 "fast" 存储类,它提供类似 SSD 的永久磁盘。 + +```yaml +apiVersion: storage.k8s.io/v1 +kind: StorageClass +metadata: + name: fast +provisioner: kubernetes.io/gce-pd +parameters: + type: pd-ssd +``` + + +## 使用动态卷供应 + + +用户通过在 `PersistentVolumeClaim` 中包含存储类来请求动态供应的存储。 +在 Kubernetes v1.6 之前,这通过 `volume.beta.kubernetes.io/storage-class` 注解实现。然而,这个注解自 v1.6 起就不被推荐使用了。 +用户现在能够而且应该使用 `PersistentVolumeClaim` 对象的 `storageClassName` 字段。 +这个字段的值必须能够匹配到集群管理员配置的 `StorageClass` 名称(见[下面](#enabling-dynamic-provisioning))。 + + +例如,要选择 "fast" 存储类,用户将创建如下的 `PersistentVolumeClaim`: + +```yaml +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: claim1 +spec: + accessModes: + - ReadWriteOnce + storageClassName: fast + resources: + requests: + storage: 30Gi +``` + + +该声明会自动供应一块类似 SSD 的永久磁盘。 +在删除该声明后,这个卷也会被销毁。 + + +## 默认行为 + + +可以在群集上启用动态卷供应,以便在未指定存储类的情况下动态设置所有声明。 +集群管理员可以通过以下方式启用此行为: + + +- 标记一个 `StorageClass` 为 *默认*; +- 确保 [`DefaultStorageClass` 准入控制器](/docs/reference/access-authn-authz/admission-controllers/#defaultstorageclass)在 API 服务端被启用。 + + +管理员可以通过向其添加 `storageclass.kubernetes.io/is-default-class` 注解来将特定的 `StorageClass` 标记为默认。 +当集群中存在默认的 `StorageClass` 并且用户创建了一个未指定 `storageClassName` 的 `PersistentVolumeClaim` 时, +`DefaultStorageClass` 准入控制器会自动向其中添加指向默认存储类的 `storageClassName` 字段。 + + +请注意,群集上最多只能有一个 *默认* 存储类,否则无法创建没有明确指定 `storageClassName` 的 `PersistentVolumeClaim`。 + + +## 拓扑感知 + + +在[多区域](/docs/setup/multiple-zones)集群中,Pod 可以被分散到多个区域。 +单区域存储后端应该被供应到 Pod 被调度到的区域。 +这可以通过设置[卷绑定模式](/docs/concepts/storage/storage-classes/#volume-binding-mode)来实现。 + +{{% /capture %}} diff --git a/content/zh/docs/concepts/storage/storage-classes.md b/content/zh/docs/concepts/storage/storage-classes.md new file mode 100644 index 0000000000..4368986ff5 --- /dev/null +++ b/content/zh/docs/concepts/storage/storage-classes.md @@ -0,0 +1,1244 @@ +--- +reviewers: +- jsafrane +- saad-ali +- thockin +- msau42 +title: Storage Classes +content_template: templates/concept +weight: 30 +--- + +{{% capture overview %}} + + +本文描述了 Kubernetes 中 StorageClass 的概念。建议先熟悉 [卷](/docs/concepts/storage/volumes/) 和 +[持久卷](/docs/concepts/storage/persistent-volumes) 的概念。 + +{{% /capture %}} + +{{% capture body %}} + + +## 介绍 + +`StorageClass` 为管理员提供了描述存储 `"类"` 的方法。 +不同的`类型`可能会映射到不同的服务质量等级或备份策略,或是由群集管理员制定的任意策略。 +Kubernetes 本身并不清楚各种`类`代表的什么。这个`类`的概念在其他存储系统中有时被称为"配置文件"。 + + +## StorageClass 资源 + +每个 `StorageClass` 都包含 `provisioner`、`parameters` 和 `reclaimPolicy` 字段, +这些字段会在`StorageClass`需要动态分配 `PersistentVolume` 时会使用到。 + + +`StorageClass` 对象的命名很重要,用户使用这个命名来请求生成一个特定的类。 +当创建 `StorageClass` 对象时,管理员设置 StorageClass 对象的命名和其他参数,一旦创建了对象就不能再对其更新。 + + +管理员可以为没有申请绑定到特定 `StorageClass` 的 PVC 指定一个默认的`类` : +更多详情请参阅 [`PersistentVolumeClaim` 章节](#persistentvolumeclaims)。 + +```yaml +apiVersion: storage.k8s.io/v1 +kind: StorageClass +metadata: + name: standard +provisioner: kubernetes.io/aws-ebs +parameters: + type: gp2 +reclaimPolicy: Retain +allowVolumeExpansion: true +mountOptions: + - debug +volumeBindingMode: Immediate +``` + + +### 存储分配器 + +`StorageClass` 有一个分配器,用来决定使用哪个`卷插件`分配`持久化卷申领`。该字段必须指定。 + + + +| 卷插件 | 提供厂商 | 配置例子 | +| :--- | :---: | :---: | +| AWSElasticBlockStore | ✓ | [AWS EBS](#aws-ebs) | +| AzureFile | ✓ | [Azure File](#azure-file) | +| AzureDisk | ✓ | [Azure Disk](#azure-disk) | +| CephFS | - | - | +| Cinder | ✓ | [OpenStack Cinder](#openstack-cinder)| +| FC | - | - | +| FlexVolume | - | - | +| Flocker | ✓ | - | +| GCEPersistentDisk | ✓ | [GCE PD](#gce-pd) | +| Glusterfs | ✓ | [Glusterfs](#glusterfs) | +| iSCSI | - | - | +| Quobyte | ✓ | [Quobyte](#quobyte) | +| NFS | - | - | +| RBD | ✓ | [Ceph RBD](#ceph-rbd) | +| VsphereVolume | ✓ | [vSphere](#vsphere) | +| PortworxVolume | ✓ | [Portworx Volume](#portworx-volume) | +| ScaleIO | ✓ | [ScaleIO](#scaleio) | +| StorageOS | ✓ | [StorageOS](#storageos) | +| Local | - | [Local](#local) | + + +您不限于指定此处列出的"内置"分配器(其名称前缀为 kubernetes.io 并打包在 Kubernetes 中)。 +您还可以运行和指定外部分配器,这些独立的程序遵循由 Kubernetes 定义的 [规范](https://git.k8s.io/community/contributors/design-proposals/storage/volume-provisioning.md)。 +外部供应商的作者完全可以自由决定他们的代码保存于何处、打包方式、运行方式、使用的插件(包括 Flex)等。 +代码仓库 [kubernetes-sigs/sig-storage-lib-external-provisioner](https://github.com/kubernetes-sigs/sig-storage-lib-external-provisioner) +包含一个用于为外部分配器编写功能实现的类库。可以通过下面的代码仓库,查看外部分配器列表。 + +[kubernetes-incubator/external-storage](https://github.com/kubernetes-incubator/external-storage). + + +例如,NFS 没有内部分配器,但可以使用外部分配器。 +也有第三方存储供应商提供自己的外部分配器。 + + +### 回收策略 + +由 `StorageClass` 动态创建的持久化卷会在的 `reclaimPolicy` 字段中指定回收策略,可以是 +`Delete` 或者 `Retain`。如果 `StorageClass` 对象被创建时没有指定 `reclaimPolicy` ,它将默认为 `Delete`。 + +通过 `StorageClass` 手动创建并管理的 Persistent Volume 会使用它们被创建时指定的回收政策。 + + + +### 允许卷扩展 + +{{< feature-state for_k8s_version="v1.11" state="beta" >}} + + + +永久卷可以配置为可扩展。将此功能设置为 `true` 时,允许用户通过编辑相应的PVC对象来调整卷大小。 + +当基础存储类的 `allowVolumeExpansion` 字段设置为true时,以下类型的卷支持卷扩展。 + +* gcePersistentDisk +* awsElasticBlockStore +* Cinder +* glusterfs +* rbd +* Azure File +* Azure Disk +* Portworx +* FlexVolumes +* CSI {{< feature-state for_k8s_version="v1.14" state="alpha" >}} + +{{< note >}} + + +此功能不能用于缩小卷。 + +{{< /note >}} + + +### 挂载选项 + +由 `StorageClass` 动态创建的 Persistent Volume 将使用`类`中 `mountOption` 字段指定的挂载选项。 + +如果卷插件不支持挂载选项,却指定了该选项,则分配操作会失败。 +挂载选项在 `StorageClass` 和持久卷上都不会做验证,所以如果挂载选项无效,那么这个 PV 就会失败。 + + +### 卷绑定模式 + +{{< feature-state for_k8s_version="v1.12" state="beta" >}} + + +**注意:** 这个功能特性需要启用 `VolumeScheduling` 参数才能使用。 + + +`volumeBindingMode` 字段控制了 [卷绑定和动态分配](/docs/concepts/storage/persistent-volumes/#provisioning) +应该发生在什么时候。 + + +默认情况下,`Immediate` 模式表示一旦创建了 PersistentVolumeClaim 也就完成了卷绑定和动态分配。 +对于由于拓扑限制而非集群所有节点可达的存储后端,PersistentVolume 会在不知道 Pod 调度要求的情况下绑定或者分配。 + + +集群管理员可以通过指定 `WaitForFirstConsumer` 模式来解决此问题。 +该模式将延迟 PersistentVolume 的绑定和分配,直到使用该 PersistentVolumeClaim 的 Pod 被创建。 +PersistentVolume 会根据 Pod 调度约束指定的拓扑来选择或分配。这些包括但不限于 [资源需求](/docs/concepts/configuration/manage-compute-resources-container), +[节点筛选器](/docs/concepts/configuration/assign-pod-node/#nodeselector), +[pod 亲和性和互斥性](/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity), +以及 [污点和容忍度](/docs/concepts/configuration/taint-and-toleration). + + +以下插件支持动态分配的 `WaitForFirstConsumer` 模式: + +* [AWSElasticBlockStore](#aws-ebs) +* [GCEPersistentDisk](#gce-pd) +* [AzureDisk](#azure-disk) + + +以下插件支持预创建绑定 PersistentVolume 的 `WaitForFirstConsumer` 模式: + +* All of the above +* [Local](#local) + +{{< feature-state state="beta" for_k8s_version="1.14" >}} + + + +动态配置和预先创建的PVs也支持 [CSI卷](/docs/concepts/storage/volumes/#csi), +但是您需要查看特定CSI驱动程序的文档以查看其支持的拓扑密钥和例子。 必须启用 `CSINodeInfo` 特性。 + + +### 允许的拓扑结构 +{{< feature-state for_k8s_version="v1.12" state="beta" >}} + + +**注意:** 这个特性需要开启 `VolumeScheduling` 特性开关。 + + +当集群操作人员使用了 `WaitForFirstConsumer` 的卷绑定模式,在大部分情况下就没有必要将配置限制为特定的拓扑结构。 +然而,如果还有需要的话,可以使用 `allowedTopologies`。 + + +这个例子描述了如何将分配卷限的拓扑限制在特定的区域,在使用时应该根据插件支持情况替换 `zone` 和 `zones` 参数。 + +```yaml +apiVersion: storage.k8s.io/v1 +kind: StorageClass +metadata: + name: standard +provisioner: kubernetes.io/gce-pd +parameters: + type: pd-standard +volumeBindingMode: WaitForFirstConsumer +allowedTopologies: +- matchLabelExpressions: + - key: failure-domain.beta.kubernetes.io/zone + values: + - us-central1-a + - us-central1-b +``` + + +## 参数 + +Storage class 具有描述属于卷的参数。取决于分配器,可以接受不同的参数。 +例如,参数 type 的值 io1 和参数 iopsPerGB 特定于 EBS PV。当参数被省略时,会使用默认值。 + +### AWS EBS + +```yaml +apiVersion: storage.k8s.io/v1 +kind: StorageClass +metadata: + name: slow +provisioner: kubernetes.io/aws-ebs +parameters: + type: io1 + iopsPerGB: "10" + fsType: ext4 +``` + + +* `type`:`io1`,`gp2`,`sc1`,`st1`。详细信息参见 [AWS 文档](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EBSVolumeTypes.html)。默认值:`gp2`。 +* `zone`(弃用):AWS 区域。如果没有指定 `zone` 和 `zones`,通常卷会在 Kubernetes 集群节点所在的活动区域中轮询调度分配。`zone` 和 `zones` 参数不能同时使用。 +* `zones`(弃用):以逗号分隔的 AWS 区域列表。如果没有指定 `zone` 和 `zones`,通常卷会在 Kubernetes 集群节点所在的活动区域中轮询调度分配。`zone`和`zones`参数不能同时使用。 +* `iopsPerGB`:只适用于 `io1` 卷。每 GiB 每秒 I/O 操作。AWS 卷插件将其与请求卷的大小相乘以计算 IOPS 的容量,并将其限制在 20 000 IOPS(AWS 支持的最高值,请参阅 [AWS 文档](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EBSVolumeTypes.html)。 + 这里需要输入一个字符串,即 `"10"`,而不是 `10`。 +* `fsType`:受 Kubernetes 支持的文件类型。默认值:`"ext4"`。 +* `encrypted`:指定 EBS 卷是否应该被加密。合法值为 `"true"` 或者 `"false"`。这里需要输入字符串,即 `"true"`, 而非 `true`。 +* `kmsKeyId`:可选。加密卷时使用密钥的完整 Amazon 资源名称。如果没有提供,但 `encrypted` 值为 true,AWS 生成一个密钥。关于有效的 ARN 值,请参阅 AWS 文档。 + +{{< note >}} + +`zone` 和 `zones` 已被弃用并被 [允许的拓扑结构](#allowed-topologies) 取代。 +{{< /note >}} + +### GCE PD + +```yaml +apiVersion: storage.k8s.io/v1 +kind: StorageClass +metadata: + name: slow +provisioner: kubernetes.io/gce-pd +parameters: + type: pd-standard + replication-type: none +``` + + +* `type`:`pd-standard` 或者 `pd-ssd`。默认:`pd-standard` +* `zone`(弃用):GCE 区域。如果没有指定 `zone` 和 `zones`,通常卷会在 Kubernetes 集群节点所在的活动区域中轮询调度分配。`zone` 和 `zones` 参数不能同时使用。 +* `zones`(弃用):逗号分隔的 GCE 区域列表。如果没有指定 `zone` 和 `zones`,通常卷会在 Kubernetes 集群节点所在的活动区域中轮询调度(round-robin)分配。`zone` 和 `zones` 参数不能同时使用。 +* `replication-type`:`none` 或者 `regional-pd`。默认值:`none`。 + + +如果 `replication-type` 设置为 `none`,会分配一个常规(当前区域内的)持久化磁盘。 + + +如果 `replication-type` 设置为 `regional-pd`,会分配一个 [区域性持久化磁盘(Regional Persistent Disk)](https://cloud.google.com/compute/docs/disks/#repds)。在这种情况下,用户必须使用 `zones` 而非 `zone` 来指定期望的复制区域(zone)。如果指定来两个特定的区域,区域性持久化磁盘会在这两个区域里分配。如果指定了多于两个的区域,Kubernetes 会选择其中任意两个区域。如果省略了 `zones` 参数,Kubernetes 会在集群管理的区域中任意选择。 + +{{< note >}} + + +`zone` 和 `zones` 已被弃用并被 [allowedTopologies](#allowed-topologies) 取代。 +{{< /note >}} + +### Glusterfs + +```yaml +apiVersion: storage.k8s.io/v1 +kind: StorageClass +metadata: + name: slow +provisioner: kubernetes.io/glusterfs +parameters: + resturl: "http://127.0.0.1:8081" + clusterid: "630372ccdc720a92c681fb928f27b53f" + restauthenabled: "true" + restuser: "admin" + secretNamespace: "default" + secretName: "heketi-secret" + gidMin: "40000" + gidMax: "50000" + volumetype: "replicate:3" +``` + + +* `resturl`:分配 gluster 卷的需求的 Gluster REST 服务/Heketi 服务 url。 + 通用格式应该是 `IPaddress:Port`,这是 GlusterFS 动态分配器的必需参数。 + 如果 Heketi 服务在 openshift/kubernetes 中安装并暴露为可路由服务,则可以使用类似于 + `http://heketi-storage-project.cloudapps.mystorage.com` 的格式,其中 fqdn 是可解析的 heketi 服务网址。 +* `restauthenabled`:Gluster REST 服务身份验证布尔值,用于启用对 REST 服务器的身份验证。如果此值为 'true',则必须填写 `restuser` 和 `restuserkey` 或 `secretNamespace` + `secretName`。此选项已弃用,当在指定 `restuser`,`restuserkey`,`secretName` 或 `secretNamespace` 时,身份验证被启用。 +* `restuser`:在 Gluster 可信池中有权创建卷的 Gluster REST服务/Heketi 用户。 +* `restuserkey`:Gluster REST 服务/Heketi 用户的密码将被用于对 REST 服务器进行身份验证。此参数已弃用,取而代之的是 `secretNamespace` + `secretName`。 + +* `secretNamespace`,`secretName`:Secret 实例的标识,包含与 Gluster REST 服务交互时使用的用户密码。 + 这些参数是可选的,`secretNamespace` 和 `secretName` 都省略时使用空密码。所提供的 Secret 必须将类型设置为 "kubernetes.io/glusterfs",例如以这种方式创建: + + ``` + kubectl create secret generic heketi-secret \ + --type="kubernetes.io/glusterfs" --from-literal=key='opensesame' \ + --namespace=default + ``` + + secret 的例子可以在 [glusterfs-provisioning-secret.yaml](https://github.com/kubernetes/examples/tree/master/staging/persistent-volume-provisioning/glusterfs/glusterfs-secret.yaml) 中找到。 + +* `clusterid`:`630372ccdc720a92c681fb928f27b53f` 是集群的 ID,当分配卷时,Heketi 将会使用这个文件。它也可以是一个 clusterid 列表,例如: + `"8452344e2becec931ece4e33c4674e4e,42982310de6c63381718ccfa6d8cf397"`。这个是可选参数。 +* `gidMin`,`gidMax`:storage class GID 范围的最小值和最大值。在此范围(gidMin-gidMax)内的唯一值(GID)将用于动态分配卷。这些是可选的值。如果不指定,卷将被分配一个 2000-2147483647 之间的值,这是 gidMin 和 gidMax 的默认值。 + + +* `volumetype`:卷的类型及其参数可以用这个可选值进行配置。如果未声明卷类型,则由分配器决定卷的类型。 + + 例如: + 'Replica volume': `volumetype: replicate:3` 其中 '3' 是 replica 数量. + 'Disperse/EC volume': `volumetype: disperse:4:2` 其中 '4' 是数据,'2' 是冗余数量. + 'Distribute volume': `volumetype: none` + + 有关可用的卷类型和管理选项,请参阅 [管理指南](https://access.redhat.com/documentation/en-US/Red_Hat_Storage/3.1/html/Administration_Guide/part-Overview.html)。 + + 更多相关的参考信息,请参阅 [如何配置 Heketi](https://github.com/heketi/heketi/wiki/Setting-up-the-topology)。 + + 当动态分配持久卷时,Gluster 插件自动创建名为 `gluster-dynamic-` 的端点和 headless service。在 PVC 被删除时动态端点和 headless service 会自动被删除。 + +### OpenStack Cinder + +```yaml +apiVersion: storage.k8s.io/v1 +kind: StorageClass +metadata: + name: gold +provisioner: kubernetes.io/cinder +parameters: + availability: nova +``` + + +* `availability`:可用区域。如果没有指定,通常卷会在 Kubernetes 集群节点所在的活动区域中轮询调度分配。 + + +{{< note >}} +{{< feature-state state="deprecated" for_k8s_version="1.11" >}} +OpenStack 的内部驱动程序已经被弃用。请使用 [OpenStack 的外部驱动程序](https://github.com/kubernetes/cloud-provider-openstack)。 +{{< /note >}} + +### vSphere + + +1. 使用用户指定的磁盘格式创建一个 StorageClass。 + + ```yaml + apiVersion: storage.k8s.io/v1 + kind: StorageClass + metadata: + name: fast + provisioner: kubernetes.io/vsphere-volume + parameters: + diskformat: zeroedthick + ``` + + + `diskformat`: `thin`, `zeroedthick` 和 `eagerzeroedthick`。默认值: `"thin"`。 + + +2. 在用户指定的数据存储上创建磁盘格式的 StorageClass。 + + ```yaml + apiVersion: storage.k8s.io/v1 + kind: StorageClass + metadata: + name: fast + provisioner: kubernetes.io/vsphere-volume + parameters: + diskformat: zeroedthick + datastore: VSANDatastore + ``` + + + `datastore`:用户也可以在 StorageClass 中指定数据存储。卷将在 storage class 中指定的数据存储上创建,在这种情况下是 `VSANDatastore`。该字段是可选的。如果未指定数据存储,则将在用于初始化 vSphere Cloud Provider 的 vSphere 配置文件中指定的数据存储上创建该卷。 + + +3. Kubernetes 中的存储策略管理 + + + * 使用现有的 vCenter SPBM 策略 + + vSphere 用于存储管理的最重要特性之一是基于策略的管理。基于存储策略的管理(SPBM)是一个存储策略框架,提供单一的统一控制平面的跨越广泛的数据服务和存储解决方案。 SPBM 使能 vSphere 管理员克服先期的存储配置挑战,如容量规划,差异化服务等级和管理容量空间。 + + SPBM 策略可以在 StorageClass 中使用 `storagePolicyName` 参数声明。 + + + * Kubernetes 内的 Virtual SAN 策略支持 + + Vsphere Infrastructure(VI)管理员将能够在动态卷配置期间指定自定义 Virtual SAN 存储功能。您现在可以定义存储需求,例如性能和可用性,当动态卷供分配时会以存储功能的形式提供。存储功能需求会转换为 Virtual SAN 策略,然后当 persistent volume(虚拟磁盘)在创建时,会将其推送到 Virtual SAN 层。虚拟磁盘分布在 Virtual SAN 数据存储中以满足要求。 + + 更多有关 persistent volume 管理的存储策略的详细信息, + 您可以参考 [基于存储策略的动态分配卷管理](https://vmware.github.io/vsphere-storage-for-kubernetes/documentation/policy-based-mgmt.html)。 + + +有几个 [vSphere 例子](https://github.com/kubernetes/examples/tree/master/staging/volumes/vsphere) +供您在 Kubernetes for vSphere 中尝试进行 persistent volume 管理。 + +### Ceph RBD + +```yaml +apiVersion: storage.k8s.io/v1 +kind: StorageClass +metadata: + name: fast +provisioner: kubernetes.io/rbd +parameters: + monitors: 10.16.153.105:6789 + adminId: kube + adminSecretName: ceph-secret + adminSecretNamespace: kube-system + pool: kube + userId: kube + userSecretName: ceph-secret-user + userSecretNamespace: default + fsType: ext4 + imageFormat: "2" + imageFeatures: "layering" +``` + + +* `monitors`:Ceph monitor,逗号分隔。该参数是必需的。 +* `adminId`:Ceph 客户端 ID,用于在池 ceph 池中创建映像。默认是 "admin"。 +* `adminSecret`:`adminId` 的 Secret 名称。该参数是必需的。 + 提供的 secret 必须有值为 "kubernetes.io/rbd" 的 type 参数。 +* `adminSecretNamespace`:`adminSecret` 的命名空间。默认是 "default"。 +* `pool`: Ceph RBD 池. 默认是 "rbd"。 +* `userId`:Ceph 客户端 ID,用于映射 RBD 镜像。默认与 `adminId` 相同。 + +* `userSecretName`:用于映射 RBD 镜像的 `userId` 的 Ceph Secret 的名字。 + 它必须与 PVC 存在于相同的 namespace 中。该参数是必需的。 + 提供的 secret 必须具有值为 "kubernetes.io/rbd" 的 type 参数,例如以这样的方式创建: + + ```shell + kubectl create secret generic ceph-secret --type="kubernetes.io/rbd" \ + --from-literal=key='QVFEQ1pMdFhPUnQrSmhBQUFYaERWNHJsZ3BsMmNjcDR6RFZST0E9PQ==' \ + --namespace=kube-system + ``` + + + +* `userSecretNamespace`:`userSecretName` 的命名空间。 +* `fsType`:Kubernetes 支持的 fsType。默认:`"ext4"`。 +* `imageFormat`:Ceph RBD 镜像格式,"1" 或者 "2"。默认值是 "1"。 +* `imageFeatures`:这个参数是可选的,只能在你将 `imageFormat` 设置为 "2" 才使用。 + 目前支持的功能只是 `layering`。默认是 "",没有功能打开。 + +### Quobyte + +```yaml +apiVersion: storage.k8s.io/v1 +kind: StorageClass +metadata: + name: slow +provisioner: kubernetes.io/quobyte +parameters: + quobyteAPIServer: "http://138.68.74.142:7860" + registry: "138.68.74.142:7861" + adminSecretName: "quobyte-admin-secret" + adminSecretNamespace: "kube-system" + user: "root" + group: "root" + quobyteConfig: "BASE" + quobyteTenant: "DEFAULT" +``` + + + +* `quobyteAPIServer`:Quobyte API 服务器的格式是 + `"http(s)://api-server:7860"` +* `registry`:用于挂载卷的 Quobyte registry。你可以指定 registry 为 ``:`` + 或者如果你想指定多个 registry,你只需要在他们之间添加逗号,例如 + ``:,:,:``。 + 主机可以是一个 IP 地址,或者如果您有正在运行的 DNS,您也可以提供 DNS 名称。 +* `adminSecretNamespace`:`adminSecretName`的 namespace。 + 默认值是 "default"。 + + + +* `adminSecretName`:保存关于 Quobyte 用户和密码的 secret,用于对 API 服务器进行身份验证。 + 提供的 secret 必须有值为 "kubernetes.io/quobyte" 的 type 参数 和 `user` 与 `password` 的键值, + 例如以这种方式创建: + + ```shell + kubectl create secret generic quobyte-admin-secret \ + --type="kubernetes.io/quobyte" --from-literal=key='opensesame' \ + --namespace=kube-system + ``` + + +* `user`:对这个用户映射的所有访问权限。默认是 "root"。 +* `group`:对这个组映射的所有访问权限。默认是 "nfsnobody"。 +* `quobyteConfig`:使用指定的配置来创建卷。您可以创建一个新的配置,或者,可以修改 Web console 或 + quobyte CLI 中现有的配置。默认是 "BASE"。 +* `quobyteTenant`:使用指定的租户 ID 创建/删除卷。这个 Quobyte 租户必须已经于 Quobyte。 + 默认是 "DEFAULT"。 + + +### Azure 磁盘 + + +#### Azure Unmanaged Disk Storage Class(非托管磁盘存储类) + +```yaml +kind: StorageClass +apiVersion: storage.k8s.io/v1 +metadata: + name: slow +provisioner: kubernetes.io/azure-disk +parameters: + skuName: Standard_LRS + location: eastus + storageAccount: azure_storage_account_name +``` + + +* `skuName`:Azure 存储帐户 Sku 层。默认为空。 +* `location`:Azure 存储帐户位置。默认为空。 +* `storageAccount`:Azure 存储帐户名称。如果提供存储帐户,它必须位于与集群相同的资源组中,并且 `location` 是被忽略的。如果未提供存储帐户,则会在与群集相同的资源组中创建新的存储帐户。 + + +#### 新的 Azure 磁盘 Storage Class(从 v1.7.2 开始) + +```yaml +kind: StorageClass +apiVersion: storage.k8s.io/v1 +metadata: + name: slow +provisioner: kubernetes.io/azure-disk +parameters: + storageaccounttype: Standard_LRS + kind: Shared +``` + + +* `storageaccounttype`:Azure 存储帐户 Sku 层。默认为空。 +* `kind`:可能的值是 `shared`(默认)、`dedicated` 和 `managed`。 + 当 `kind` 的值是 `shared` 时,所有非托管磁盘都在集群的同一个资源组中的几个共享存储帐户中创建。 + 当 `kind` 的值是 `dedicated` 时,将为在集群的同一个资源组中新的非托管磁盘创建新的专用存储帐户。 + + +- Premium VM 可以同时添加 Standard_LRS 和 Premium_LRS 磁盘,而 Standard 虚拟机只能添加 Standard_LRS 磁盘。 +- 托管虚拟机只能连接托管磁盘,非托管虚拟机只能连接非托管磁盘。 + + +### Azure 文件 + +```yaml +kind: StorageClass +apiVersion: storage.k8s.io/v1 +metadata: + name: azurefile +provisioner: kubernetes.io/azure-file +parameters: + skuName: Standard_LRS + location: eastus + storageAccount: azure_storage_account_name +``` + + +* `skuName`:Azure 存储帐户 Sku 层。默认为空。 +* `location`:Azure 存储帐户位置。默认为空。 +* `storageAccount`:Azure 存储帐户名称。默认为空。 + 如果不提供存储帐户,会搜索所有与资源相关的存储帐户,以找到一个匹配 `skuName` 和 `location` 的账号。 + 如果提供存储帐户,它必须存在于与集群相同的资源组中,`skuName` 和 `location` 会被忽略。 +* `secretNamespace`:包含 Azure 存储帐户名称和密钥的密钥的名称空间。 默认值与 Pod 相同。 +* `secretName`:包含 Azure 存储帐户名称和密钥的密钥的名称。 默认值为 `azure-storage-account--secret` +* `readOnly`:指示是否将存储安装为只读的标志。默认为 false,表示 读/写 挂载。 该设置也会影响VolumeMounts中的 `ReadOnly` 设置。 + + +在存储分配期间,为挂载凭证创建一个名为 `secretName` 的 secret。如果集群同时启用了 [RBAC](/docs/admin/authorization/rbac/) 和 [Controller Roles](/docs/admin/authorization/rbac/#controller-roles), +为 `system:controller:persistent-volume-binder` 的 clusterrole 添加 `secret` 资源的 `create` 权限。 + + + +在多租户上下文中,强烈建议显式设置 `secretNamespace` 的值,否则其他用户可能会读取存储帐户凭据。 + + +### Portworx 卷 + +```yaml +apiVersion: storage.k8s.io/v1 +kind: StorageClass +metadata: + name: portworx-io-priority-high +provisioner: kubernetes.io/portworx-volume +parameters: + repl: "1" + snap_interval: "70" + io_priority: "high" + +``` + + +* `fs`:选择的文件系统:`none/xfs/ext4`(默认:`ext4`)。 +* `block_size`:以 Kbytes 为单位的块大小(默认值:`32`)。 +* `repl`:同步副本数量,以复制因子 `1..3`(默认值:`1`)的形式提供。 + 这里需要填写字符串,即,`"1"` 而不是 `1`。 +* `io_priority`:决定是否从更高性能或者较低优先级存储创建卷 `high/medium/low`(默认值:`low`)。 +* `snap_interval`:触发快照的时钟/时间间隔(分钟)。快照是基于与先前快照的增量变化,0 是禁用快照(默认:`0`)。 + 这里需要填写字符串,即,是 `"70"` 而不是 `70`。 +* `aggregation_level`:指定卷分配到的块数量,0 表示一个非聚合卷(默认:`0`)。 + 这里需要填写字符串,即,是 `"0"` 而不是 `0`。 +* `ephemeral`:指定卷在卸载后进行清理还是持久化。 `emptyDir` 的使用场景可以将这个值设置为 true , + `persistent volumes` 的使用场景可以将这个值设置为 false(例如 Cassandra 这样的数据库)`true/false`(默认为 `false`)。这里需要填写字符串,即,是 `"true"` 而不是 `true`。 + +### ScaleIO + +```yaml +kind: StorageClass +apiVersion: storage.k8s.io/v1 +metadata: + name: slow +provisioner: kubernetes.io/scaleio +parameters: + gateway: https://192.168.99.200:443/api + system: scaleio + protectionDomain: pd0 + storagePool: sp1 + storageMode: ThinProvisioned + secretRef: sio-secret + readOnly: false + fsType: xfs +``` + + +* `provisioner`:属性设置为 `kubernetes.io/scaleio` +* `gateway` 到 ScaleIO API 网关的地址(必需) +* `system`:ScaleIO 系统的名称(必需) +* `protectionDomain`:ScaleIO 保护域的名称(必需) +* `storagePool`:卷存储池的名称(必需) +* `storageMode`:存储提供模式:`ThinProvisioned`(默认)或 `ThickProvisioned` +* `secretRef`:对已配置的 Secret 对象的引用(必需) +* `readOnly`:指定挂载卷的访问模式(默认为 false) +* `fsType`:卷的文件系统(默认是 ext4) + + +ScaleIO Kubernetes 卷插件需要配置一个 Secret 对象。 +secret 必须用 `kubernetes.io/scaleio` 类型创建,并与引用它的 PVC 所属的名称空间使用相同的值 +如下面的命令所示: + +```shell +kubectl create secret generic sio-secret --type="kubernetes.io/scaleio" \ +--from-literal=username=sioadmin --from-literal=password=d2NABDNjMA== \ +--namespace=default +``` + +### StorageOS + +```yaml +apiVersion: storage.k8s.io/v1 +kind: StorageClass +metadata: + name: fast +provisioner: kubernetes.io/storageos +parameters: + pool: default + description: Kubernetes volume + fsType: ext4 + adminSecretNamespace: default + adminSecretName: storageos-secret +``` + + +* `pool`:分配卷的 StorageOS 分布式容量池的名称。如果未指定,则使用通常存在的 `default` 池。 +* `description`:分配给动态创建的卷的描述。所有卷描述对于 storage class 都是相同的, + 但不同的 storage class 可以使用不同的描述,以区分不同的使用场景。 + 默认为 `Kubernetas volume`。 +* `fsType`:请求的默认文件系统类型。请注意,在 StorageOS 中用户定义的规则可以覆盖此值。默认为 `ext4` +* `adminSecretNamespace`:API 配置 secret 所在的命名空间。如果设置了 adminSecretName,则是必需的。 +* `adminSecretName`:用于获取 StorageOS API 凭证的 secret 名称。如果未指定,则将尝试默认值。 + + +StorageOS Kubernetes 卷插件可以使 Secret 对象来指定用于访问 StorageOS API 的端点和凭据。 +只有当默认值已被更改时,这才是必须的。 +secret 必须使用 `kubernetes.io/storageos` 类型创建,如以下命令: + +```shell +kubectl create secret generic storageos-secret \ +--type="kubernetes.io/storageos" \ +--from-literal=apiAddress=tcp://localhost:5705 \ +--from-literal=apiUsername=storageos \ +--from-literal=apiPassword=storageos \ +--namespace=default +``` + + +用于动态分配卷的 Secret 可以在任何名称空间中创建,并通过 `adminSecretNamespace` 参数引用。 +预先配置的卷使用的 Secret 必须在与引用它的 PVC 在相同的名称空间中。 + + +### 本地 + +{{< feature-state for_k8s_version="v1.14" state="stable" >}} + +```yaml +kind: StorageClass +apiVersion: storage.k8s.io/v1 +metadata: + name: local-storage +provisioner: kubernetes.io/no-provisioner +volumeBindingMode: WaitForFirstConsumer +``` + + +本地卷还不支持动态分配,然而还是需要创建 StorageClass 以延迟卷绑定,直到完成 pod 的调度。这是由 `WaitForFirstConsumer` 卷绑定模式指定的。 + + +延迟卷绑定使得调度器在为 PersistentVolumeClaim 选择一个合适的 PersistentVolume 时能考虑到所有 pod 的调度限制。 + +{{% /capture %}} diff --git a/content/zh/docs/concepts/storage/storage-limits.md b/content/zh/docs/concepts/storage/storage-limits.md new file mode 100644 index 0000000000..9b077d9d41 --- /dev/null +++ b/content/zh/docs/concepts/storage/storage-limits.md @@ -0,0 +1,144 @@ +--- +title: 特定于节点的卷数限制 +content_template: templates/concept +--- + +{{% capture overview %}} + + + +此页面描述了各个云供应商可关联至一个节点的最大卷数。 + + + +谷歌、亚马逊和微软等云供应商通常对可以关联到节点的卷数量进行限制。 +Kubernetes 需要尊重这些限制。 否则,在节点上调度的 Pod 可能会卡住去等待卷的关联。 + +{{% /capture %}} + +{{% capture body %}} + + + +## Kubernetes 的默认限制 + +The Kubernetes 调度器对关联于一个节点的卷数有默认限制: + + + + + + +
云服务每节点最大卷数
Amazon Elastic Block Store (EBS)39
Google Persistent Disk16
Microsoft Azure Disk Storage16
+ + + +## 自定义限制 + +您可以通过设置 `KUBE_MAX_PD_VOLS` 环境变量的值来设置这些限制,然后再启动调度器。 + +如果设置的限制高于默认限制,请谨慎使用。请参阅云提供商的文档以确保节点可支持您设置的限制。 + +此限制应用于整个集群,所以它会影响所有节点。 + + + +## 动态卷限制 + +{{< feature-state state="beta" for_k8s_version="v1.12" >}} + + + +Kubernetes 1.11 引入了基于节点类型的动态卷限制的支持作为 Alpha 功能。 +在 Kubernetes 1.12 中,此功能升级到 Beta 版,将默认开启。 + +以下卷类型支持动态卷限制。 + +- Amazon EBS +- Google Persistent Disk +- Azure Disk +- CSI + + + +启用动态卷限制功能后,Kubernetes 会自动确定节点类型并确保节点上可关联的卷数目合规。 例如: + + + +* 在 +Google Compute Engine环境中, +[根据节点类型](https://cloud.google.com/compute/docs/disks/#pdnumberlimits)最多可以将128个卷关联到节点。 + +* 对于 M5、C5、R5、T3 和 Z1D 类型实例的 Amazon EBS 磁盘,Kubernetes 仅允许 25 个卷关联到节点。 +对于 ec2 上的其他实例类型 +Amazon Elastic Compute Cloud (EC2), +Kubernetes 允许 39 个卷关联至节点。 + +* 在 Azure 环境中, 根据节点类型,最多 64 个磁盘可以关联至一个节点。 +更多详细信息,请参阅[Azure 虚拟机的数量大小](https://docs.microsoft.com/en-us/azure/virtual-machines/windows/sizes)。 + +* 对于 CSI,任何符合 CSI 规范中卷关联限制的驱动都将这些限制作为 Node 的 allocatable 属性。调度器不会往已经达到其容量限制的任何节点上调度具有卷的Pod。 参考 [CSI 规范](https://github.com/container-storage-interface/spec/blob/master/spec.md#nodegetinfo) 获取更多详细信息。 + +{{% /capture %}} diff --git a/content/zh/docs/concepts/storage/volume-snapshot-classes.md b/content/zh/docs/concepts/storage/volume-snapshot-classes.md new file mode 100644 index 0000000000..a0ef82a330 --- /dev/null +++ b/content/zh/docs/concepts/storage/volume-snapshot-classes.md @@ -0,0 +1,92 @@ +--- +title: 卷快照类 +content_template: templates/concept +weight: 20 +--- + +{{% capture overview %}} + + + +本文档描述了 Kubernetes 中 `VolumeSnapshotClass` 的概念。 建议熟悉[卷快照(Volume Snapshots)](/docs/concepts/storage/volume-snapshots/)和[存储类(Storage Class)](/docs/concepts/storage/storage-classes)。 + +{{% /capture %}} + + +{{% capture body %}} + + + +## 介绍 + +就像 `StorageClass` 为管理员提供了一种在配置卷时描述存储“类”的方法,`VolumeSnapshotClass` 提供了一种在配置卷快照时描述存储“类”的方法。 + + + +## VolumeSnapshotClass 资源 + +每个 `VolumeSnapshotClass` 都包含 `snapshotter` 和 `parameters` 字段,当需要动态配置属于该类的 `VolumeSnapshot` 时使用。 + +`VolumeSnapshotClass` 对象的名称很重要,是用户可以请求特定类的方式。 +管理员在首次创建 `VolumeSnapshotClass` 对象时设置类的名称和其他参数,对象一旦创建就无法更新。 + +管理员可以为不请求任何特定类绑定的 VolumeSnapshots 指定默认的 `VolumeSnapshotClass`。 + + +```yaml +apiVersion: snapshot.storage.k8s.io/v1alpha1 +kind: VolumeSnapshotClass +metadata: + name: csi-hostpath-snapclass +snapshotter: csi-hostpath +parameters: +``` + + + +### 快照生成器(Snapshotter) + +卷快照类具有一个快照生成器,用于确定配置 VolumeSnapshot 的 CSI 卷插件。 必须指定此字段。 + + + +## 参数 + +卷快照类具有描述属于卷快照类的卷快照参数。 可根据 `snapshotter` 接受不同的参数。 + +{{% /capture %}} diff --git a/content/zh/docs/concepts/storage/volumes.md b/content/zh/docs/concepts/storage/volumes.md new file mode 100644 index 0000000000..0631a59313 --- /dev/null +++ b/content/zh/docs/concepts/storage/volumes.md @@ -0,0 +1,2390 @@ +--- +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) + * [cinder](#cinder) + * [configMap](#configmap) + * [csi](#csi) + * [downwardAPI](#downwardapi) + * [emptyDir](#emptydir) + * [fc (fibre channel)](#fc) + * [flexVolume](#flexVolume) + * [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)。 + + +#### CSI迁移 + +{{< feature-state for_k8s_version="v1.15" state="alpha" >}} + + + +启用azureDisk的CSI迁移功能后,它会将所有插件操作从现有的内建插件填添加disk.csi.azure.com容器存储接口(CSI)驱动程序中。 +为了使用此功能,必须在群集上安装 [Azure磁盘CSI驱动程序](https://github.com/kubernetes-sigs/azuredisk-csi-driver), +并且 `CSIMigration` 和 `CSIMigrationAzureDisk` Alpha功能 必须启用。 + +### 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)。 + + +#### CSI迁移 + +{{< feature-state for_k8s_version="v1.15" state="alpha" >}} + + + +启用azureFile的CSI迁移功能后,它会将所有插件操作从现有的内建插件填添加file.csi.azure.com容器存储接口(CSI)驱动程序中。 +为了使用此功能,必须在群集上安装 [Azure文件CSI驱动程序](https://github.com/kubernetes-sigs/azurefile-csi-driver), +并且 `CSIMigration` 和 `CSIMigrationAzureFile` Alpha功能 必须启用。 + +### 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" >}}/volumes/cephfs/)。 + +### cinder {#cinder} + +{{< note >}} + + + +先决条件:配置了OpenStack Cloud Provider 的 Kubernetes。 有关 cloudprovider 配置,请参考 [cloud provider openstack](https://kubernetes.io/docs/concepts/cluster-administration/cloud-providers/#openstack)。 + +{{< /note >}} + + + +`cinder` 用于将 OpenStack Cinder 卷安装到 Pod 中。 + +#### Cinder Volume示例配置 + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: test-cinder +spec: + containers: + - image: k8s.gcr.io/test-webserver + name: test-cinder-container + volumeMounts: + - mountPath: /test-cinder + name: test-volume + volumes: + - name: test-volume + # This OpenStack volume must already exist. + cinder: + volumeID: + fsType: ext4 +``` + + +#### CSI迁移 + +{{< feature-state for_k8s_version="v1.14" state="alpha" >}} + + + +启用Cinder的CSI迁移功能后,它会将所有插件操作从现有的内建插件填添加 `cinder.csi.openstack.org` 容器存储接口(CSI)驱动程序中。 +为了使用此功能,必须在群集上安装 [Openstack Cinder CSI驱动程序](https://github.com/kubernetes/cloud-provider-openstack/blob/master/docs/using-cinder-csi-plugin.md), +并且 `CSIMigration` 和 `CSIMigrationOpenStack` Alpha功能 必须启用。 + + +### 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 +``` + + +#### CSI迁移 + +{{< feature-state for_k8s_version="v1.14" state="alpha" >}} + + + +启用 GCE PD 的 CSI 迁移功能后,它会将所有插件操作从现有的内建插件填添加 `pd.csi.storage.gke.io` 容器存储接口( CSI )驱动程序中。 +为了使用此功能,必须在群集上安装 [GCE PD CSI驱动程序](https://github.com/kubernetes-sigs/gcp-compute-persistent-disk-csi-driver), +并且 `CSIMigration` 和 `CSIMigrationGCE` Alpha功能 必须启用。 + + + + +### 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" >}}/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" >}}/volumes/iscsi)。 + + + +### local {#local} + +{{< feature-state for_k8s_version="v1.14" state="stable" >}} + +{{< 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-sigs/sig-storage-local-static-provisioner)。 + +{{< 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](https://portworx.com/use-case/kubernetes-storage/) 支持对服务器上存储的指纹处理、基于存储能力进行分层以及跨多个服务器整合存储容量。 +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 支持{{< glossary_tooltip text="容器存储接口" term_id="csi" >}}。 +推荐使用 CSI 插件以在 Kubernetes 中使用 Quobyte 卷。 +Quobyte 的 GitHub 项目具有[说明(https://github.com/quobyte/quobyte/quobyte-csi#quobyte-csi)以及使用示例来部署 CSI 的 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" >}}/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/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.15" state="beta" >}} + + + + +使用 `subPathExpr` 字段从 Downward API 环境变量构造 `subPath` 目录名。 +在使用此特性之前,必须启用 `VolumeSubpathEnvExpansion` 功能开关。 +`subPath` 和 `subPathExpr` 属性是互斥的。 + + + +在这个示例中,Pod 基于 Downward API 中的 Pod 名称,使用 `subPathExpr` 在 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 + subPathExpr: $(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 v1.13 正式 GA。 + +{{< note >}} + +{{< /note >}} + +Kubernetes v1.13中不支持 CSI 规范版本0.2和0.3,并将在以后的版本中删除。 + +{{< note >}} + + +CSI驱动程序可能并非在所有Kubernetes版本中都兼容。 +请查看特定CSI驱动程序的文档,以获取每个 Kubernetes 版本所支持的部署步骤以及兼容性列表。 + +{{< /note >}} + + + +一旦在 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.14" state="beta" >}} + + + +从 1.11 版本开始,CSI 引入了对原始块卷的支持。该特性依赖于在 Kubernetes 的之前版本中引入的原始块卷(Raw Block Volume)功能。 +该特性将使具有外部 CSI 驱动程序的供应商能够在 Kubernetes 工作负载中实现原始块卷支持。 + + + +CSI块卷支持功能已启用,但默认情况下启用。必须为此功能启用的两个功能是“ BlockVolume”和“ CSIBlockVolume”。 + +``` +--feature-gates=BlockVolume=true,CSIBlockVolume=true +``` + + +学习怎样[安装您的带有块卷支持的 PV/PVC](/docs/concepts/storage/persistent-volumes/#raw-block-volume-support)。 + + + +#### CSI临时卷 + +{{< feature-state for_k8s_version="v1.16" state="beta" >}} + + + +此功能使 CSI 卷可以直接嵌入 Pod 规范中,而不是 PersistentVolume 中。 以这种方式指定的卷是临时的,不会在 Pod 重新启动后持续存在。 + +实例: + +```yaml +kind: Pod +apiVersion: v1 +metadata: + name: my-csi-app +spec: + containers: + - name: my-frontend + image: busybox + volumeMounts: + - mountPath: "/data" + name: my-csi-inline-vol + command: [ "sleep", "1000000" ] + volumes: + - name: my-csi-inline-vol + csi: + driver: inline.storage.kubernetes.io + volumeAttributes: + foo: bar +``` + + + +此功能需要启用 CSIInlineVolume 功能门。 从Kubernetes 1.16开始默认启用它。 + +CSI 临时卷仅由一部分 CSI 驱动程序支持。 请在[此处](https://kubernetes-csi.github.io/docs/drivers.html)查看 CSI 驱动程序列表。 + + + +#开发人员资源 +有关如何开发 CSI 驱动程序的更多信息,请参考[kubernetes-csi文档](https://kubernetes-csi.github.io/docs/) + +#### 从 in-tree 插件迁移到 CSI 驱动程序 + +{{< feature-state for_k8s_version="v1.14" state="alpha" >}} + + + +启用 CSI 迁移功能后,会将针对现有 in-tree 插件的操作定向到相应的 CSI 插件(应安装和配置)。 +该功能实现了必要的转换逻辑和填充以无缝方式重新路由操作。 因此,操作员在过渡到取代树内插件的CSI驱动程序时,无需对现有存储类,PV 或 PVC(指 in-tree 插件)进行任何配置更改。 +在 Alpha 状态下,受支持的操作和功能包括供应/删除,附加/分离,安装/卸载和调整卷大小。 +上面的 "卷类型" 部分列出了支持 CSI 迁移并已实现相应 CSI 驱动程序的树内插件。 + +### FlexVolume {#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/sig-storage/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 %}}