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
注意,这些 volume 并非全部都是持久化的,比如 emptyDir、secret、gitRepo 等,这些 volume 会随着 Pod 的消亡而消失。

API 版本对照表

Kubernetes 版本
Core API 版本
v1.5+
core/v1

emptyDir

如果 Pod 设置了 emptyDir 类型 Volume, Pod 被分配到 Node 上时候,会创建 emptyDir,只要 Pod 运行在 Node 上,emptyDir 都会存在(容器挂掉不会导致 emptyDir 丢失数据),但是如果 Pod 从 Node 上被删除(Pod 被删除,或者 Pod 发生迁移),emptyDir 也会被删除,并且永久丢失。
1
apiVersion: v1
2
kind: Pod
3
metadata:
4
name: test-pd
5
spec:
6
containers:
7
- image: gcr.io/google_containers/test-webserver
8
name: test-container
9
volumeMounts:
10
- mountPath: /cache
11
name: cache-volume
12
volumes:
13
- name: cache-volume
14
emptyDir: {}
Copied!

hostPath

hostPath 允许挂载 Node 上的文件系统到 Pod 里面去。如果 Pod 需要使用 Node 上的文件,可以使用 hostPath。
1
apiVersion: v1
2
kind: Pod
3
metadata:
4
name: test-pd
5
spec:
6
containers:
7
- image: gcr.io/google_containers/test-webserver
8
name: test-container
9
volumeMounts:
10
- mountPath: /test-pd
11
name: test-volume
12
volumes:
13
- name: test-volume
14
hostPath:
15
path: /data
Copied!

NFS

NFS 是 Network File System 的缩写,即网络文件系统。Kubernetes 中通过简单地配置就可以挂载 NFS 到 Pod 中,而 NFS 中的数据是可以永久保存的,同时 NFS 支持同时写操作。
1
volumes:
2
- name: nfs
3
nfs:
4
# FIXME: use the right hostname
5
server: 10.254.234.223
6
path: "/"
Copied!

gcePersistentDisk

gcePersistentDisk 可以挂载 GCE 上的永久磁盘到容器,需要 Kubernetes 运行在 GCE 的 VM 中。
1
volumes:
2
- name: test-volume
3
# This GCE PD must already exist.
4
gcePersistentDisk:
5
pdName: my-data-disk
6
fsType: ext4
Copied!

awsElasticBlockStore

awsElasticBlockStore 可以挂载 AWS 上的 EBS 盘到容器,需要 Kubernetes 运行在 AWS 的 EC2 上。
1
volumes:
2
- name: test-volume
3
# This AWS EBS volume must already exist.
4
awsElasticBlockStore:
5
volumeID: <volume-id>
6
fsType: ext4
Copied!

gitRepo

gitRepo volume 将 git 代码下拉到指定的容器路径中
1
volumes:
2
- name: git-volume
3
gitRepo:
4
repository: "[email protected]:me/my-git-repository.git"
5
revision: "22f1d8406d464b0c0874075539c1f2e96c253775"
Copied!

使用 subPath

Pod 的多个容器使用同一个 Volume 时,subPath 非常有用
1
apiVersion: v1
2
kind: Pod
3
metadata:
4
name: my-lamp-site
5
spec:
6
containers:
7
- name: mysql
8
image: mysql
9
volumeMounts:
10
- mountPath: /var/lib/mysql
11
name: site-data
12
subPath: mysql
13
- name: php
14
image: php
15
volumeMounts:
16
- mountPath: /var/www/html
17
name: site-data
18
subPath: html
19
volumes:
20
- name: site-data
21
persistentVolumeClaim:
22
claimName: my-lamp-site-data
Copied!

FlexVolume

如果内置的这些 Volume 不满足要求,则可以使用 FlexVolume 实现自己的 Volume 插件。注意要把 volume plugin 放到 /usr/libexec/kubernetes/kubelet-plugins/volume/exec/<vendor~driver>/<driver>,plugin 要实现 init/attach/detach/mount/umount 等命令(可参考 lvm 的 示例)。
1
- name: test
2
flexVolume:
3
driver: "kubernetes.io/lvm"
4
fsType: "ext4"
5
options:
6
volumeID: "vol1"
7
size: "1000m"
8
volumegroup: "kube_vg"
Copied!

Projected Volume

Projected volume 将多个 Volume 源映射到同一个目录中,支持 secret、downwardAPI 和 configMap。
1
apiVersion: v1
2
kind: Pod
3
metadata:
4
name: volume-test
5
spec:
6
containers:
7
- name: container-test
8
image: busybox
9
volumeMounts:
10
- name: all-in-one
11
mountPath: "/projected-volume"
12
readOnly: true
13
volumes:
14
- name: all-in-one
15
projected:
16
sources:
17
- secret:
18
name: mysecret
19
items:
20
- key: username
21
path: my-group/my-username
22
- downwardAPI:
23
items:
24
- path: "labels"
25
fieldRef:
26
fieldPath: metadata.labels
27
- path: "cpu_limit"
28
resourceFieldRef:
29
containerName: container-test
30
resource: limits.cpu
31
- configMap:
32
name: myconfigmap
33
items:
34
- key: config
35
path: my-group/my-config
Copied!

本地存储限额

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 的可写层存储空间
1
apiVersion: v1
2
kind: Pod
3
metadata:
4
name: ls1
5
spec:
6
restartPolicy: Never
7
containers:
8
- name: hello
9
image: busybox
10
command: ["df"]
11
resources:
12
requests:
13
storage.kubernetes.io/overlay: 64Mi
Copied!
为 empty 请求 64MB 的存储空间
1
apiVersion: v1
2
kind: Pod
3
metadata:
4
name: ls1
5
spec:
6
restartPolicy: Never
7
containers:
8
- name: hello
9
image: busybox
10
command: ["df"]
11
volumeMounts:
12
- name: data
13
mountPath: /data
14
volumes:
15
- name: data
16
emptyDir:
17
sizeLimit: 64Mi
Copied!

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
    rslavershared 的说明可以参考 内核文档

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"
1
apiVersion: v1
2
kind: Pod
3
metadata:
4
name: hostpath-pod
5
spec:
6
containers:
7
- name: hostpath-nano
8
image: microsoft/nanoserver:1709
9
stdin: true
10
tty: true
11
volumeMounts:
12
- name: blah
13
mountPath: "C:\\etc\\foo"
14
readOnly: true
15
nodeSelector:
16
beta.kubernetes.io/os: windows
17
volumes:
18
- name: blah
19
hostPath:
20
path: "C:\\AzureData"
Copied!
1
apiVersion: v1
2
kind: Pod
3
metadata:
4
name: empty-dir-pod
5
spec:
6
containers:
7
- image: microsoft/nanoserver:1709
8
name: empty-dir-nano
9
stdin: true
10
tty: true
11
volumeMounts:
12
- mountPath: /cache
13
name: cache-volume
14
- mountPath: C:/scratch
15
name: scratch-volume
16
volumes:
17
- name: cache-volume
18
emptyDir: {}
19
- name: scratch-volume
20
emptyDir: {}
21
nodeSelector:
22
beta.kubernetes.io/os: windows
Copied!

挂载传播

挂载传播(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 参考示例

最近更新 2yr ago