容器中的磁盘文件是短暂的,这对于在容器中运行的非平凡应用程序来说会带来一些问题。一个问题发生在容器崩溃或停止时。容器状态不会保存,因此在容器生命周期内创建或修改的所有文件都会丢失。在崩溃期间,kubelet 会以干净的状态重新启动容器。另一个问题发生在多个容器在 Pod 中运行且需要共享文件时。在所有容器之间设置和访问共享文件系统可能很困难。Kubernetes 抽象解决了这两个问题。建议您熟悉 Pod

背景

Kubernetes 支持多种类型的卷。一个 Pod 可以同时使用任意数量的卷类型。 短暂卷 的生命周期与 Pod 相同,而 持久卷 的存在时间超过 Pod 的生命周期。当 Pod 不再存在时,Kubernetes 会销毁短暂卷;但是,Kubernetes 不会销毁持久卷。对于给定 Pod 中的任何类型的卷,数据都会在容器重新启动时保留。

从根本上说,卷是一个目录,可能包含一些数据,Pod 中的容器可以访问它。该目录是如何产生的,支持它的介质以及它的内容由使用的特定卷类型决定。

要使用卷,请在 .spec.volumes 中指定要为 Pod 提供的卷,并在 .spec.containers[*].volumeMounts 中声明将这些卷装载到容器中的位置。容器中的进程看到一个文件系统视图,该视图由 容器镜像 的初始内容加上在容器内部装载的卷(如果已定义)组成。该进程看到一个根文件系统,它最初与容器镜像的内容匹配。对该文件系统层次结构内的任何写入,如果允许,都会影响该进程在执行后续文件系统访问时看到的视图。卷在镜像中的 指定路径 处装载。对于 Pod 中定义的每个容器,您必须独立指定要装载每个容器使用的卷的位置。

卷不能在其他卷内装载(但请参阅 使用 subPath 以了解相关机制)。此外,卷不能包含到不同卷中的任何内容的硬链接。

卷类型

Kubernetes 支持多种类型的卷。

awsElasticBlockStore(已弃用)

在 Kubernetes 1.31 中,awsElasticBlockStore 类型的所有操作都被重定向到 ebs.csi.aws.com CSI 驱动程序。

AWSElasticBlockStore 内置存储驱动程序在 Kubernetes v1.19 版本中已弃用,然后在 v1.27 版本中完全删除。

Kubernetes 项目建议您使用 AWS EBS 第三方存储驱动程序。

azureDisk(已弃用)

在 Kubernetes 1.31 中,azureDisk 类型的所有操作都被重定向到 disk.csi.azure.com CSI 驱动程序。

AzureDisk 内置存储驱动程序在 Kubernetes v1.19 版本中已弃用,然后在 v1.27 版本中完全删除。

Kubernetes 项目建议您使用 Azure Disk 第三方存储驱动程序。

azureFile(已弃用)

功能状态: Kubernetes v1.21 [已弃用]

azureFile 卷类型将 Microsoft Azure 文件卷(SMB 2.1 和 3.0)装载到 Pod 中。

有关更多详细信息,请参阅 azureFile 卷插件

azureFile CSI 迁移

功能状态: Kubernetes v1.26 [稳定]

azureFileCSIMigration 功能(如果启用)会将所有插件操作从现有的内置插件重定向到 file.csi.azure.com 容器存储接口 (CSI) 驱动程序。为了使用此功能,必须在集群上安装 Azure 文件 CSI 驱动程序 并且必须启用 CSIMigrationAzureFile 功能门控

Azure 文件 CSI 驱动程序不支持使用具有不同 fsgroups 的相同卷。如果启用了 CSIMigrationAzureFile,则完全不支持使用具有不同 fsgroups 的相同卷。

azureFile CSI 迁移完成

功能状态: Kubernetes v1.21 [alpha]

要禁用控制器管理器和 kubelet 加载 azureFile 存储插件,请将 InTreePluginAzureFileUnregister 标志设置为 true

cephfs(已删除)

Kubernetes 1.31 不包含 cephfs 卷类型。

cephfs 内置存储驱动程序在 Kubernetes v1.28 版本中已弃用,然后在 v1.31 版本中完全删除。

cinder(已弃用)

在 Kubernetes 1.31 中,cinder 类型的所有操作都被重定向到 cinder.csi.openstack.org CSI 驱动程序。

OpenStack Cinder 内置存储驱动程序在 Kubernetes v1.11 版本中已弃用,然后在 v1.26 版本中完全删除。

Kubernetes 项目建议您使用 OpenStack Cinder 第三方存储驱动程序。

configMap

一个 ConfigMap 提供了一种将配置数据注入 Pod 的方法。存储在 ConfigMap 中的数据可以在类型为 configMap 的卷中引用,然后由在 Pod 中运行的容器化应用程序使用。

