PersistentVolume
PersistentVolume (PV) 和 PersistentVolumeClaim (PVC) 提供了方便的持久化卷:PV 提供网络存储资源,而 PVC 请求存储资源。这样,设置持久化的工作流包括配置底层文件系统或者云数据卷、创建持久性数据卷、最后创建 PVC 来将 Pod 跟数据卷关联起来。PV 和 PVC 可以将 pod 和数据卷解耦,pod 不需要知道确切的文件系统或者支持它的持久化引擎。

Volume 生命周期

Volume 的生命周期包括 5 个阶段
    1.
    Provisioning,即 PV 的创建,可以直接创建 PV(静态方式),也可以使用 StorageClass 动态创建
    2.
    Binding,将 PV 分配给 PVC
    3.
    Using,Pod 通过 PVC 使用该 Volume,并可以通过准入控制 StorageObjectInUseProtection(1.9 及以前版本为 PVCProtection)阻止删除正在使用的 PVC
    4.
    Releasing,Pod 释放 Volume 并删除 PVC
    5.
    Reclaiming,回收 PV,可以保留 PV 以便下次使用,也可以直接从云存储中删除
    6.
    Deleting,删除 PV 并从云存储中删除后段存储
根据这 5 个阶段,Volume 的状态有以下 4 种
    Available:可用
    Bound:已经分配给 PVC
    Released:PVC 解绑但还未执行回收策略
    Failed:发生错误

API 版本对照表

Kubernetes 版本
PV/PVC 版本
StorageClass 版本
v1.5-v1.6
core/v1
storage.k8s.io/v1beta1
v1.7+
core/v1
storage.k8s.io/v1

PV

PersistentVolume(PV)是集群之中的一块网络存储。跟 Node 一样,也是集群的资源。PV 跟 Volume (卷) 类似,不过会有独立于 Pod 的生命周期。比如一个 NFS 的 PV 可以定义为
1
apiVersion: v1
2
kind: PersistentVolume
3
metadata:
4
name: pv0003
5
spec:
6
capacity:
7
storage: 5Gi
8
accessModes:
9
- ReadWriteOnce
10
persistentVolumeReclaimPolicy: Recycle
11
nfs:
12
path: /tmp
13
server: 172.17.0.2
Copied!
PV 的访问模式(accessModes)有三种:
    ReadWriteOnce(RWO):是最基本的方式,可读可写,但只支持被单个节点挂载。
    ReadOnlyMany(ROX):可以以只读的方式被多个节点挂载。
    ReadWriteMany(RWX):这种存储可以以读写的方式被多个节点共享。不是每一种存储都支持这三种方式,像共享方式,目前支持的还比较少,比较常用的是 NFS。在 PVC 绑定 PV 时通常根据两个条件来绑定,一个是存储的大小,另一个就是访问模式。
