千寻

道路很长, 开始了就别停下!

0%

Kubernetes对象之PersistentVolume和PersistentVolumeClaim

学习本节内容前,希望你已经对Kubernetes中Volume的概念有了初步的了解,具体请参考这篇文章:

  • [Kubernetes基本概念之Volume]

简介

Kubernetes的pod本身是无状态的(stateless),生命周期通常比较短,只要出现了异常,Kubernetes就会自动创建一个新的Pod来代替它。

而容器产生的数据,会随着Pod消亡而自动消失。

为了实现Pod内数据的存储管理,Kubernetes引入了两个API资源:Persistent Volume(持久卷,以下简称PV)和Persistent Volume Claim(持久卷申请,以下简称PVC)。

PV

  • PV是Kubernetes集群中的一种网络存储实现,跟Node一样,也是属于集群的资源。

  • PV跟Docker里的Volume(卷)类似,不过会有独立于Pod的生命周期。

  • PersistentVolume和Volume一样,代表了集群中的一块存储区域,然而Kubernetes将PersistentVolume抽象成了一种集群资源,类似于集群中的Node对象,这意味着我们可以使用Kubernetes API来创建PersistentVolume对象。

  • PV与Volume最大的不同是PV拥有着独立于Pod的生命周期。

    PVC

    PersistentVolumeClaim(PVC)代表了用户对PV资源的请求。用户需要使用PV资源时,只需要创建一个PVC对象(包括指定使用何种存储资源,使用多少GB,以何种模式使用PV等信息),Kubernetes会自动为我们分配我们所需的PV。

如果把PersistentVolume类比成集群中的Node,那么PersistentVolumeClaim就相当于集群中的Pod,Kubernetes为Pod分配可用的Node,为PersistentVolumeClaim分配可用的PersistentVolume。

1. PV的静态创建

首先是一个创建PV的简单例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv0003
spec:
capacity:
storage: 5Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Recycle
storageClassName: slow
mountOptions:
- hard
- nfsvers=4.1
nfs:
path: /tmp
server: 172.17.0.2

PV 的访问模式(accessModes)有三种:

  1. ReadWriteOnce(RWO):是最基本的方式,可读可写,但只支持被单个 Pod 挂载。
  2. ReadOnlyMany(ROX):可以以只读的方式被多个 Pod 挂载。
  3. ReadWriteMany(RWX):这种存储可以以读写的方式被多个 Pod 共享。
    不是每一种PV都支持这三种方式,例如ReadWriteMany,目前支持的还比较少。在 PVC 绑定 PV 时通常根据两个条件来绑定,一个是存储的大小,另一个就是访问模式。