在引用 ConfigMap 时,您提供 ConfigMap 的名称。您可以自定义要用于 ConfigMap 中特定条目的路径。以下配置展示了如何将 log-config ConfigMap 装载到名为 configmap-pod 的 Pod 上

apiVersion: v1
kind: Pod
metadata:
  name: configmap-pod
spec:
  containers:
    - name: test
      image: busybox:1.28
      command: ['sh', '-c', 'echo "The app is running!" && tail -f /dev/null']
      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 路径。请注意,此路径是从卷的 mountPath 和使用 log_level 为键的 path 推导出来的。

downwardAPI

downwardAPI 卷使 下行 API 数据可供应用程序使用。在卷内,您可以找到作为纯文本格式的只读文件公开的数据。

请参阅 通过文件向容器公开 Pod 信息 以了解更多信息。

emptyDir

对于定义了 emptyDir 卷的 Pod,该卷是在 Pod 被分配到节点时创建的。顾名思义,emptyDir 卷最初是空的。Pod 中的所有容器都可以读取和写入 emptyDir 卷中的相同文件,尽管该卷可以在每个容器中的相同或不同路径处装载。当 Pod 因任何原因从节点中删除时,emptyDir 中的数据将被永久删除。

emptyDir 的一些用途包括

  • 临时空间,例如用于基于磁盘的归并排序
  • 对长时间计算进行检查点以从崩溃中恢复
  • 保存内容管理器容器获取的文件,同时 Web 服务器容器提供服务数据

emptyDir.medium 字段控制 emptyDir 卷的存储位置。默认情况下,emptyDir 卷存储在支持节点的任何介质上,例如磁盘、SSD 或网络存储,具体取决于您的环境。如果您将 emptyDir.medium 字段设置为 "Memory",Kubernetes 会为您装载一个 tmpfs(基于 RAM 的文件系统)。虽然 tmpfs 速度非常快,但请注意,与磁盘不同,您写入的文件会占用写入它们的容器的内存限制。

可以为默认介质指定大小限制,这限制了emptyDir卷的容量。存储空间从节点临时存储分配。如果从其他来源(例如日志文件或镜像覆盖层)填满了,则emptyDir可能会在达到此限制之前耗尽容量。

emptyDir 配置示例

apiVersion: v1
kind: Pod
metadata:
  name: test-pd
spec:
  containers:
  - image: registry.k8s.io/test-webserver
    name: test-container
    volumeMounts:
    - mountPath: /cache
      name: cache-volume
  volumes:
  - name: cache-volume
    emptyDir:
      sizeLimit: 500Mi

fc(光纤通道)

fc卷类型允许将现有的光纤通道块存储卷挂载到 Pod 中。您可以使用卷配置中的targetWWNs参数指定单个或多个目标 WWN(世界范围名称)。如果指定了多个 WWN,则 targetWWNs 预期这些 WWN 来自多路径连接。

有关更多详细信息,请参阅光纤通道示例

gcePersistentDisk(已弃用)

在 Kubernetes 1.31 中,针对树内gcePersistentDisk类型的所有操作都会重定向到pd.csi.storage.gke.io CSI驱动程序。

gcePersistentDisk树内存储驱动程序在 Kubernetes v1.17 版本中已弃用,并在 v1.28 版本中完全删除。

Kubernetes 项目建议您改用Google Compute Engine 持久磁盘 CSI第三方存储驱动程序。

gitRepo(已弃用)

gitRepo卷是卷插件的一个示例。此插件会挂载一个空目录,并将 git 存储库克隆到此目录中,供您的 Pod 使用。

以下是一个gitRepo卷的示例

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(已删除)

Kubernetes 1.31 不包含glusterfs卷类型。

GlusterFS 树内存储驱动程序在 Kubernetes v1.25 版本中已弃用,并在 v1.26 版本中完全删除。

hostPath

hostPath卷将主机节点文件系统中的文件或目录挂载到您的 Pod 中。这并非大多数 Pod 所需,但它为某些应用程序提供了强大的逃生舱。

hostPath的一些用途包括

  • 运行需要访问节点级系统组件的容器(例如,将系统日志传输到中央位置的容器,使用/var/log的只读挂载访问这些日志)
  • 使存储在主机系统上的配置文件对静态 Pod只读;与普通 Pod 不同,静态 Pod 无法访问 ConfigMap

hostPath卷类型

除了必需的path属性之外,您还可以为hostPath卷选择性地指定type

type的可用值包括

