Kubernetes 提供了更强大的 Volume 机制和丰富的插件,解决了容器数据持久化和容器间共享数据的问题。
spec.volumes
提供了数据的声明,spec.containers[*].volumeMounts
则将这个声明挂载为一个文件或目录。volumes 和 volumeMount 通过 name 字段进行关联
Kubernetes Volume 的生命周期与 Pod 绑定:
- 容器挂掉后 Kubelet 再次重启容器时,Volume 的数据依然还在
- 当 Pod 删除时,Volume 才会清理。数据是否丢失取决于具体的 Volume 类型,比如 emptyDir 的数据会丢失,而 PV 的数据则不会丢
API 版本对照表
Kubernetes 版本 | Core API 版本 |
---|---|
v1.5+ | core/v1 |
Volumes 支持的数据类型
emptyDir
使用 emptyDir 时,当 Pod 分配到 Node 上时,将会创建 emptyDir,并且只要 Node 上的 Pod 一直运行,Volume 就会一直存。当 Pod(不管任何原因)从 Node 上被删除时,emptyDir 也同时会删除,存储的数据也将永久删除。
注意:
emptyDir 的生命周期 是 Pod 删除时会同时删除对应的 emptyDir 数据,但删除容器不影响 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: {}
emptyDir Volume 的存储介质(Disk,SSD 等)取决于 kubelet 根目录(如 /var/lib/kubelet)所处文件系统的存储介质。默认不限制 emptyDir 使用的空间大小,不对容器或 Pod 的资源隔离。
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
hostPath Volume 的存储介质(Disk,SSD 等)取决于 kubelet 根目录(如 /var/lib/kubelet)所处文件系统的存储介质。默认不限制hostPath Volume 使用的空间大小,不对容器或 Pod 的资源隔离。
secret
secret volume 用于将敏感信息(如密码)传递给 pod。可以将 secrets 存储在 Kubernetes API 中,使用的时候以文件的形式挂载到 pod 中,而不用连接 api。 secret volume 由 tmpfs(RAM 支持的文件系统)支持。
详细了解secret
persistentVolumeClaim
persistentVolumeClaim 用来挂载持久化磁盘的。PersistentVolumes 是用户在不知道特定云环境的细节的情况下,实现持久化存储(如 GCE PersistentDisk 或 iSCSI 卷)的一种方式。
更多详细信息,请参阅 PersistentVolumes 示例。
configMap
downwardAPI
通过环境变量的方式告诉容器Pod的信息
更多详细信息,请参见downwardAPI卷示例。
projected
Projected volume将多个Volume源映射到同一个目录
目前,可以支持以下类型的卷源: secret downwardAPI configMap 所有卷源都要求与pod在同一命名空间中。更详细信息,请参阅all-in-one volume design document。
示例
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
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
LocalPV
目前处于 Kubernetes 1.7中的 alpha 级别。
Local 是Kubernetes集群中每个节点的本地存储(如磁盘,分区或目录),在Kubernetes1.7中kubelet可以支持对kube-reserved和system-reserved指定本地存储资源。
通过上面的这个新特性可以看出来,Local Storage同HostPath的区别在于对Pod的调度上,使用Local Storage可以由Kubernetes自动的对Pod进行调度,而是用HostPath只能人工手动调度Pod,因为Kubernetes已经知道了每个节点上kube-reserved和system-reserved设置的本地存储限制。
示例:
apiVersion: v1
kind: PersistentVolume
metadata:
name: example-pv
annotations:
"volume.alpha.kubernetes.io/node-affinity": '{
"requiredDuringSchedulingIgnoredDuringExecution": {
"nodeSelectorTerms": [
{ "matchExpressions": [
{ "key": "kubernetes.io/hostname",
"operator": "In",
"values": ["example-node"]
}
]}
]}
}'
spec:
capacity:
storage: 100Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Delete
storageClassName: local-storage
local:
path: /mnt/disks/ssd1
请注意,本地PersistentVolume需要手动清理和删除。
有关local卷类型的详细信息,请参阅 Local Persistent Storage user guide
FlexVolume
如果内置的这些 Volume 不满足要求,则可以使用 FlexVolume 实现自己的 Volume 插件。注意要把 volume plugin 放到 /usr/libexec/kubernetes/kubelet-plugins/volume/exec/<vendor~driver>/
- name: test
flexVolume:
driver: "kubernetes.io/lvm"
fsType: "ext4"
options:
volumeID: "vol1"
size: "1000m"
volumegroup: "kube_vg"
NFS
NFS 是Network File System的缩写,即网络文件系统。Kubernetes中通过简单地配置就可以挂载NFS到Pod中,而NFS中的数据是可以永久保存的,同时NFS支持同时写操作。Pod被删除时,Volume被卸载,内容被保留。这就意味着NFS能够允许我们提前对数据进行处理,而且这些数据可以在Pod之间相互传递。
详细信息,请参阅NFS示例。
volumes:
- name: nfs
nfs:
# FIXME: use the right hostname
server: 10.254.234.223
path: "/"
iSCSI
iscsi允许将现有的iscsi磁盘挂载到我们的pod中,和emptyDir不同的是,删除Pod时会被删除,但Volume只是被卸载,内容被保留,这就意味着iscsi能够允许我们提前对数据进行处理,而且这些数据可以在Pod之间“切换”。
详细信息,请参阅iSCSI示例。
flocker
Flocker是一个开源的容器集群数据卷管理器。它提供各种存储后端支持的数据卷的管理和编排。
详细信息,请参阅Flocker示例。
glusterfs
glusterfs,允许将Glusterfs(一个开源网络文件系统)Volume安装到pod中。不同于emptyDir,Pod被删除时,Volume只是被卸载,内容被保留。味着glusterfs能够允许我们提前对数据进行处理,而且这些数据可以在Pod之间“切换”。
详细信息,请参阅GlusterFS示例。
RBD
RBD允许Rados Block Device格式的磁盘挂载到Pod中,同样的,当pod被删除的时候,rbd也仅仅是被卸载,内容保留,rbd能够允许我们提前对数据进行处理,而且这些数据可以在Pod之间“切换”。
详细信息,请参阅RBD示例。
cephfs
cephfs Volume可以将已经存在的CephFS Volume挂载到pod中,与emptyDir特点不同,pod被删除的时,cephfs仅被被卸载,内容保留。cephfs能够允许我们提前对数据进行处理,而且这些数据可以在Pod之间“切换”。
提示:可以使用自己的Ceph服务器运行导出,然后在使用cephfs。
详细信息,请参阅CephFS示例。
gitRepo
gitRepo volume将git代码下拉到指定的容器路径中。
示例:
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"
PortworxVolume
Portworx能把你的服务器容量进行蓄积(pool),将你的服务器或者云实例变成一个聚合的高可用的计算和存储节点。
PortworxVolume可以通过Kubernetes动态创建,也可以在Kubernetes pod中预先配置和引用。示例:
apiVersion: v1
kind: Pod
metadata:
name: test-portworx-volume-pod
spec:
containers:
- image: gcr.io/google_containers/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>"
更多细节和例子可以在这里找到
ScaleIO
ScaleIO是一种基于软件的存储平台(虚拟SAN),可以使用现有硬件来创建可扩展共享块网络存储的集群。ScaleIO卷插件允许部署的pod访问现有的ScaleIO卷(或者可以为持久卷声明动态配置新卷,请参阅 Scaleio Persistent Volumes)。
示例:
apiVersion: v1
kind: Pod
metadata:
name: pod-0
spec:
containers:
- image: gcr.io/google_containers/test-webserver
name: pod-0
volumeMounts:
- mountPath: /test-pd
name: vol-0
volumes:
- name: vol-0
scaleIO:
gateway: https://localhost:443/api
system: scaleio
volumeName: vol-0
secretRef:
name: sio-secret
fsType: xfs
详细信息,请参阅ScaleIO示例。
gcePersistentDisk
gcePersistentDisk可以挂载GCE上的永久磁盘到容器,需要Kubernetes运行在GCE的VM中。与emptyDir不同,Pod删除时,gcePersistentDisk被删除,但Persistent Disk 的内容任然存在。这就意味着gcePersistentDisk能够允许我们提前对数据进行处理,而且这些数据可以在Pod之间“切换”。
提示:使用gcePersistentDisk,必须用gcloud或使用GCE API或UI 创建PD
创建PD
使用GCE PD与pod之前,需要创建它
gcloud compute disks create --size=500GB --zone=us-central1-a my-data-disk
示例
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
# This GCE PD must already exist.
gcePersistentDisk:
pdName: my-data-disk
fsType: ext4
awsElasticBlockStore
awsElasticBlockStore可以挂载AWS上的EBS盘到容器,需要Kubernetes运行在AWS的EC2上。与emptyDir Pod被删除情况不同,Volume仅被卸载,内容将被保留。这就意味着awsElasticBlockStore能够允许我们提前对数据进行处理,而且这些数据可以在Pod之间“切换”。
提示:必须使用aws ec2 create-volumeAWS API 创建EBS Volume,然后才能使用。
创建EBS Volume
在使用EBS Volume与pod之前,需要创建它。
aws ec2 create-volume --availability-zone eu-west-1a --size 10 --volume-type gp2
AWS EBS配置示例
apiVersion: v1
kind: Pod
metadata:
name: test-ebs
spec:
containers:
- image: gcr.io/google_containers/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: <volume-id>
fsType: ext4
AzureFileVolume
AzureFileVolume用于将Microsoft Azure文件卷(SMB 2.1和3.0)挂载到Pod中。
更多细节在这里
AzureDiskVolume
Azure是微软提供的公有云服务,如果使用Azure上面的虚拟机来作为Kubernetes集群使用时,那么可以通过AzureDisk这种类型的卷插件来挂载Azure提供的数据磁盘。
更多细节在这里
vsphereVolume
需要条件:配置了vSphere Cloud Provider的Kubernetes。有关cloudprovider配置,请参阅vSphere入门指南。
vsphereVolume用于将vSphere VMDK Volume挂载到Pod中。卸载卷后,内容将被保留。它同时支持VMFS和VSAN数据存储。
重要提示:使用POD之前,必须使用以下方法创建VMDK。
创建一个VMDK卷 使用vmkfstools创建。先将ssh接入ESX,然后使用以下命令创建vmdk vmkfstools -c 2G /vmfs/volumes/DatastoreName/volumes/myDisk.vmdk 使用vmware-vdiskmanager创建 shell vmware-vdiskmanager -c -t 0 -s 40GB -a lsilogic myDisk.vmdk 示例
apiVersion: v1
kind: Pod
metadata:
name: test-vmdk
spec:
containers:
- image: gcr.io/google_containers/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
更多例子在这里。
Quobyte
在kubernetes中使用Quobyte存储,需要提前部署Quobyte软件,要求必须是1.3以及更高版本,并且在kubernetes管理的节点上面部署Quobyte客户端。
详细信息,请参阅这里。
StorageOS
StorageOS是一家英国的初创公司,给无状态容器提供简单的自动块存储、状态来运行数据库和其他需要企业级存储功能,但避免随之而来的复杂性、刚性以及成本。
核心:是StorageOS向容器提供块存储,可通过文件系统访问。
StorageOS容器需要64位Linux,没有额外的依赖关系,提供免费开发许可证。
安装说明,请参阅StorageOS文档
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示例。
扩展阅读
本地存储限额
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
挂载传播
挂载传播(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
- iSCSI Volume 示例
- cephfs Volume 示例
- Flocker Volume 示例
- GlusterFS Volume 示例
- RBD Volume 示例
- Secret Volume 示例
- downwardAPI Volume 示例
- AzureFile Volume 示例
- AzureDisk Volume 示例
- Quobyte Volume 示例
- Portworx Volume 示例
- ScaleIO Volume 示例
- StorageOS Volume 示例
参考
- http://docs.kubernetes.org.cn/429.html
- https://feisky.gitbooks.io/kubernetes/content/concepts/volume.html
- https://feisky.gitbooks.io/kubernetes/content/concepts/volume.html#mount-%E4%BC%A0%E9%80%92
- https://github.com/feiskyer/kubernetes-handbook