PV 的回收策略(persistentVolumeReclaimPolicy,即 PVC 释放卷的时候 PV 该如何操作)也有三种
    Retain,不清理, 保留 Volume(需要手动清理)
    Recycle,删除数据,即 rm -rf /thevolume/*(只有 NFS 和 HostPath 支持)
    Delete,删除存储资源,比如删除 AWS EBS 卷(只有 AWS EBS, GCE PD, Azure Disk 和 Cinder 支持)

StorageClass

上面通过手动的方式创建了一个 NFS Volume,这在管理很多 Volume 的时候不太方便。Kubernetes 还提供了 StorageClass 来动态创建 PV,不仅节省了管理员的时间,还可以封装不同类型的存储供 PVC 选用。
StorageClass 包括四个部分
    provisioner:指定 Volume 插件的类型,包括内置插件(如 kubernetes.io/glusterfs)和外部插件(如 external-storage 提供的 ceph.com/cephfs)。
    mountOptions:指定挂载选项,当 PV 不支持指定的选项时会直接失败。比如 NFS 支持 hardnfsvers=4.1 等选项。
    parameters:指定 provisioner 的选项,比如 kubernetes.io/aws-ebs 支持 typezoneiopsPerGB 等参数。
    reclaimPolicy:指定回收策略,同 PV 的回收策略。
在使用 PVC 时,可以通过 DefaultStorageClass 准入控制设置默认 StorageClass, 即给未设置 storageClassName 的 PVC 自动添加默认的 StorageClass。而默认的 StorageClass 带有 annotation storageclass.kubernetes.io/is-default-class=true
Volume Plugin
Internal Provisioner
Config Example
AWSElasticBlockStore
AWS
AzureFile
AzureDisk
CephFS
-
-
Cinder
FC
-
-
FlexVolume
-
-
Flocker
-
GCEPersistentDisk
GCE
Glusterfs
Glusterfs
iSCSI
-
-
PhotonPersistentDisk
-
Quobyte
Quobyte
NFS
-
-
RBD
Ceph RBD
VsphereVolume
vSphere
PortworxVolume
ScaleIO
ScaleIO
StorageOS
StorageOS
Local
-
Local

修改默认 StorageClass

取消原来的默认 StorageClass
1
kubectl patch storageclass <default-class-name> -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"false"}}}'
Copied!
标记新的默认 StorageClass
1
kubectl patch storageclass <your-class-name> -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
Copied!

GCE 示例

单个 GCE 节点最大支持挂载 16 个 Google Persistent Disk。开启 AttachVolumeLimit 特性后,根据节点的类型最大可以挂载 128 个。
1
kind: StorageClass
2
apiVersion: storage.k8s.io/v1
3
metadata:
4
name: slow
5
provisioner: kubernetes.io/gce-pd
6
parameters:
7
type: pd-standard
8
zone: us-central1-a
Copied!

Glusterfs 示例

1
apiVersion: storage.k8s.io/v1
2
kind: StorageClass
3
metadata:
4
name: slow
5
provisioner: kubernetes.io/glusterfs
6
parameters:
7
resturl: "http://127.0.0.1:8081"
8
clusterid: "630372ccdc720a92c681fb928f27b53f"
9
restauthenabled: "true"
10
restuser: "admin"
11
secretNamespace: "default"
12
secretName: "heketi-secret"
13
gidMin: "40000"
14
gidMax: "50000"
15
volumetype: "replicate:3"
Copied!

OpenStack Cinder 示例

1
kind: StorageClass
2
apiVersion: storage.k8s.io/v1
3
metadata:
4
name: gold
5
provisioner: kubernetes.io/cinder
6
parameters:
7
type: fast
8
availability: nova
Copied!

Ceph RBD 示例

1
apiVersion: storage.k8s.io/v1
2
kind: StorageClass
3
metadata:
4
name: fast
5
provisioner: kubernetes.io/rbd
6
parameters:
7
monitors: 10.16.153.105:6789
8
adminId: kube
9
adminSecretName: ceph-secret
10
adminSecretNamespace: kube-system
11
pool: kube
12
userId: kube
13
userSecretName: ceph-secret-user
Copied!

Local Volume

Local Volume 允许将 Node 本地的磁盘、分区或者目录作为持久化存储使用。注意,Local Volume 不支持动态创建,使用前需要预先创建好 PV。
1
apiVersion: v1
2
kind: PersistentVolume
3
metadata:
4
name: example-pv
5
spec:
6
capacity:
7
storage: 100Gi
8
# volumeMode field requires BlockVolume Alpha feature gate to be enabled.
9
volumeMode: Filesystem
10
accessModes:
11
- ReadWriteOnce
12
persistentVolumeReclaimPolicy: Delete
13
storageClassName: local-storage
14
local:
15
path: /mnt/disks/ssd1
16
nodeAffinity:
17
required:
18
nodeSelectorTerms:
19
- matchExpressions:
20
- key: kubernetes.io/hostname
21
operator: In
22
values:
23
- example-node
24
---
25
kind: StorageClass
26
apiVersion: storage.k8s.io/v1
27
metadata:
28
name: local-storage
29
provisioner: kubernetes.io/no-provisioner
30
volumeBindingMode: WaitForFirstConsumer
Copied!
推荐配置
    对于需要强 IO 隔离的场景,推荐使用整块磁盘作为 Volume
    对于需要容量隔离的场景,推荐使用分区作为 Volume
    避免在集群中重新创建同名的 Node(无法避免时需要先删除通过 Affinity 引用该 Node 的 PV)
    对于文件系统类型的本地存储,推荐使用 UUID (如 ls -l /dev/disk/by-uuid)作为系统挂载点
    对于无文件系统的块存储,推荐生成一个唯一 ID 作软链接(如 /dev/dis/by-id)。这可以保证 Volume 名字唯一,并不会与其他 Node 上面的同名 Volume 混淆

PVC

PV 是存储资源,而 PersistentVolumeClaim (PVC) 是对 PV 的请求。PVC 跟 Pod 类似:Pod 消费 Node 资源,而 PVC 消费 PV 资源;Pod 能够请求 CPU 和内存资源,而 PVC 请求特定大小和访问模式的数据卷。
1
kind: PersistentVolumeClaim
2
apiVersion: v1
3
metadata:
4
name: myclaim
5
spec:
6
accessModes:
7
- ReadWriteOnce
8
resources:
9
requests:
10
storage: 8Gi
11
storageClassName: slow
12
selector:
13
matchLabels:
14
release: "stable"
15
matchExpressions:
16
- {key: environment, operator: In, values: [dev]}
Copied!
PVC 可以直接挂载到 Pod 中:
1
kind: Pod
2
apiVersion: v1
3
metadata:
4
name: mypod
5
spec:
6
containers:
7
- name: myfrontend
8
image: dockerfile/nginx
9
volumeMounts:
10
- mountPath: "/var/www/html"
11
name: mypd
12
volumes:
13
- name: mypd
14
persistentVolumeClaim:
15
claimName: myclaim
Copied!

扩展 PV 空间

ExpandPersistentVolumes 在 v1.8 开始 Alpha,v1.11 升级为 Beta 版。
v1.8 开始支持扩展 PV 空间,支持在不丢失数据和重启容器的情况下扩展 PV 的大小。注意, 当前的实现仅支持不需要调整文件系统大小(XFS、Ext3、Ext4)的 PV,并且只支持以下几种存储插件
    AzureDisk
    AzureFile
    gcePersistentDisk
    awsElasticBlockStore
    Cinder
    glusterfs
    rbd
    Portworx
开启扩展 PV 空间的功能需要配置
    开启 ExpandPersistentVolumes 功能,即配置 --feature-gates=ExpandPersistentVolumes=true
    开启准入控制插件 PersistentVolumeClaimResize,它只允许扩展明确配置 allowVolumeExpansion=true 的 StorageClass,比如
1
kind: StorageClass
2
apiVersion: storage.k8s.io/v1
3
metadata:
4
name: gluster-vol-default
5
provisioner: kubernetes.io/glusterfs
6
parameters:
7
resturl: "http://192.168.10.100:8080"
8
restuser: ""
9
secretNamespace: ""
10
secretName: ""
11
allowVolumeExpansion: true
Copied!
这样,用户就可以修改 PVC 中请求存储的大小(如通过 kubectl edit 命令)请求更大的存储空间。

块存储(Raw Block Volume)

Kubernetes v1.9 新增了 Alpha 版的 Raw Block Volume,可通过设置 volumeMode: Block(可选项为 FilesystemBlock)来使用块存储。
注意:使用前需要为 kube-apiserver、kube-controller-manager 和 kubelet 开启 BlockVolume 特性,即添加命令行选项 --feature-gates=BlockVolume=true,...
支持块存储的 PV 插件包括
    Local Volume
    fc
    iSCSI
    Ceph RBD
    AWS EBS
    GCE PD
    AzureDisk
    Cinder
使用示例
1
# Persistent Volumes using a Raw Block Volume
2
apiVersion: v1
3
kind: PersistentVolume
4
metadata:
5
name: block-pv
6
spec:
7
capacity:
8
storage: 10Gi
9
accessModes:
10
- ReadWriteOnce
11
volumeMode: Block
12
persistentVolumeReclaimPolicy: Retain
13
fc:
14
targetWWNs: ["50060e801049cfd1"]
15
lun: 0
16
readOnly: false
17
---
18
# Persistent Volume Claim requesting a Raw Block Volume
19
apiVersion: v1
20
kind: PersistentVolumeClaim
21
metadata:
22
name: block-pvc
23
spec:
24
accessModes:
25
- ReadWriteOnce
26
volumeMode: Block
27
resources:
28
requests:
29
storage: 10Gi
30
---
31
# Pod specification adding Raw Block Device path in container
32
apiVersion: v1
33
kind: Pod
34
metadata:
35
name: pod-with-block-volume
36
annotations:
37
# apparmor should be unconfied for mounting the device inside container.
38
container.apparmor.security.beta.kubernetes.io/fc-container: unconfined
39
spec:
40
containers:
41
- name: fc-container
42
image: fedora:26
43
command: ["/bin/sh", "-c"]
44
args: ["tail -f /dev/null"]
45
securityContext:
46
capabilities:
47
# CAP_SYS_ADMIN is required for mount() syscall.
48
add: ["SYS_ADMIN"]
49
volumeDevices:
50
- name: data
51
devicePath: /dev/xvda
52
volumes:
53
- name: data
54
persistentVolumeClaim:
55
claimName: block-pvc
Copied!

StorageObjectInUseProtection

准入控制 StorageObjectInUseProtection 在 v1.11 版本 GA。
当开启准入控制 StorageObjectInUseProtection(--admission-control=StorageObjectInUseProtection)时,删除使用中的 PV 和 PVC 后,它们会等待使用者删除后才删除(而不是之前的立即删除)。而在使用者删除之前,它们会一直处于 Terminating 状态。

拓扑感知动态调度

拓扑感知动态存储卷调度(topology-aware dynamic provisioning)是 v1.12 版本的一个 Beta 特性,用来支持在多可用区集群中动态创建和调度持久化存储卷。目前的实现支持以下几种存储:
    AWS EBS
    Azure Disk
    GCE PD (including Regional PD)
    CSI (alpha) - currently only the GCE PD CSI driver has implemented topology support
使用示例
1
# set WaitForFirstConsumer in storage class
2
kind: StorageClass
3
apiVersion: storage.k8s.io/v1
4
metadata:
5
name: topology-aware-standard
6
provisioner: kubernetes.io/gce-pd
7
volumeBindingMode: WaitForFirstConsumer
8
parameters:
9
type: pd-standard
10
11
# Refer storage class
12
apiVersion: apps/v1
13
kind: StatefulSet
14
metadata:
15
name: web
16
spec:
17
serviceName: "nginx"
18
replicas: 2
19
selector:
20
matchLabels:
21
app: nginx
22
template:
23
metadata:
24
labels:
25
app: nginx
26
spec:
27
affinity:
28
nodeAffinity:
29
requiredDuringSchedulingIgnoredDuringExecution:
30
nodeSelectorTerms:
31
- matchExpressions:
32
- key: failure-domain.beta.kubernetes.io/zone
33
operator: In
34
values:
35
- us-central1-a
36
- us-central1-f
37
podAntiAffinity:
38
requiredDuringSchedulingIgnoredDuringExecution:
39
- labelSelector:
40
matchExpressions:
41
- key: app
42
operator: In
43
values:
44
- nginx
45
topologyKey: failure-domain.beta.kubernetes.io/zone
46
containers:
47
- name: nginx
48
image: gcr.io/google_containers/nginx-slim:0.8
49
ports:
50
- containerPort: 80
51
name: web
52
volumeMounts:
53
- name: www
54
mountPath: /usr/share/nginx/html
55
- name: logs
56
mountPath: /logs
57
volumeClaimTemplates:
58
- metadata:
59
name: www
60
spec:
61
accessModes: [ "ReadWriteOnce" ]
62
storageClassName: topology-aware-standard
63
resources:
64
requests:
65
storage: 10Gi
66
- metadata:
67
name: logs
68
spec:
69
accessModes: [ "ReadWriteOnce" ]
70
storageClassName: topology-aware-standard
71
resources:
72
requests:
73
storage: 1Gi
Copied!
然后查看 PV,可以发现它们创建在不同的可用区内
1
$ kubectl get pv -o=jsonpath='{range .items[*]}{.spec.claimRef.name}{"\t"}{.metadata.labels.failure\-domain\.beta\.kubernetes\.io/zone}{"\n"}{end}'
2
www-web-0 us-central1-f
3
logs-web-0 us-central1-f
4
www-web-1 us-central1-a
5
logs-web-1 us-central1-a
Copied!

存储快照

存储快照是 v1.12 新增的 Alpha 特性,用来支持给存储卷创建快照。支持的插件包括
image-20181014215558480
在使用前需要开启特性开关 VolumeSnapshotDataSource。
使用示例:
1
# create snapshot
2
apiVersion: snapshot.storage.k8s.io/v1alpha1
3
kind: VolumeSnapshot
4
metadata:
5
name: new-snapshot-demo
6
namespace: demo-namespace
7
spec:
8
snapshotClassName: csi-snapclass
9
source:
10
name: mypvc
11
kind: PersistentVolumeClaim
12
13
# import from snapshot
14
apiVersion: snapshot.storage.k8s.io/v1alpha1
15
kind: VolumeSnapshotContent
16
metadata:
17
name: static-snapshot-content
18
spec:
19
csiVolumeSnapshotSource:
20
driver: com.example.csi-driver
21
snapshotHandle: snapshotcontent-example-id
22
volumeSnapshotRef:
23
kind: VolumeSnapshot
24
name: static-snapshot-demo
25
namespace: demo-namespace
26
27
# provision volume from snapshot
28
apiVersion: v1
29
kind: PersistentVolumeClaim
30
metadata:
31
name: pvc-restore
32
Namespace: demo-namespace
33
spec:
34
storageClassName: csi-storageclass
35
dataSource:
36
name: new-snapshot-demo
37
kind: VolumeSnapshot
38
apiGroup: snapshot.storage.k8s.io
39
accessModes:
40
- ReadWriteOnce
41
resources:
42
requests:
43
storage: 1Gi
Copied!

参考文档

最近更新 1mo ago