行为
‌""空字符串(默认值)用于向后兼容,这意味着在挂载hostPath卷之前不会执行任何检查。
DirectoryOrCreate如果在给定路径下不存在任何内容,则将根据需要在该路径下创建一个空目录,权限设置为 0755,具有与 Kubelet 相同的组和所有权。
Directory给定路径下必须存在一个目录
FileOrCreate如果在给定路径下不存在任何内容,则将根据需要在该路径下创建一个空文件,权限设置为 0644,具有与 Kubelet 相同的组和所有权。
File给定路径下必须存在一个文件
Socket给定路径下必须存在一个 UNIX 套接字
CharDevice(仅限 Linux 节点) 给定路径下必须存在一个字符设备
BlockDevice(仅限 Linux 节点) 给定路径下必须存在一个块设备

在底层主机上创建的一些文件或目录可能仅供 root 访问。然后,您需要将进程作为 root 在特权容器中运行,或者修改主机上的文件权限,以能够从(或写入)hostPath卷中读取(或写入)。

hostPath 配置示例


---
# This manifest mounts /data/foo on the host as /foo inside the
# single container that runs within the hostpath-example-linux Pod.
#
# The mount into the container is read-only.
apiVersion: v1
kind: Pod
metadata:
  name: hostpath-example-linux
spec:
  os: { name: linux }
  nodeSelector:
    kubernetes.io/os: linux
  containers:
  - name: example-container
    image: registry.k8s.io/test-webserver
    volumeMounts:
    - mountPath: /foo
      name: example-volume
      readOnly: true
  volumes:
  - name: example-volume
    # mount /data/foo, but only if that directory already exists
    hostPath:
      path: /data/foo # directory location on host
      type: Directory # this field is optional


---
# This manifest mounts C:\Data\foo on the host as C:\foo, inside the
# single container that runs within the hostpath-example-windows Pod.
#
# The mount into the container is read-only.
apiVersion: v1
kind: Pod
metadata:
  name: hostpath-example-windows
spec:
  os: { name: windows }
  nodeSelector:
    kubernetes.io/os: windows
  containers:
  - name: example-container
    image: microsoft/windowsservercore:1709
    volumeMounts:
    - name: example-volume
      mountPath: "C:\\foo"
      readOnly: true
  volumes:
    # mount C:\Data\foo from the host, but only if that directory already exists
  - name: example-volume
    hostPath:
      path: "C:\\Data\\foo" # directory location on host
      type: Directory       # this field is optional

hostPath FileOrCreate 配置示例

以下清单定义了一个 Pod,它将/var/local/aaa挂载到 Pod 中的单个容器内。如果节点尚未具有/var/local/aaa路径,则 kubelet 会将其创建为一个目录,然后将其挂载到 Pod 中。

如果/var/local/aaa已存在,但不是目录,则 Pod 无法启动。此外,kubelet 会尝试在该目录中创建一个名为/var/local/aaa/1.txt的文件(如从主机看到的那样);如果该路径下已存在某些内容,但不是普通文件,则 Pod 无法启动。

以下是一个示例清单

apiVersion: v1
kind: Pod
metadata:
  name: test-webserver
spec:
  os: { name: linux }
  nodeSelector:
    kubernetes.io/os: linux
  containers:
  - name: test-webserver
    image: registry.k8s.io/test-webserver:latest
    volumeMounts:
    - mountPath: /var/local/aaa
      name: mydir
    - mountPath: /var/local/aaa/1.txt
      name: myfile
  volumes:
  - name: mydir
    hostPath:
      # Ensure the file directory is created.
      path: /var/local/aaa
      type: DirectoryOrCreate
  - name: myfile
    hostPath:
      path: /var/local/aaa/1.txt
      type: FileOrCreate

image

功能状态: Kubernetes v1.31 [alpha]

image卷源表示一个 OCI 对象(容器镜像或构件),它在 kubelet 的主机机器上可用。

使用image卷源的一个示例是

apiVersion: v1
kind: Pod
metadata:
  name: image-volume
spec:
  containers:
  - name: shell
    command: ["sleep", "infinity"]
    image: debian
    volumeMounts:
    - name: volume
      mountPath: /volume
  volumes:
  - name: volume
    image:
      reference: quay.io/crio/artifact:v1
      pullPolicy: IfNotPresent

卷在 Pod 启动时解析,具体取决于提供的pullPolicy

Always
kubelet 始终尝试拉取引用。如果拉取失败,则 kubelet 会将 Pod 设置为Failed
Never
kubelet 从不拉取引用,仅使用本地镜像或构件。如果任何镜像层不存在于本地,或者该镜像的清单尚未缓存,则 Pod 将变为Failed
IfNotPresent
如果引用不存在于磁盘上,则 kubelet 会拉取。如果引用不存在并且拉取失败,则 Pod 将变为Failed

