# k8s Volume
默认情况下容器中的磁盘文件是非持久化的,对于运行在容器中的应用来说面临两个问题,第一:当容器挂掉 kubelet 将重启启动它时,文件将会丢失;第二:当 Pod 中同时运行多个容器,容器之间需要共享文件时。k8s 的 Volume 解决了这两个问题。
建议熟悉 Pod。
# 背景
在 Docker 中也有一个 docker Volume 的概念,Docker 的 Volume 只是磁盘中的一个目录,生命周期不受管理。当然 Docker 现在也提供 Volume 将数据持久化存储,但支持功能比较少(例如,对于 Docker 1.7,每个容器只允许挂载一个 Volume,并且不能将参数传递给 Volume)。
另一方面,k8s Volume 具有明确的生命周期 - 与 pod 相同。因此,Volume 的生命周期比 Pod 中运行的任何容器要持久,在容器重新启动时能可以保留数据,当然,当 Pod 被删除不存在时,Volume 也将消失。注意,k8s 支持许多类型的 Volume,Pod 可以同时使用任意类型/数量的 Volume。
内部实现中,一个 Volume 只是一个目录,目录中可能有一些数据,pod 的容器可以访问这些数据。至于这个目录是如何产生的、支持它的介质、其中的数据内容是什么,这些都由使用的特定 Volume 类型来决定。
要使用 Volume,pod 需要指定 Volume 的类型和内容(spec.volumes 字段),和映射到容器的位置(spec.containers.volumeMounts 字段)。
# Volume 类型
k8s 支持 Volume 类型有:
- emptyDir
- hostPath
- gcePersistentDisk
- awsElasticBlockStore
- nfs
- iscsi
- fc (fibre channel)
- flocker
- glusterfs
- rbd
- cephfs
- gitRepo
- secret
- persistentVolumeClaim
- downwardAPI
- projected
- azureFileVolume
- azureDisk
- vsphereVolume
- Quobyte
- PortworxVolume
- ScaleIO
- StorageOS
- local
# emptyDir
使用 emptyDir,当 Pod 分配到 Node 上时,将会创建 emptyDir,并且只要 Node 上的 Pod 一直运行,Volume 就会一直存。当 Pod(不管任何原因)从 Node 上被删除时,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: {}
# 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:
# directory location on host
path: /data
# gcePersistentDisk
gcePersistentDisk 可以挂载 GCE 上的永久磁盘到容器,需要 k8s 运行在 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 盘到容器,需要 k8s 运行在 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
# NFS
NFS 是 Network File System 的缩写,即网络文件系统。k8s 中通过简单地配置就可以挂载 NFS 到 Pod 中,而 NFS 中的数据是可以永久保存的,同时 NFS 支持同时写操作。Pod 被删除时,Volume 被卸载,内容被保留。这就意味着 NFS 能够允许我们提前对数据进行处理,而且这些数据可以在 Pod 之间相互传递。
详细信息,请参阅 NFS 示例。
# 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"
# secret
secret volume 用于将敏感信息(如密码)传递给 pod。可以将 secrets 存储在 k8s API 中,使用的时候以文件的形式挂载到 pod 中,而不用连接 api。 secret volume 由 tmpfs(RAM 支持的文件系统)支持。
详细了解 secret
# persistentVolumeClaim
persistentVolumeClaim 用来挂载持久化磁盘的。PersistentVolumes 是用户在不知道特定云环境的细节的情况下,实现持久化存储(如 GCE PersistentDisk 或 iSCSI 卷)的一种方式。
更多详细信息,请参阅 PersistentVolumes 示例。
# 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
# FlexVolume
alpha 功能
更多细节在这里
# AzureFileVolume
AzureFileVolume 用于将 Microsoft Azure 文件卷(SMB 2.1 和 3.0)挂载到 Pod 中。
更多细节在这里
# AzureDiskVolume
Azure 是微软提供的公有云服务,如果使用 Azure 上面的虚拟机来作为 k8s 集群使用时,那么可以通过 AzureDisk 这种类型的卷插件来挂载 Azure 提供的数据磁盘。
更多细节在这里
# vsphereVolume
需要条件:配置了 vSphere Cloud Provider 的 k8s。有关 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
在 k8s 中使用 Quobyte 存储,需要提前部署 Quobyte 软件,要求必须是 1.3 以及更高版本,并且在 k8s 管理的节点上面部署 Quobyte 客户端。
详细信息,请参阅这里。
# PortworxVolume
Portworx 能把你的服务器容量进行蓄积(pool),将你的服务器或者云实例变成一个聚合的高可用的计算和存储节点。
PortworxVolume 可以通过 k8s 动态创建,也可以在 k8s 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 示例。
# 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: k8s/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 示例。
# Local
目前处于 k8s 1.7 中的 alpha 级别。
Local 是 k8s 集群中每个节点的本地存储(如磁盘,分区或目录),在 k8s1.7 中 kubelet 可以支持对 kube-reserved 和 system-reserved 指定本地存储资源。
通过上面的这个新特性可以看出来,Local Storage 同 HostPath 的区别在于对 Pod 的调度上,使用 Local Storage 可以由 k8s 自动的对 Pod 进行调度,而是用 HostPath 只能人工手动调度 Pod,因为 k8s 已经知道了每个节点上 kube-reserved 和 system-reserved 设置的本地存储限制。
示例:
apiVersion: v1
kind: PersistentVolume
metadata:
name: example-pv
annotations:
"volume.alpha.k8s.io/node-affinity": '{
"requiredDuringSchedulingIgnoredDuringExecution": {
"nodeSelectorTerms": [
{ "matchExpressions": [
{ "key": "k8s.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
# Using subPath
有时,可以在一个 pod 中,将同一个卷共享,使其有多个用处。volumeMounts.subPath 特性可以用来指定卷中的一个子目录,而不是直接使用卷的根目录。
以下是使用单个共享卷的 LAMP 堆栈(Linux Apache Mysql PHP)的 pod 的示例。HTML 内容映射到其 html 文件夹,数据库将存储在 mysql 文件夹中:
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
# Resources
emptyDir Volume 的存储介质(Disk,SSD 等)取决于 kubelet 根目录(如/var/lib/kubelet)所处文件系统的存储介质。不限制 emptyDir 或 hostPath Volume 使用的空间大小,不对容器或 Pod 的资源隔离。