Kubernetes对象之PersistentVolume,StorageClass和PersistentVolumeClaim

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

前面我们学习了Kubernetes中的Volume,我们可以发现前文中的Volume(无论何种类型)和使用它的Pod都是一种静态绑定关系,在Pod定义文件中,同时定义了它使用的Volume。在这种情况下,Volume是Pod的附属品,我们无法像创建其他资源(例如Pod,Node,Deployment等等)一样创建一个Volume。

因此Kubernetes提出了PersistentVolume(PV)的概念。PersistentVolume和Volume一样,代表了集群中的一块存储区域,然而Kubernetes将PersistentVolume抽象成了一种集群资源,类似于集群中的Node对象,这意味着我们可以使用Kubernetes API来创建PersistentVolume对象。PV与Volume最大的不同是PV拥有着独立于Pod的生命周期。

而PersistentVolumeClaim(PVC)代表了用户对PV资源的请求。用户需要使用PV资源时,只需要创建一个PVC对象(包括指定使用何种存储资源,使用多少GB,以何种模式使用PV等信息),Kubernetes会自动为我们分配我们所需的PV。如果把PersistentVolume类比成集群中的Node,那么PersistentVolumeClaim就相当于集群中的Pod,Kubernetes为Pod分配可用的Node,为PersistentVolumeClaim分配可用的PersistentVolume。

1. PV的静态创建

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

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)有三种:

  • ReadWriteOnce(RWO):是最基本的方式,可读可写,但只支持被单个 Pod 挂载。
  • ReadOnlyMany(ROX):可以以只读的方式被多个 Pod 挂载。
  • 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支持以下类型:

  • 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:

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: myclaim
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 8Gi
  storageClassName: slow
  selector:
    matchLabels:
      release: "stable"

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

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=slowaccessModes = ReadWriteOnce并且拥有Label:release: "stable"的PV。
  • 最后是storage: 8Gi。这表明此PVC希望使用8G的Volume资源。

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

storage来进行绑定。

3. PV的动态创建

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

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

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池的工作中解放出来。

目前StorageClass支持如下类型:


storageClass.PNG

4. PV的生命周期

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

  • Provisioning,即 PV 的创建,可以直接创建 PV(静态方式),也可以使用 StorageClass 动态创建
  • Binding,将 PV 分配给 PVC
  • Using,Pod 通过 PVC 使用该 Volume,并可以通过准入控制 StorageProtection(1.9及以前版本为PVCProtection)阻止删除正在使用的 PVC
  • Releasing,Pod 释放 Volume 并删除 PVC
  • Reclaiming,回收 PV,可以保留 PV 以便下次使用,也可以直接从云存储中删除
    Deleting,删除 PV 并从云存储中删除后段存储

根据这 5 个阶段,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功能:

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

参考文章

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容