如果 Pod 被删除并重新创建,则卷会重新解析,这意味着新的远程内容将在 Pod 重新创建时变得可用。在 Pod 启动期间无法解析或拉取镜像会导致容器无法启动,并可能增加显着延迟。失败将使用正常的卷回退重试,并将报告在 Pod 原因和消息中。

此卷可以挂载的对象类型由主机上的容器运行时实现定义,并且至少必须包括容器镜像字段支持的所有有效类型。OCI 对象将被挂载到单个目录(spec.containers[*].volumeMounts.mountPath)中,并且将以只读方式挂载。在 Linux 上,容器运行时通常还会将卷挂载为文件执行被阻止(noexec)。

除此之外

  • 不支持容器的子路径挂载(spec.containers[*].volumeMounts.subpath)。
  • 字段spec.securityContext.fsGroupChangePolicy对这种卷类型没有影响。
  • AlwaysPullImages准入控制器也适用于此卷源,就像容器镜像一样。

image类型提供以下字段

reference
要使用的构件引用。例如,您可以指定registry.k8s.io/conformance:v1.31.0来加载 Kubernetes 一致性测试镜像中的文件。其行为与pod.spec.containers[*].image相同。拉取密钥将以与容器镜像相同的方式组装,方法是查找节点凭据、服务帐户镜像拉取密钥和 Pod 规范镜像拉取密钥。此字段是可选的,允许更高层的配置管理在工作负载控制器(如 Deployment 和 StatefulSet)中默认或覆盖容器镜像。有关容器镜像的更多信息
pullPolicy
拉取 OCI 对象的策略。可能的值为:AlwaysNeverIfNotPresent。如果指定了:latest标记,则默认为Always,否则为IfNotPresent

有关如何使用卷源的更多详细信息,请参阅使用 Pod 的镜像卷示例。

iscsi

iscsi卷允许将现有的 iSCSI(Internet SCSI)卷挂载到您的 Pod 中。与emptyDir不同的是,emptyDir会在 Pod 被删除时被擦除,而iscsi卷的内容会保留,并且卷只是被卸载。这意味着iscsi卷可以预先填充数据,并且该数据可以在 Pod 之间共享。

iSCSI 的一个特性是,它可以被多个消费者同时以只读模式挂载。这意味着您可以预先使用数据集填充卷,然后从您需要的任意数量的 Pod 中并行提供服务。不幸的是,iSCSI 卷只能被一个消费者以读写模式挂载。不允许同时写入。

有关更多详细信息,请参阅 iSCSI 示例

local

local 卷表示挂载的本地存储设备,例如磁盘、分区或目录。

本地卷只能用作静态创建的 PersistentVolume。不支持动态供应。

hostPath 卷相比,local 卷以持久且便携的方式使用,无需手动将 Pod 调度到节点。系统通过查看 PersistentVolume 上的节点亲和性来了解卷的节点约束。

但是,local 卷受底层节点可用性的影响,不适合所有应用程序。如果节点变得不健康,则 Pod 将无法访问 local 卷。使用此卷的 Pod 无法运行。使用 local 卷的应用程序必须能够容忍这种可用性降低,以及潜在的数据丢失,具体取决于底层磁盘的持久性特性。

以下示例显示了使用 local 卷和 nodeAffinity 的 PersistentVolume

apiVersion: v1
kind: PersistentVolume
metadata:
  name: example-pv
spec:
  capacity:
    storage: 100Gi
  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 调度器使用 PersistentVolume nodeAffinity 将这些 Pod 调度到正确的节点。

PersistentVolume volumeMode 可以设置为“Block”(而不是默认值“Filesystem”),以将本地卷公开为原始块设备。

使用本地卷时,建议创建一个具有 volumeBindingMode 设置为 WaitForFirstConsumer 的 StorageClass。有关更多详细信息,请参阅本地 StorageClass 示例。延迟卷绑定可确保 PersistentVolumeClaim 绑定决策也将与 Pod 可能具有的任何其他节点约束一起评估,例如节点资源要求、节点选择器、Pod 亲和性和 Pod 反亲和性。

可以单独运行外部静态供应程序来改进本地卷生命周期的管理。请注意,此供应程序尚不支持动态供应。有关如何运行外部本地供应程序的示例,请参阅 本地卷供应程序用户指南

nfs

nfs 卷允许将现有的 NFS(网络文件系统)共享挂载到 Pod 中。与 emptyDir(在 Pod 被移除时会被擦除)不同,nfs 卷的内容将被保留,并且卷仅被卸载。这意味着 NFS 卷可以预先填充数据,并且这些数据可以在 Pod 之间共享。多个写入器可以同时挂载 NFS。

apiVersion: v1
kind: Pod
metadata:
  name: test-pd
spec:
  containers:
  - image: registry.k8s.io/test-webserver
    name: test-container
    volumeMounts:
    - mountPath: /my-nfs-data
      name: test-volume
  volumes:
  - name: test-volume
    nfs:
      server: my-nfs-server.example.com
      path: /my-nfs-volume
      readOnly: true

