卷
容器中的磁盘文件是临时的,这对于在容器中运行的非平凡应用程序来说会带来一些问题。当容器崩溃或停止时,会发生一个问题。容器状态不会被保存,因此在容器生命周期内创建或修改的所有文件都会丢失。在崩溃期间,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.32 中,所有针对内部 awsElasticBlockStore
类型的操作都将重定向到 ebs.csi.aws.com
CSI 驱动程序。
AWSElasticBlockStore 内部存储驱动程序在 Kubernetes v1.19 版本中已弃用,然后在 v1.27 版本中已完全删除。
Kubernetes 项目建议您改用 AWS EBS 第三方存储驱动程序。
azureDisk (已弃用)
在 Kubernetes 1.32 中,所有针对内部 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 [稳定]
当启用 azureFile
的 CSIMigration
功能时,会将所有插件操作从现有的内部插件重定向到 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.32 不包含 cephfs
卷类型。
cephfs
内部存储驱动程序在 Kubernetes v1.28 版本中已弃用,然后在 v1.31 版本中已完全删除。
cinder (已弃用)
在 Kubernetes 1.32 中,所有针对内部 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
推导出来的。
注意
你必须先创建 ConfigMap,然后才能使用它。
ConfigMap 始终以
readOnly
方式挂载。使用 ConfigMap 作为
subPath
卷挂载的容器将不会收到 ConfigMap 的更新。文本数据以 UTF-8 字符编码作为文件公开。对于其他字符编码,请使用
binaryData
。
downwardAPI
downwardAPI
卷使向下 API 数据可用于应用程序。在卷中,你可以找到以纯文本格式作为只读文件公开的数据。
注意
当字段值更改时,使用向下 API 作为subPath
卷挂载的容器不会收到更新。请参阅通过文件将 Pod 信息暴露给容器以了解更多信息。
emptyDir
对于定义了 emptyDir
卷的 Pod,该卷会在 Pod 被分配到节点时创建。顾名思义,emptyDir
卷最初是空的。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
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
medium: Memory
fc(光纤通道)
fc
卷类型允许将现有的光纤通道块存储卷挂载到 Pod 中。你可以使用卷配置中的参数 targetWWNs
指定单个或多个目标全球通用名称 (WWN)。如果指定了多个 WWN,则 targetWWNs 期望这些 WWN 来自多路径连接。
注意
你必须预先配置 FC SAN 分区,以将这些 LUN(卷)分配并屏蔽到目标 WWN,以便 Kubernetes 主机可以访问它们。有关更多详细信息,请参阅光纤通道示例。
gcePersistentDisk(已弃用)
在 Kubernetes 1.32 中,内置 gcePersistentDisk
类型的所有操作都被重定向到 pd.csi.storage.gke.io
CSI 驱动程序。
内置的 gcePersistentDisk
存储驱动程序在 Kubernetes v1.17 版本中被弃用,然后在 v1.28 版本中被完全移除。
Kubernetes 项目建议你使用 Google Compute Engine Persistent Disk CSI 第三方存储驱动程序。
gitRepo(已弃用)
警告
gitRepo
卷类型已弃用。
要配置具有挂载 Git 存储库的 Pod,你可以将 emptyDir
卷挂载到使用 Git 克隆存储库的初始化容器中,然后将 EmptyDir 挂载到 Pod 的容器中。
你可以使用策略(例如ValidatingAdmissionPolicy)来限制集群中 gitRepo
卷的使用。你可以使用以下通用表达式语言 (CEL) 表达式作为策略的一部分来拒绝使用 gitRepo
卷:!has(object.spec.volumes) || !object.spec.volumes.exists(v, has(v.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.32 不包含 glusterfs
卷类型。
GlusterFS 内置存储驱动程序在 Kubernetes v1.25 版本中被弃用,然后在 v1.26 版本中被完全移除。
hostPath
hostPath
卷将主机节点文件系统中的文件或目录挂载到你的 Pod 中。这并不是大多数 Pod 所需要的,但它为某些应用程序提供了一个强大的转义通道。
警告
使用 hostPath
卷类型会带来许多安全风险。如果可以避免使用 hostPath
卷,则应该避免。例如,定义一个 local
PersistentVolume,并改用它。
如果你使用准入时验证来限制对节点上特定目录的访问,那么只有当你还要求对该 hostPath
卷的任何挂载都是**只读**时,该限制才有效。如果你允许不受信任的 Pod 以读写方式挂载任何主机路径,则该 Pod 中的容器可能能够破坏读写主机挂载。
使用 hostPath
卷时要小心,无论它们是以只读还是读写方式挂载,因为
- 访问主机文件系统可能会暴露特权系统凭据(例如,kubelet 的凭据)或特权 API(例如容器运行时套接字),这些凭据或 API 可用于容器逃逸或攻击集群的其他部分。
- 具有相同配置(例如从 PodTemplate 创建)的 Pod 在不同的节点上可能会表现不同,因为节点上的文件不同。
hostPath
卷的使用不被视为临时存储使用。你需要自行监视磁盘使用情况,因为过多的hostPath
磁盘使用会导致节点上的磁盘压力。
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 节点)在给定路径上必须存在一个块设备 |
注意
FileOrCreate
模式不会创建文件的父目录。如果挂载文件的父目录不存在,则 Pod 无法启动。为了确保此模式有效,你可以尝试单独挂载目录和文件,如 hostPath
的 FileOrCreate
示例中所示。在底层主机上创建的一些文件或目录可能只能由 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,该 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]
(默认启用:false)image
卷源表示 kubelet 主机上可用的 OCI 对象(容器镜像或工件)。
使用 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.32.0
从 Kubernetes 一致性测试镜像加载文件。其行为与pod.spec.containers[*].image
相同。拉取密钥将通过查找节点凭据、服务帐户镜像拉取密钥和 Pod 规范镜像拉取密钥的方式进行组装,与容器镜像的方式相同。此字段是可选的,允许更高级别的配置管理来默认或覆盖工作负载控制器(如 Deployments 和 StatefulSets)中的容器镜像。有关容器镜像的更多信息 pullPolicy
- 用于拉取 OCI 对象的策略。可能的值为:
Always
、Never
或IfNotPresent
。如果指定了:latest
标签,则默认为Always
,否则默认为IfNotPresent
。
有关如何使用此卷源的更多详细信息,请参阅在 Pod 中使用镜像卷示例。
iscsi
iscsi
卷允许将现有的 iSCSI(IP 上的 SCSI)卷挂载到您的 Pod 中。与 Pod 删除时被擦除的 emptyDir
不同,iscsi
卷的内容会被保留,而卷只是被卸载。这意味着 iscsi 卷可以预先填充数据,并且数据可以在 Pod 之间共享。
注意
您必须先运行自己的 iSCSI 服务器并创建卷,然后才能使用它。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 反亲和性)一起进行评估。
可以单独运行外部静态供应器,以改进对本地卷生命周期的管理。请注意,此供应器尚不支持动态配置。有关如何运行外部本地供应器的示例,请参阅本地卷供应器用户指南。
注意
如果未使用外部静态供应器来管理卷生命周期,则本地 PersistentVolume 需要用户手动清理和删除。nfs
nfs
卷允许将现有的 NFS(网络文件系统)共享挂载到 Pod 中。与 Pod 删除时被擦除的 emptyDir
不同,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
注意
您必须先运行自己的 NFS 服务器并导出共享,然后才能使用它。
另请注意,您不能在 Pod 规范中指定 NFS 挂载选项。您可以设置服务器端挂载选项,或者使用 /etc/nfsmount.conf。您还可以通过允许您设置挂载选项的 PersistentVolumes 来挂载 NFS 卷。
有关使用 PersistentVolumes 挂载 NFS 卷的示例,请参阅 NFS 示例。
persistentVolumeClaim
persistentVolumeClaim
卷用于将 PersistentVolume 挂载到 Pod 中。PersistentVolumeClaims 是用户“声明”持久存储(例如 iSCSI 卷)的一种方式,而无需了解特定云环境的详细信息。
有关更多详细信息,请参阅有关PersistentVolumes的信息。
portworxVolume(已弃用)
Kubernetes v1.25 [已弃用]
portworxVolume
是一个弹性块存储层,它与 Kubernetes 超融合运行。Portworx 对服务器中的存储进行指纹识别,根据功能进行分层,并聚合多个服务器上的容量。Portworx 在虚拟机或裸机 Linux 节点上的访客中运行。
可以通过 Kubernetes 动态创建 portworxVolume
,也可以预先配置并在 Pod 中引用。以下是引用预先配置的 Portworx 卷的 Pod 示例
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>"
注意
请确保在 Pod 中使用之前,您有一个名为pxvol
的现有 PortworxVolume。有关更多详细信息,请参阅Portworx 卷示例。
Portworx CSI 迁移
Kubernetes v1.25 [beta]
默认情况下,Kubernetes 1.32 尝试将旧版 Portworx 卷迁移为使用 CSI。(Portworx 的 CSI 迁移自 Kubernetes v1.23 起可用,但自 v1.31 版本起才默认启用)。如果要禁用自动迁移,可以将 CSIMigrationPortworx
功能门设置为 false
;您需要对 kube-controller-manager 和 每个相关的 kubelet 进行此更改。
它将所有插件操作从现有的内置插件重定向到 pxd.portworx.com
容器存储接口 (CSI) 驱动程序。必须在群集上安装 Portworx CSI 驱动程序。
projected
投射卷将多个现有卷源映射到同一目录中。有关更多详细信息,请参阅投射卷。
rbd(已删除)
Kubernetes 1.32 不包含 rbd
卷类型。
Kubernetes v1.28 版本中已弃用 Rados 块设备 (RBD) 内置存储驱动程序及其 csi 迁移支持,然后在 v1.31 版本中完全删除。
secret
secret
卷用于将敏感信息(例如密码)传递给 Pod。您可以在 Kubernetes API 中存储密钥,并将其作为文件挂载供 Pod 使用,而无需直接耦合到 Kubernetes。secret
卷由 tmpfs(一个 RAM 支持的文件系统)支持,因此它们永远不会写入非易失性存储。
注意
您必须先在 Kubernetes API 中创建 Secret,然后才能使用它。
Secret 始终以
readOnly
方式挂载。使用 Secret 作为
subPath
卷挂载的容器将不会收到 Secret 更新。
有关更多详细信息,请参阅配置密钥。
vsphereVolume(已弃用)
注意
Kubernetes 项目建议使用 vSphere CSI 树外存储驱动程序。vsphereVolume
用于将 vSphere VMDK 卷挂载到您的 Pod 中。卸载卷时,卷的内容会被保留。它同时支持 VMFS 和 VSAN 数据存储。
有关更多信息,请参阅 vSphere 卷示例。
vSphere CSI 迁移
Kubernetes v1.26 [稳定]
在 Kubernetes 1.32 中,内置的 vsphereVolume
类型的所有操作都重定向到 csi.vsphere.vmware.com
CSI 驱动程序。
必须在群集上安装 vSphere CSI 驱动程序。您可以在 VMware 的文档页面 将内置 vSphere 卷迁移到 vSphere 容器存储插件中找到有关如何迁移内置 vsphereVolume
的更多建议。如果未安装 vSphere CSI 驱动程序,则无法对使用内置 vsphereVolume
类型创建的 PV 执行卷操作。
您必须运行 vSphere 7.0u2 或更高版本才能迁移到 vSphere CSI 驱动程序。
如果您运行的 Kubernetes 版本不是 v1.32,请查阅该 Kubernetes 版本的文档。
注意
vSphere CSI 驱动程序不支持内置 vsphereVolume
插件的以下 StorageClass 参数
diskformat
hostfailurestotolerate
forceprovisioning
cachereservation
diskstripes
objectspacereservation
iopslimit
使用这些参数创建的现有卷将迁移到 vSphere CSI 驱动程序,但由 vSphere CSI 驱动程序创建的新卷将不会遵守这些参数。
vSphere CSI 迁移完成
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
Kubernetes v1.17 [稳定版]
使用 subPathExpr
字段从向下 API 环境变量构建 subPath
目录名称。subPath
和 subPathExpr
属性是互斥的。
在此示例中,Pod
使用 subPathExpr
在 hostPath
卷 /var/log/pods
中创建一个名为 pod1
的目录。hostPath
卷从 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
)的文件系统的介质决定。emptyDir
或 hostPath
卷可以消耗的空间没有限制,并且在容器之间或 Pod 之间没有隔离。
要了解如何使用资源规范请求空间,请参阅如何管理资源。
树外卷插件
树外卷插件包括容器存储接口 (CSI),以及 FlexVolume (已弃用)。这些插件使存储供应商可以创建自定义存储插件,而无需将其插件源代码添加到 Kubernetes 存储库中。
以前,所有卷插件都是“树内”的。“树内”插件是使用核心 Kubernetes 二进制文件构建、链接、编译和交付的。这意味着将新的存储系统添加到 Kubernetes(卷插件)需要将代码检入核心 Kubernetes 代码存储库。
CSI 和 FlexVolume 都允许独立于 Kubernetes 代码库开发卷插件,并作为扩展部署(安装)在 Kubernetes 集群上。
对于希望创建树外卷插件的存储供应商,请参阅卷插件 FAQ。
csi
容器存储接口 (CSI) 为容器编排系统(如 Kubernetes)定义了一个标准接口,以便将其任意存储系统暴露给其容器工作负载。
有关更多信息,请阅读CSI 设计提案。
注意
Kubernetes v1.13 中已弃用对 CSI 规范版本 0.2 和 0.3 的支持,并且将在未来的版本中删除。注意
CSI 驱动程序可能并非在所有 Kubernetes 版本中都兼容。请检查特定 CSI 驱动程序的文档,了解每个 Kubernetes 版本的支持部署步骤和兼容性矩阵。一旦在 Kubernetes 集群上部署了 CSI 兼容的卷驱动程序,用户就可以使用 csi
卷类型来附加或挂载 CSI 驱动程序公开的卷。
csi
卷可以通过三种不同的方式在 Pod 中使用:
- 通过引用 PersistentVolumeClaim
- 使用通用临时卷
- 如果驱动程序支持,则使用 CSI 临时卷
存储管理员可以使用以下字段来配置 CSI 持久卷:
driver
:一个字符串值,指定要使用的卷驱动程序的名称。此值必须与 CSI 驱动程序在 CSI 规范中定义的GetPluginInfoResponse
中返回的值相对应。Kubernetes 使用它来识别要调用的 CSI 驱动程序,而 CSI 驱动程序组件使用它来识别哪些 PV 对象属于该 CSI 驱动程序。volumeHandle
:一个字符串值,唯一标识卷。此值必须与 CSI 驱动程序在 CSI 规范中定义的CreateVolumeResponse
的volume.id
字段中返回的值相对应。当引用卷时,该值作为volume_id
传递给 CSI 卷驱动程序的所有调用。readOnly
:一个可选的布尔值,指示该卷是否应以只读方式“ControllerPublished”(附加)。默认值为 false。此值通过ControllerPublishVolumeRequest
中的readonly
字段传递给 CSI 驱动程序。fsType
:如果 PV 的VolumeMode
是Filesystem
,则可以使用此字段指定用于挂载卷的文件系统。如果该卷尚未格式化并且支持格式化,则将使用此值来格式化该卷。此值通过ControllerPublishVolumeRequest
、NodeStageVolumeRequest
和NodePublishVolumeRequest
的VolumeCapability
字段传递给 CSI 驱动程序。volumeAttributes
:一个字符串到字符串的映射,指定卷的静态属性。此映射必须与 CSI 驱动程序在 CSI 规范中定义的CreateVolumeResponse
的volume.attributes
字段中返回的映射相对应。该映射通过ControllerPublishVolumeRequest
、NodeStageVolumeRequest
和NodePublishVolumeRequest
中的volume_context
字段传递给 CSI 驱动程序。controllerPublishSecretRef
:对包含传递给 CSI 驱动程序的敏感信息的密钥对象的引用,以完成 CSIControllerPublishVolume
和ControllerUnpublishVolume
调用。此字段是可选的,如果不需要密钥,则可以为空。如果密钥包含多个密钥,则会传递所有密钥。nodeExpandSecretRef
:对包含传递给 CSI 驱动程序的敏感信息的密钥的引用,以完成 CSINodeExpandVolume
调用。此字段是可选的,如果不需要密钥,则可以为空。如果该对象包含多个密钥,则会传递所有密钥。当你为节点发起的卷扩展配置了密钥数据时,kubelet 通过NodeExpandVolume()
调用将该数据传递给 CSI 驱动程序。所有受支持的 Kubernetes 版本都提供nodeExpandSecretRef
字段,并且默认情况下可用。Kubernetes v1.25 之前的版本不包含此支持。- 为每个 kube-apiserver 和每个节点上的 kubelet 启用名为
CSINodeExpandSecret
的特性门。自 Kubernetes 版本 1.27 起,此功能默认已启用,无需显式启用特性门。你还必须使用在节点发起的存储大小调整操作期间支持或需要密钥数据的 CSI 驱动程序。 nodePublishSecretRef
:对包含传递给 CSI 驱动程序的敏感信息的密钥对象的引用,以完成 CSINodePublishVolume
调用。此字段是可选的,如果不需要密钥,则可以为空。如果密钥对象包含多个密钥,则会传递所有密钥。nodeStageSecretRef
:对包含传递给 CSI 驱动程序的敏感信息的密钥对象的引用,以完成 CSINodeStageVolume
调用。此字段是可选的,如果不需要密钥,则可以为空。如果密钥包含多个密钥,则会传递所有密钥。
CSI 原始块卷支持
Kubernetes v1.18 [稳定版]
具有外部 CSI 驱动程序的供应商可以在 Kubernetes 工作负载中实现原始块卷支持。
你可以像往常一样设置你的带有原始块卷支持的 PersistentVolume/PersistentVolumeClaim,而无需进行任何 CSI 特定的更改。
CSI 临时卷
Kubernetes v1.25 [稳定版]
你可以在 Pod 规范中直接配置 CSI 卷。以这种方式指定的卷是临时的,并且不会在 Pod 重启后保留。有关更多信息,请参阅临时卷。
有关如何开发 CSI 驱动程序的更多信息,请参阅kubernetes-csi 文档
Windows CSI 代理
Kubernetes v1.22 [稳定版]
CSI 节点插件需要执行各种特权操作,例如扫描磁盘设备和挂载文件系统。这些操作对于每个主机操作系统都不同。对于 Linux 工作节点,容器化的 CSI 节点插件通常部署为特权容器。对于 Windows 工作节点,使用 csi-proxy(一个社区管理的独立二进制文件,需要在每个 Windows 节点上预先安装)支持容器化 CSI 节点插件的特权操作。
有关更多详细信息,请参阅你希望部署的 CSI 插件的部署指南。
从树内插件迁移到 CSI 驱动程序
Kubernetes v1.25 [稳定版]
CSIMigration
功能将针对现有树内插件的操作定向到相应的 CSI 插件(预期已安装和配置)。因此,在过渡到取代树内插件的 CSI 驱动程序时,操作员不必对现有的存储类、持久卷或持久卷声明(引用树内插件)进行任何配置更改。
注意
即使在完成该卷类型的 CSI 迁移之后,甚至在你升级到不包含对该类存储的编译支持的 Kubernetes 版本之后,由树内卷插件创建的现有 PV 仍然可以在将来使用,而无需进行任何配置更改。
作为迁移的一部分,您(或其他集群管理员)必须为该存储安装并配置相应的 CSI 驱动程序。Kubernetes 的核心不会为您安装该软件。
迁移后,您还可以定义新的 PVC 和 PV,它们引用旧的、内置的存储集成。只要您安装并配置了相应的 CSI 驱动程序,即使是全新的卷,PV 的创建也会继续工作。实际的存储管理现在通过 CSI 驱动程序进行。
支持的操作和功能包括:卷的配置/删除、连接/分离、挂载/卸载以及调整大小。
支持 CSIMigration
并且已实现相应 CSI 驱动程序的内部插件,请参见卷的类型。
以下内部插件支持 Windows 节点上的持久存储
flexVolume(已弃用)
Kubernetes v1.23 [已弃用]
FlexVolume 是一种外部插件接口,它使用基于 exec 的模型与存储驱动程序交互。FlexVolume 驱动程序二进制文件必须安装在每个节点上预定义的卷插件路径中,在某些情况下也必须安装在控制平面节点上。
Pod 通过 flexVolume
内部卷插件与 FlexVolume 驱动程序交互。有关更多详细信息,请参阅 FlexVolume README 文档。
以下 FlexVolume 插件(作为主机上的 PowerShell 脚本部署)支持 Windows 节点
注意
FlexVolume 已被弃用。建议使用外部 CSI 驱动程序来将外部存储与 Kubernetes 集成。
FlexVolume 驱动程序的维护者应实现 CSI 驱动程序,并帮助将 FlexVolume 驱动程序的用户迁移到 CSI。FlexVolume 的用户应将其工作负载迁移到使用等效的 CSI 驱动程序。
挂载传播
挂载传播允许将容器挂载的卷共享给同一 Pod 中的其他容器,甚至共享给同一节点上的其他 Pod。
卷的挂载传播由 containers[*].volumeMounts
中的 mountPropagation
字段控制。其值包括:
None
- 此卷挂载不会接收主机随后挂载到此卷或其任何子目录的任何挂载。类似地,容器创建的任何挂载在主机上都不可见。这是默认模式。此模式等同于
mount(8)
中描述的rprivate
挂载传播。但是,当
rprivate
传播不适用时,CRI 运行时可能会选择rslave
挂载传播(即,HostToContainer
)。已知 cri-dockerd (Docker) 在挂载源包含 Docker 守护程序的根目录(/var/lib/docker
)时会选择rslave
挂载传播。HostToContainer
- 此卷挂载将接收所有后续挂载到此卷或其任何子目录的挂载。换句话说,如果主机在卷挂载内部挂载任何内容,则容器将看到它挂载在那里。
同样,如果任何使用
Bidirectional
挂载传播到同一卷的 Pod 在那里挂载任何内容,则使用HostToContainer
挂载传播的容器将看到它。此模式等同于
mount(8)
中描述的rslave
挂载传播。Bidirectional
- 此卷挂载的行为与HostToContainer
挂载相同。此外,容器创建的所有卷挂载都将传播回主机以及所有使用同一卷的所有 Pod 的所有容器。此模式的典型用例是带有 FlexVolume 或 CSI 驱动程序的 Pod,或者需要使用
hostPath
卷在主机上挂载某些内容的 Pod。此模式等同于
mount(8)
中描述的rshared
挂载传播。警告
Bidirectional
挂载传播可能很危险。它可能会损坏主机操作系统,因此仅允许在特权容器中使用。强烈建议熟悉 Linux 内核行为。此外,Pod 中容器创建的任何卷挂载都必须在终止时由容器销毁(卸载)。
只读挂载
可以通过将 .spec.containers[].volumeMounts[].readOnly
字段设置为 true
来使挂载变为只读。这不会使卷本身变为只读,但该特定容器将无法写入该卷。Pod 中的其他容器可以将同一卷挂载为读写。
在 Linux 上,默认情况下,只读挂载不是递归只读的。例如,考虑一个 Pod,它将主机的 /mnt
挂载为 hostPath
卷。如果在 /mnt/<SUBMOUNT>
上(例如 tmpfs、NFS 或 USB 存储)挂载了另一个读写的文件系统,则挂载到容器中的卷也将具有可写的 /mnt/<SUBMOUNT>
,即使挂载本身被指定为只读。
递归只读挂载
Kubernetes v1.31 [beta]
(默认启用:true)可以通过为 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
字段将设置为 Enabled
或 Disabled
。
实现
已知以下容器运行时支持递归只读挂载。
CRI 级别
- containerd,自 v2.0 起
- CRI-O,自 v1.30 起
OCI 级别
下一步
请参阅使用持久卷部署 WordPress 和 MySQL的示例。
本页上的项目引用了提供 Kubernetes 所需功能的第三方产品或项目。Kubernetes 项目的作者不对这些第三方产品或项目负责。有关更多详细信息,请参阅 CNCF 网站指南。
在提出添加额外第三方链接的更改之前,您应该阅读内容指南。