PV 的回收策略(persistentVolumeReclaimPolicy,即 PVC 释放卷的时候 PV 该如何操作)也有三种:

  • Retain,不清理, 保留 Volume(需要手动清理)
  • Recycle,删除数据,即 rm -rf /thevolume/*(只有 NFS 和 HostPath 支持)
  • Delete,删除存储资源,比如删除 AWS EBS 卷(只有 AWS EBS, GCE PD, Azure Disk 和 Cinder 支持)

PVC释放卷是指用户删除一个PVC对象时,那么与该PVC对象绑定的PV就会被释放。

1.1 PV支持的类型
定义PV时,我们需要指定其底层存储的类型,例如上文中创建的PV,底层使用nfs存储。目前Kuberntes支持以下类型:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
GCEPersistentDisk
AWSElasticBlockStore
AzureFile
AzureDisk
FC (Fibre Channel)**
FlexVolume
Flocker
NFS
iSCSI
RBD (Ceph Block Device)
CephFS
Cinder (OpenStack block storage)
Glusterfs
VsphereVolume
Quobyte Volumes
HostPath (Single node testing only – local storage is not supported in any way and WILL NOT WORK in a multi-node cluster)
VMware Photon
Portworx Volumes
ScaleIO Volumes
StorageOS

2. PVC的创建

当我们定义好一个PV后,我们希望像使用Volume那样使用这个PV,那么我们需要做的就是创建一个PVC对象,并在Pod定义中使用这个PVC。
定义一个PVC:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: myclaim
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 8Gi
storageClassName: slow
selector:
matchLabels:
release: "stable"

Pod通过挂在Volume的方式应用PVC:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
kind: Pod
apiVersion: v1
metadata:
name: mypod
spec:
containers:
- name: myfrontend
image: dockerfile/nginx
volumeMounts:
- mountPath: "/var/www/html"
name: mypd
volumes:
- name: mypd
persistentVolumeClaim:
claimName: myclaim

下面简要分析一下定义的PVC文件的关键:

  • 首先关注这个配置:storageClassName: slow。此配置用于绑定PVC和PV。这表明这个PVC希望使用storageClassName=slow的PV。返回到上文中PV的定义,我们可以看到PV定义中也包含storageClassName=slow的配置。
  • 接下来是accessModes = ReadWriteOnce。这表明这个PV希望使用storageClassName=slow,并且accessModes = ReadWriteOnce的PV。
  • 在上述条件都满足后,PVC还可以指定PV必须满足的Label,如matchLabels: release: “stable”。这表明此PVC希望使用storageClassName=slow,accessModes = ReadWriteOnce并且拥有Label:release: “stable”的PV。
  • 最后是storage: 8Gi。这表明此PVC希望使用8G的Volume资源。

通过上面的分析,我们可以看到PVC和PV的绑定,不是简单的通过Label来进行。而是要综合storageClassName,accessModes,matchLabels以及storage来进行绑定。

3. PV的动态创建

上文中我们通过PersistentVolume描述文件创建了一个PV。这样的创建方式我们成为静态创建。这样的创建方式有一个弊端,那就是假如我们创建PV时指定大小为50G,而PVC请求80G的PV,那么此PVC就无法找到合适的PV来绑定。因此产生了了PV的动态创建。

PV的动态创建依赖于StorageClass对象。我们不需要手动创建任何PV,所有的工作都由StorageClass为我们完成。一个例子如下:

1
2
3
4
5
6
7
8
9
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: slow
provisioner: kubernetes.io/aws-ebs
parameters:
type: io1
zones: us-east-1d, us-east-1c
iopsPerGB: "10"

这个例子使用AWS提供的插件( kubernetes.io/aws-ebs)创建了一个基于AWS底层存储的StorageClass。这意味着使用这个StorageClass,那么所有的PV都是AWSElasticBlockStore类型的。

StorageClass的定义包含四个部分:

  • provisioner:指定 Volume 插件的类型,包括内置插件(如 kubernetes.io/aws-ebs)和外部插件(如 external-storage 提供的 ceph.com/cephfs)。
  • mountOptions:指定挂载选项,当 PV 不支持指定的选项时会直接失败。比如 NFS 支持 hard 和 nfsvers=4.1 等选项。
  • parameters:指定 provisioner 的选项,比如 kubernetes.io/aws-ebs 支持 type、zone、iopsPerGB 等参数。
  • reclaimPolicy:指定回收策略,同 PV 的回收策略。

手动创建的PV时,我们指定了storageClassName=slow的配置项,然后Pod定义中也通过指定storageClassName=slow,从而完成绑定。而通过StorageClass实现动态PV时,我们只需要指定StorageClass的metadata.name。

回到上文中创建PVC的例子,此时PVC指定了storageClassName=slow。那么Kubernetes会在集群中寻找是否存在metadata.name=slow的StorageClass,如果存在,此StorageClass会自动为此PVC创建一个accessModes = ReadWriteOnce,并且大小为8GB的PV。

通过StorageClass的使用,使我们从提前构建静态PV池的工作中解放出来。

4. PV的生命周期

PV的生命周期包括 6 个阶段:

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

一个PV从创建到销毁的具体流程如下:

  1. 一个PV创建完后状态会变成Available,等待被PVC绑定。
  2. 一旦被PVC邦定,PV的状态会变成Bound,就可以被定义了相应PVC的Pod使用。
  3. Pod使用完后会释放PV,PV的状态变成Released。
  4. 变成Released的PV会根据定义的回收策略做相应的回收工作。有三种回收策略,Retain、Delete 和 Recycle。
    • Retain就是保留现场,K8S什么也不做,等待用户手动去处理PV里的数据,处理完后,再手动删除PV。
    • Delete 策略,K8S会自动删除该PV及里面的数据。
    • Recycle方式,K8S会将PV里的数据删除,然后把PV的状态变成Available,又可以被新的PVC绑定使用。

5. DefaultStorageClass

前面我们说到,PVC和PV的绑定是通过StorageClassName进行的。然而如果定义PVC时没有指定StorageClassName呢?这取决与admission插件是否开启了DefaultDefaultStorageClass功能:

如果DefaultStorageClass功能开启,那么此PVC的StorageClassName就会被指定为DefaultStorageClass。DefaultStorageClass从何处而来呢?原来在定义StorageClass时,可以在Annotation中添加一个键值对:storageclass.kubernetes.io/is-default-class: true,那么此StorageClass就变成默认的StorageClass了。

如果DefaultStorageClass功能没有开启,那么没有指定StorageClassName的PVC只能被绑定到同样没有指定StorageClassName的PV。

常见问题

  1. pod has unbound immediate PersistentVolumeClaims

参考文章
http://blog.csdn.net/liukuan73/article/details/60089305
https://www.jianshu.com/p/99e610067bc8