有关使用 PersistentVolumes 挂载 NFS 卷的示例,请参阅 NFS 示例

persistentVolumeClaim

persistentVolumeClaim 卷用于将 PersistentVolume 挂载到 Pod 中。PersistentVolumeClaims 是一种允许用户“声明”持久存储(例如 iSCSI 卷)的方法,而不必了解特定云环境的详细信息。

有关更多详细信息,请参阅有关 PersistentVolumes 的信息。

portworxVolume(已弃用)

FEATURE 状态: Kubernetes v1.25 [已弃用]

portworxVolume 是一个弹性块存储层,与 Kubernetes 协同运行。 Portworx 在服务器中对存储进行指纹识别,根据功能进行分层,并聚合跨多个服务器的容量。Portworx 在虚拟机或裸机 Linux 节点中运行。

portworxVolume 可以通过 Kubernetes 动态创建,也可以预先配置并在 Pod 中引用。以下是一个 Pod 引用预先配置的 Portworx 卷的示例

apiVersion: v1
kind: Pod
metadata:
  name: test-portworx-volume-pod
spec:
  containers:
  - image: registry.k8s.io/test-webserver
    name: test-container
    volumeMounts:
    - mountPath: /mnt
      name: pxvol
  volumes:
  - name: pxvol
    # This Portworx volume must already exist.
    portworxVolume:
      volumeID: "pxvol"
      fsType: "<fs-type>"

有关更多详细信息,请参阅 Portworx 卷 示例。

Portworx CSI 迁移

FEATURE 状态: Kubernetes v1.25 [beta]

默认情况下,Kubernetes 1.31 尝试将旧版 Portworx 卷迁移到使用 CSI。(Portworx 的 CSI 迁移自 Kubernetes v1.23 以来一直可用,但仅在 v1.31 版本发布后才默认启用)。如果要禁用自动迁移,可以将 CSIMigrationPortworx 功能门控 设置为 false;您需要对 kube-controller-manager **和** 所有相关 kubelet 进行此更改。

它将所有插件操作从现有的树内插件重定向到 pxd.portworx.com 容器存储接口 (CSI) 驱动程序。 Portworx CSI 驱动程序 必须安装在集群中。

projected

projected 卷将多个现有卷源映射到同一个目录。有关更多详细信息,请参阅 projected 卷

rbd(已移除)

Kubernetes 1.31 不包括 rbd 卷类型。

在 Kubernetes v1.28 版本中,Rados 块设备 (RBD) 树内存储驱动程序及其 csi 迁移支持被弃用,并在 v1.31 版本中被完全移除。

secret

secret 卷用于将敏感信息(例如密码)传递给 Pod。您可以在 Kubernetes API 中存储机密,并将它们作为文件挂载,供 Pod 使用,而无需直接耦合到 Kubernetes。secret 卷由 tmpfs(基于 RAM 的文件系统)支持,因此它们永远不会写入非易失性存储。

有关更多详细信息,请参阅 配置机密

vsphereVolume(已弃用)

vsphereVolume 用于将 vSphere VMDK 卷挂载到您的 Pod 中。当卷被卸载时,卷的内容将被保留。它支持 VMFS 和 VSAN 数据存储。

有关更多信息,请参阅 vSphere 卷 示例。

vSphere CSI 迁移

功能状态: Kubernetes v1.26 [稳定]

在 Kubernetes 1.31 中,树内 vsphereVolume 类型的所有操作都将重定向到 csi.vsphere.vmware.com CSI 驱动程序。

vSphere CSI 驱动程序 必须安装在集群中。您可以在 VMware 的文档页面中找到有关如何迁移树内 vsphereVolume 的更多建议 将树内 vSphere 卷迁移到 vSphere 容器存储插件。如果未安装 vSphere CSI 驱动程序,则无法对使用树内 vsphereVolume 类型创建的 PV 执行卷操作。

您必须运行 vSphere 7.0u2 或更高版本才能迁移到 vSphere CSI 驱动程序。

如果您运行的是除 v1.31 以外的 Kubernetes 版本,请参阅该 Kubernetes 版本的文档。

vSphere CSI 迁移完成

FEATURE 状态: Kubernetes v1.19 [beta]

要关闭控制器管理器和 kubelet 加载 vsphereVolume 插件,您需要将 InTreePluginvSphereUnregister 功能标志设置为 true。您必须在所有工作节点上安装 csi.vsphere.vmware.com CSI 驱动程序。

使用 subPath

有时,在单个 Pod 中将一个卷用于多个用途会很有用。volumeMounts[*].subPath 属性指定了引用卷内的子路径,而不是其根路径。

