Volume
我们知道默认情况下容器的数据都是非持久化的,在容器消亡以后数据也跟着丢失,所以 Docker 提供了 Volume 机制以便将数据持久化存储。类似的,Kubernetes 提供了更强大的 Volume 机制和丰富的插件,解决了容器数据持久化和容器间共享数据的问题。
与 Docker 不同,Kubernetes Volume 的生命周期与 Pod 绑定
容器挂掉后 Kubelet 再次重启容器时,Volume 的数据依然还在
而 Pod 删除时,Volume 才会清理。数据是否丢失取决于具体的 Volume 类型,比如 emptyDir 的数据会丢失,而 PV 的数据则不会丢
Volume 类型
目前,Kubernetes 支持以下 Volume 类型:
emptyDir
hostPath
gcePersistentDisk
awsElasticBlockStore
nfs
iscsi
flocker
glusterfs
rbd
cephfs
gitRepo
secret
persistentVolumeClaim
downwardAPI
azureFileVolume
azureDisk
vsphereVolume
Quobyte
PortworxVolume
ScaleIO
FlexVolume
StorageOS
local
image
注意,这些 volume 并非全部都是持久化的,比如 emptyDir、secret、gitRepo 等,这些 volume 会随着 Pod 的消亡而消失。
API 版本对照表
v1.5+
core/v1
emptyDir
如果 Pod 设置了 emptyDir 类型 Volume, Pod 被分配到 Node 上时候,会创建 emptyDir,只要 Pod 运行在 Node 上,emptyDir 都会存在(容器挂掉不会导致 emptyDir 丢失数据),但是如果 Pod 从 Node 上被删除(Pod 被删除,或者 Pod 发生迁移),emptyDir 也会被删除,并且永久丢失。
apiVersion: v1
kind: Pod
metadata:
name: test-pd
spec:
containers:
- image: gcr.io/google_containers/test-webserver
name: test-container
volumeMounts:
- mountPath: /cache
name: cache-volume
volumes:
- name: cache-volume
emptyDir: {}
hostPath
hostPath 允许挂载 Node 上的文件系统到 Pod 里面去。如果 Pod 需要使用 Node 上的文件,可以使用 hostPath。
apiVersion: v1
kind: Pod
metadata:
name: test-pd
spec:
containers:
- image: gcr.io/google_containers/test-webserver
name: test-container
volumeMounts:
- mountPath: /test-pd
name: test-volume
volumes:
- name: test-volume
hostPath:
path: /data
NFS
NFS 是 Network File System 的缩写,即网络文件系统。Kubernetes 中通过简单地配置就可以挂载 NFS 到 Pod 中,而 NFS 中的数据是可以永久保存的,同时 NFS 支持同时写操作。
volumes:
- name: nfs
nfs:
# FIXME: use the right hostname
server: 10.254.234.223
path: "/"
gcePersistentDisk
gcePersistentDisk 可以挂载 GCE 上的永久磁盘到容器,需要 Kubernetes 运行在 GCE 的 VM 中。
volumes:
- name: test-volume
# This GCE PD must already exist.
gcePersistentDisk:
pdName: my-data-disk
fsType: ext4
awsElasticBlockStore
awsElasticBlockStore 可以挂载 AWS 上的 EBS 盘到容器,需要 Kubernetes 运行在 AWS 的 EC2 上。
volumes:
- name: test-volume
# This AWS EBS volume must already exist.
awsElasticBlockStore:
volumeID: <volume-id>
fsType: ext4
gitRepo
gitRepo volume 将 git 代码下拉到指定的容器路径中
volumes:
- name: git-volume
gitRepo:
repository: "git@somewhere:me/my-git-repository.git"
revision: "22f1d8406d464b0c0874075539c1f2e96c253775"
image
image volume 是 Kubernetes v1.33 中升级为 Beta 的新功能,允许将容器镜像作为 volume 挂载到 Pod 中。这个功能对于需要共享容器镜像内容或访问镜像中的静态文件非常有用。
主要特性
从 Alpha 升级为 Beta(需要开启
ImageVolume
特性开关)支持
subPath
和subPathExpr
挂载方式卷被挂载为只读,且具有
noexec
限制新增了 kubelet 指标来跟踪镜像卷的请求和挂载操作
使用示例
apiVersion: v1
kind: Pod
metadata:
name: image-volume-example
spec:
containers:
- name: shell
image: debian
volumeMounts:
- name: volume
mountPath: /volume
subPath: dir
volumes:
- name: volume
image:
reference: quay.io/crio/artifact:v2
pullPolicy: IfNotPresent
容器运行时支持
CRI-O 从 v1.31 开始支持此功能
containerd 正在开发完整的 Beta 支持
注意事项
需要开启
ImageVolume
特性开关检查容器运行时是否支持此功能
可以使用新的 kubelet 指标监控镜像卷性能
使用 subPath
Pod 的多个容器使用同一个 Volume 时,subPath 非常有用
apiVersion: v1
kind: Pod
metadata:
name: my-lamp-site
spec:
containers:
- name: mysql
image: mysql
volumeMounts:
- mountPath: /var/lib/mysql
name: site-data
subPath: mysql
- name: php
image: php
volumeMounts:
- mountPath: /var/www/html
name: site-data
subPath: html
volumes:
- name: site-data
persistentVolumeClaim:
claimName: my-lamp-site-data
FlexVolume
如果内置的这些 Volume 不满足要求,则可以使用 FlexVolume 实现自己的 Volume 插件。注意要把 volume plugin 放到 /usr/libexec/kubernetes/kubelet-plugins/volume/exec/<vendor~driver>/<driver>
,plugin 要实现 init/attach/detach/mount/umount
等命令(可参考 lvm 的 示例)。
- name: test
flexVolume:
driver: "kubernetes.io/lvm"
fsType: "ext4"
options:
volumeID: "vol1"
size: "1000m"
volumegroup: "kube_vg"
Projected Volume
Projected volume 将多个 Volume 源映射到同一个目录中,支持 secret、downwardAPI 和 configMap。
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
本地存储限额
v1.7 + 支持对基于本地存储(如 hostPath, emptyDir, gitRepo 等)的容量进行调度限额,可以通过 --feature-gates=LocalStorageCapacityIsolation=true
来开启这个特性。
为了支持这个特性,Kubernetes 将本地存储分为两类
storage.kubernetes.io/overlay
,即/var/lib/docker
的大小storage.kubernetes.io/scratch
,即/var/lib/kubelet
的大小
Kubernetes 根据 storage.kubernetes.io/scratch
的大小来调度本地存储空间,而根据 storage.kubernetes.io/overlay
来调度容器的存储。比如
为容器请求 64MB 的可写层存储空间
apiVersion: v1
kind: Pod
metadata:
name: ls1
spec:
restartPolicy: Never
containers:
- name: hello
image: busybox
command: ["df"]
resources:
requests:
storage.kubernetes.io/overlay: 64Mi
为 empty 请求 64MB 的存储空间
apiVersion: v1
kind: Pod
metadata:
name: ls1
spec:
restartPolicy: Never
containers:
- name: hello
image: busybox
command: ["df"]
volumeMounts:
- name: data
mountPath: /data
volumes:
- name: data
emptyDir:
sizeLimit: 64Mi
Mount 传递
在 Kubernetes 中,Volume Mount 默认是 私有的,但从 v1.8 开始,Kubernetes 支持配置 Mount 传递(mountPropagation)。它支持两种选项
HostToContainer:这是开启
MountPropagation=true
时的默认模式,等效于rslave
模式,即容器可以看到 Host 上面在该 volume 内的任何新 Mount 操作Bidirectional:等效于
rshared
模式,即 Host 和容器都可以看到对方在该 Volume 内的任何新 Mount 操作。该模式要求容器必须运行在特权模式(即securityContext.privileged=true
)
注意:
使用 Mount 传递需要开启
--feature-gates=MountPropagation=true
rslave
和rshared
的说明可以参考 内核文档
Volume 快照
v1.8 新增了 pre-alpha 版本的 Volume 快照,但还只是一个雏形,并且其实现不在 Kubernetes 核心代码中,而是存放在 kubernetes-incubator/external-storage 中。
TODO: 补充 Volume 快照的设计原理和示例。
Windows Volume
Windows 容器暂时只支持 local、emptyDir、hostPath、AzureDisk、AzureFile 以及 flexvolume。注意 Volume 的路径格式需要为 mountPath: "C:\\etc\\foo"
或者 mountPath: "C:/etc/foo"
。
apiVersion: v1
kind: Pod
metadata:
name: hostpath-pod
spec:
containers:
- name: hostpath-nano
image: microsoft/nanoserver:1709
stdin: true
tty: true
volumeMounts:
- name: blah
mountPath: "C:\\etc\\foo"
readOnly: true
nodeSelector:
beta.kubernetes.io/os: windows
volumes:
- name: blah
hostPath:
path: "C:\\AzureData"
apiVersion: v1
kind: Pod
metadata:
name: empty-dir-pod
spec:
containers:
- image: microsoft/nanoserver:1709
name: empty-dir-nano
stdin: true
tty: true
volumeMounts:
- mountPath: /cache
name: cache-volume
- mountPath: C:/scratch
name: scratch-volume
volumes:
- name: cache-volume
emptyDir: {}
- name: scratch-volume
emptyDir: {}
nodeSelector:
beta.kubernetes.io/os: windows
卷数据填充器(Volume Populators,v1.33 GA)
卷数据填充器是 Kubernetes v1.33 正式稳定(GA)的特性,允许在创建 PersistentVolumeClaim 时使用自定义资源作为数据源来预填充卷的内容。
基本概念
卷数据填充器支持在 PVC 创建时指定自定义资源作为数据源,这些自定义资源可以包含初始化数据的相关信息,如备份位置、模板数据或其他数据源配置。
使用方式
通过在 PVC 中使用 dataSourceRef
字段指定自定义数据源:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: app-data-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: example-storage
dataSourceRef:
apiGroup: backup.example.com
kind: BackupSource
name: app-backup-20250109
主要特性
自定义数据源 - 支持任意类型的自定义资源作为数据源
灵活的初始化 - 可从备份、模板、或外部系统初始化数据
AnyVolumeDataSource 默认启用 - v1.33 中该特性门控默认开启
可选填充 Pod - 支持基于插件的填充方式,可选择性跳过创建填充 Pod
应用场景
数据库初始化 - 从备份恢复数据库到新的存储卷
应用模板 - 使用预配置的应用数据模板
开发环境 - 快速创建包含测试数据的开发环境
灾难恢复 - 从备份系统恢复数据到新集群
实现示例
# 自定义数据源定义
apiVersion: template.example.com/v1
kind: DataTemplate
metadata:
name: wordpress-template
spec:
templateURL: "https://example.com/templates/wordpress-starter.tar.gz"
includeDatabase: true
sampleContent: true
---
# 使用数据源的 PVC
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: wordpress-data
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 20Gi
storageClassName: fast-ssd
dataSourceRef:
apiGroup: template.example.com
kind: DataTemplate
name: wordpress-template
注意事项
需要相应的卷填充器控制器来处理特定的自定义资源类型
数据填充过程可能需要时间,Pod 会等待填充完成后才能启动
确保自定义资源与 PVC 在相同的命名空间中
挂载传播
挂载传播(MountPropagation)是 v1.9 引入的新功能,并在 v1.10 中升级为 Beta 版本。挂载传播用来解决同一个 Volume 在不同的容器甚至是 Pod 之间挂载的问题。通过设置 `Container.volumeMounts.mountPropagation),可以为该存储卷设置不同的传播类型。
支持三种选项:
None:即私有挂载(private)
HostToContainer:即 Host 内在该目录中的新挂载都可以在容器中看到,等价于 Linux 内核的 rslave。
Bidirectional:即 Host 内在该目录中的新挂载都可以在容器中看到,同样容器内在该目录中的任何新挂载也都可以在 Host 中看到,等价于 Linux 内核的 rshared。仅特权容器(privileged)可以使用 Bidirectional 类型。
注意:
使用前需要开启 MountPropagation 特性
如未设置,则 v1.9 和 v1.10 中默认为私有挂载(
None
),而 v1.11 中默认为HostToContainer
Docker 服务的 systemd 配置文件中需要设置
MountFlags=shared
其他的 Volume 参考示例
https://github.com/kubernetes/examples/tree/master/staging/volumes/iscsi
最后更新于