以下示例显示了如何使用单个共享卷配置具有 LAMP 堆栈(Linux Apache MySQL PHP)的 Pod。此示例 subPath 配置不建议用于生产环境。

PHP 应用程序的代码和资产映射到卷的 html 文件夹,MySQL 数据库存储在卷的 mysql 文件夹中。例如

apiVersion: v1
kind: Pod
metadata:
  name: my-lamp-site
spec:
    containers:
    - name: mysql
      image: mysql
      env:
      - name: MYSQL_ROOT_PASSWORD
        value: "rootpasswd"
      volumeMounts:
      - mountPath: /var/lib/mysql
        name: site-data
        subPath: mysql
    - 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 状态: Kubernetes v1.17 [stable]

使用 subPathExpr 字段从向下 API 环境变量构建 subPath 目录名称。subPathsubPathExpr 属性是互斥的。

在此示例中,Pod 使用 subPathExprhostPath/var/log/pods 中创建目录 pod1hostPath 卷从 downwardAPI 获取 Pod 名称。主机目录 /var/log/pods/pod1 挂载在容器中的 /logs 下。

apiVersion: v1
kind: Pod
metadata:
  name: pod1
spec:
  containers:
  - name: container1
    env:
    - name: POD_NAME
      valueFrom:
        fieldRef:
          apiVersion: v1
          fieldPath: metadata.name
    image: busybox:1.28
    command: [ "sh", "-c", "while [ true ]; do echo 'Hello'; sleep 10; done | tee -a /logs/hello.txt" ]
    volumeMounts:
    - name: workdir1
      mountPath: /logs
      # The variable expansion uses round brackets (not curly brackets).
      subPathExpr: $(POD_NAME)
  restartPolicy: Never
  volumes:
  - name: workdir1
    hostPath:
      path: /var/log/pods

资源

emptyDir 卷的存储介质(例如磁盘或 SSD)由持有 kubelet 根目录(通常为 /var/lib/kubelet)的文件系统的介质决定。emptyDirhostPath 卷可以使用的空间没有限制,容器之间或 Pod 之间也没有隔离。

要了解如何使用资源规范请求空间,请参阅 如何管理资源

树外卷插件

树外卷插件包括 容器存储接口 (CSI),以及 FlexVolume(已弃用)。这些插件使存储供应商能够创建自定义存储插件,而无需将其插件源代码添加到 Kubernetes 存储库中。

以前,所有卷插件都是“树内”的。“树内”插件与核心 Kubernetes 二进制文件一起构建、链接、编译和发布。这意味着将新的存储系统添加到 Kubernetes(一个卷插件)需要将代码签入核心 Kubernetes 代码存储库中。

CSI 和 FlexVolume 都允许卷插件独立于 Kubernetes 代码库进行开发,并作为扩展部署(安装)在 Kubernetes 集群中。

对于希望创建出树卷插件的存储供应商,请参阅 卷插件常见问题解答

csi

容器存储接口 (CSI) 为容器编排系统(如 Kubernetes)定义了一个标准接口,以便将任意存储系统暴露给其容器工作负载。

请阅读 CSI 设计提案 了解更多信息。

在 Kubernetes 集群上部署了兼容 CSI 的卷驱动程序后,用户可以使用 csi 卷类型来挂载或装载 CSI 驱动程序公开的卷。

可以通过三种不同的方式在 Pod 中使用 csi

以下字段可供存储管理员配置 CSI 持久卷

  • driver:一个字符串值,指定要使用的卷驱动程序的名称。此值必须与 CSI 驱动程序在 CSI 规范 中定义的 GetPluginInfoResponse 中返回的值相对应。Kubernetes 使用它来识别要调用的 CSI 驱动程序,而 CSI 驱动程序组件使用它来识别属于 CSI 驱动程序的哪些 PV 对象。
  • volumeHandle:一个字符串值,用于唯一标识卷。此值必须与 CSI 驱动程序在 CSI 规范 中定义的 CreateVolumeResponsevolume.id 字段中返回的值相对应。在引用卷时,此值将作为 volume_id 传递给 CSI 卷驱动程序的所有调用。
  • readOnly:一个可选的布尔值,指示卷是否要以只读方式“ControllerPublished”(挂载)。默认为 false。此值通过 ControllerPublishVolumeRequest 中的 readonly 字段传递给 CSI 驱动程序。
  • fsType:如果 PV 的 VolumeModeFilesystem,则可以使用此字段指定用于装载卷的文件系统。如果卷未格式化且支持格式化,则此值将用于格式化卷。此值通过 ControllerPublishVolumeRequestNodeStageVolumeRequestNodePublishVolumeRequestVolumeCapability 字段传递给 CSI 驱动程序。
  • volumeAttributes:一个字符串到字符串的映射,指定卷的静态属性。此映射必须与 CSI 驱动程序在 CSI 规范 中定义的 CreateVolumeResponsevolume.attributes 字段中返回的映射相对应。此映射通过 ControllerPublishVolumeRequestNodeStageVolumeRequestNodePublishVolumeRequestvolume_context 字段传递给 CSI 驱动程序。
  • controllerPublishSecretRef:对包含敏感信息的秘密对象的引用,该信息将传递给 CSI 驱动程序以完成 CSI ControllerPublishVolumeControllerUnpublishVolume 调用。此字段是可选的,如果不需要秘密,则可以为空。如果 Secret 包含多个秘密,则传递所有秘密。
  • nodeExpandSecretRef:对包含敏感信息的秘密对象的引用,该信息将传递给 CSI 驱动程序以完成 CSI NodeExpandVolume 调用。此字段是可选的,如果不需要秘密,则可以为空。如果对象包含多个秘密,则传递所有秘密。当您为节点触发的卷扩展配置了秘密数据时,kubelet 会通过 NodeExpandVolume() 调用将该数据传递给 CSI 驱动程序。所有支持的 Kubernetes 版本都提供 nodeExpandSecretRef 字段,默认情况下可用。Kubernetes v1.25 之前的版本不支持此功能。
  • 为每个 kube-apiserver 和每个节点上的 kubelet 启用名为 CSINodeExpandSecret特性门控。从 Kubernetes 1.27 版本开始,此功能已默认启用,不需要显式启用特性门控。您还必须使用支持或需要在节点触发的存储调整大小操作期间使用秘密数据的 CSI 驱动程序。
  • nodePublishSecretRef:对包含敏感信息的秘密对象的引用,该信息将传递给 CSI 驱动程序以完成 CSI NodePublishVolume 调用。此字段是可选的,如果不需要秘密,则可以为空。如果秘密对象包含多个秘密,则传递所有秘密。
  • nodeStageSecretRef:对包含敏感信息的秘密对象的引用,该信息将传递给 CSI 驱动程序以完成 CSI NodeStageVolume 调用。此字段是可选的,如果不需要秘密,则可以为空。如果 Secret 包含多个秘密,则传递所有秘密。

CSI 原生块卷支持

功能状态: Kubernetes v1.18 [稳定]

拥有外部 CSI 驱动程序的供应商可以在 Kubernetes 工作负载中实现原生块卷支持。

您可以像往常一样设置您的 持久卷/持久卷声明,具有原生块卷支持,无需进行任何 CSI 特定更改。

CSI 短暂卷

功能状态: Kubernetes v1.25 [稳定]

您可以直接在 Pod 规范中配置 CSI 卷。以这种方式指定的卷是短暂的,不会跨 Pod 重启持久化。有关更多信息,请参阅 短暂卷

有关如何开发 CSI 驱动程序的更多信息,请参阅 kubernetes-csi 文档

Windows CSI 代理

功能状态: Kubernetes v1.22 [稳定]

CSI 节点插件需要执行各种特权操作,例如扫描磁盘设备和挂载文件系统。这些操作在每个主机操作系统上有所不同。对于 Linux 工作节点,容器化的 CSI 节点插件通常作为特权容器部署。对于 Windows 工作节点,容器化 CSI 节点插件的特权操作是通过 csi-proxy 支持的,它是一个社区管理的独立二进制文件,需要预先安装在每个 Windows 节点上。

有关更多详细信息,请参阅您要部署的 CSI 插件的部署指南。

从树内插件迁移到 CSI 驱动程序

功能状态: Kubernetes v1.25 [稳定]

CSIMigration 功能将针对现有树内插件的操作重定向到相应的 CSI 插件(预计已安装和配置)。因此,在过渡到取代树内插件的 CSI 驱动程序时,操作人员无需对现有存储类、持久卷或持久卷声明(引用树内插件)进行任何配置更改。

支持的操作和功能包括:卷的配置/删除、挂载/卸载、装载/卸载和调整大小。

支持 CSIMigration 并已实现相应 CSI 驱动程序的树内插件在 卷类型 中列出。

以下树内插件支持 Windows 节点上的持久存储

flexVolume(已弃用)

功能状态: Kubernetes v1.23 [已弃用]

FlexVolume 是一个出树插件接口,它使用基于执行的模型与存储驱动程序进行交互。FlexVolume 驱动程序二进制文件必须安装在每个节点上预定义的卷插件路径中,在某些情况下还需要安装在控制平面节点上。

Pod 通过树内卷插件 flexVolume 与 FlexVolume 驱动程序进行交互。有关更多详细信息,请参阅 FlexVolume 自述文件

以下 FlexVolume 插件(作为 PowerShell 脚本部署在主机上)支持 Windows 节点

装载传播

装载传播允许将容器装载的卷共享给同一 Pod 中的其他容器,甚至共享给同一节点上的其他 Pod。

卷的装载传播由 containers[*].volumeMounts 中的 mountPropagation 字段控制。其值如下:

  • None - 此卷装载将不会接收随后装载到此卷或其任何子目录中的任何装载,这些装载由主机完成。同样,容器创建的任何装载都不会在主机上可见。这是默认模式。

    此模式等效于 mount(8) 中描述的 rprivate 装载传播。

    但是,当 rprivate 传播不适用时,CRI 运行时可能会选择 rslave 装载传播(即 HostToContainer)。已知 cri-dockerd(Docker)在装载源包含 Docker 守护程序的根目录(/var/lib/docker)时会选择 rslave 装载传播。

  • HostToContainer - 此卷装载将接收随后装载到此卷或其任何子目录中的所有装载。

    换句话说,如果主机在卷装载内装载任何内容,容器将看到它装载在那里。

    同样,如果任何 Pod 对同一卷具有 Bidirectional 装载传播并在那里装载任何内容,则具有 HostToContainer 装载传播的容器将看到它。

    此模式等效于 mount(8) 中描述的 rslave 装载传播。

  • Bidirectional - 此卷装载的行为与 HostToContainer 装载相同。此外,容器创建的所有卷装载将传播回主机,并传播到所有使用同一卷的 Pod 的所有容器。

    此模式的典型用例是具有 FlexVolume 或 CSI 驱动程序的 Pod,或者需要使用 hostPath 卷在主机上装载某些内容的 Pod。

    此模式等效于 mount(8) 中描述的 rshared 装载传播。

只读挂载

通过将.spec.containers[].volumeMounts[].readOnly字段设置为true,可以使挂载变为只读。这不会使卷本身变为只读,但特定容器将无法写入它。Pod 中的其他容器可以将同一个卷挂载为读写。

在 Linux 上,默认情况下,只读挂载不会递归地设置为只读。例如,考虑一个 Pod,它将主机的/mnt挂载为hostPath卷。如果在/mnt/<SUBMOUNT>上挂载了另一个读写文件系统(如 tmpfs、NFS 或 USB 存储),则挂载到容器中的卷也将具有可写/mnt/<SUBMOUNT>,即使挂载本身被指定为只读。

递归只读挂载

功能状态: Kubernetes v1.30 [alpha]

可以通过为 kubelet 和 kube-apiserver 设置RecursiveReadOnlyMounts 功能开关,并为 Pod 设置.spec.containers[].volumeMounts[].recursiveReadOnly字段来启用递归只读挂载。

允许的值为

  • Disabled(默认):无效果。

  • Enabled:使挂载递归地变为只读。需要满足以下所有要求

    • readOnly设置为true
    • mountPropagation未设置,或者设置为None
    • 主机运行的是 Linux 内核 v5.12 或更高版本
    • CRI级容器运行时支持递归只读挂载
    • OCI级容器运行时支持递归只读挂载。如果其中任何一项不满足,则会失败。
  • IfPossible:尝试应用Enabled,如果内核或运行时类不支持此功能,则回退到Disabled

示例

apiVersion: v1
kind: Pod
metadata:
  name: rro
spec:
  volumes:
    - name: mnt
      hostPath:
        # tmpfs is mounted on /mnt/tmpfs
        path: /mnt
  containers:
    - name: busybox
      image: busybox
      args: ["sleep", "infinity"]
      volumeMounts:
        # /mnt-rro/tmpfs is not writable
        - name: mnt
          mountPath: /mnt-rro
          readOnly: true
          mountPropagation: None
          recursiveReadOnly: Enabled
        # /mnt-ro/tmpfs is writable
        - name: mnt
          mountPath: /mnt-ro
          readOnly: true
        # /mnt-rw/tmpfs is writable
        - name: mnt
          mountPath: /mnt-rw

当 kubelet 和 kube-apiserver 识别此属性时,.status.containerStatuses[].volumeMounts[].recursiveReadOnly字段将设置为EnabledDisabled

实现

以下容器运行时已知支持递归只读挂载。

CRI 级

OCI 级

  • runc,自 v1.1 起
  • crun,自 v1.8.6 起

下一步

遵循使用持久卷部署 WordPress 和 MySQL的示例。

此页面上的项目指的是提供 Kubernetes 所需功能的第三方产品或项目。Kubernetes 项目作者不对这些第三方产品或项目负责。有关更多详细信息,请参见CNCF 网站指南

在提出添加额外第三方链接的更改之前,您应该阅读内容指南

上次修改时间:2024 年 6 月 24 日 下午 10:58 PST:添加 ImageVolume 文档 (a12454f2dc)