当前位置:   article > 正文

kubernetes in action读书笔记(三)pod中的磁盘挂载,卷/持久卷/持久卷声明_kubernetes 卷声明

kubernetes 卷声明

卷(volume

为了能够让pod在运行期间使用磁盘资源,kubernetes为pod定义了volume属性,和pod拥有相同的生命周期,pod创建时创建 ,pod删除时删除,volume本身并不是一个独立的kubernetes资源对象,而是pod的一个属性,volume可以理解为不同的存储类型,常见的可以支持的类型包括:

  • hostPath,将node上的一个目录挂载在pod中
  • NFS,network file system,一种网络存储技术
  • emptyDir,存储临时数据简单空目录
  • gitRepo,用一个具体的git仓库地址对应的内容来初始化的volume
  • cephfs,一种分布式的存储技术
  • configMap/secret,将一个kubernetes的configmap/sercret内容转存为文件后挂载在pod 对应文件路径下
  • persistVolumeClaim,一种动态配置的持久存储类型

对于卷(volume)的使用,一般分两步:

  1. 声明一个volume
  2. 挂载应用程序需要的目录到已经声明的volume

一个简单的例子:

apiVersion: v1
kind: Pod
metadata:  
  name: fortune
spec:
  containers:
  - image: luksa/fortune
    name: html-generator
    volumeMounts: //在html卷下挂载一个路径
    - name: html
      mountPath: /var/htdocs
  - image: nginx:alphine
    name: web-server
    volumeMounts: //在html卷下挂载一个路径
    - name: html
      mountPath: /usr/share/nginx/html
      readOnly: true
volumes: //一个类型为empty的volume,名字叫html
- name: html
  emptyDir: {}
    medium:  Memory //可以指定卷的类型,使用内存而不是磁盘,提高效率
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

emptyDir是最简单的卷类型,其他卷都是基于empty进行构建的,举个例子,类型为git-repo的卷类型 ,其yaml如下:

volumes: //一个类型为empty的volume,名字叫html
- name: html
  gitRepo: {}
    repository: xxxxxxxxx
    reverison: master
    directory: .
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

每次pod在删除创建的到时候都会从git repo拉取最新的文件,按照sidecar的逻辑来看,应该将git-repo更新的逻辑放在用一个pod的不同容器中,减少对住应用程序的影响。

以上两种volume都属于临时性存储,当pod删除时,卷的内容和卷本身都会删除,hostPath则不会,在pod删除后,新创建的pod仍然能够访问上一个pod修改后的数据,volume和volume的内容都得到了保存。只不过在使用hostPath的时候要注意连续两次的pod都必须在同一台主机上,不然会出现找不到上一个pod卷的问题。

持久卷(persist volume)和持久卷声明 (persist volume claim)

和volume一样,用以提供给pod进行数据持久化使用,只不过persistVolume和volume的区别在于persistVolume在pod删除后仍然能够在下一个pod启动后继续使用。本身和其存储的内容不会丢失,其实一个用hostPath类型volume挂载的目录已经能够实现数据的不丢失,但是受限于节点的限制,因此为了实现前后两次pod能够使用同一份数据,需要提供NAS类型的存储能力作为volume。

举个例子:NFS类型的volume

volumes: //一个类型为empty的volume,名字叫html
- name: html
  nfs: 
    server: xxx.xx.xx.xx
    path: /xxxx/xxxx
  • 1
  • 2
  • 3
  • 4
  • 5

通过声明一个类型为NFS的volume,pod在重启后可以仍然使用相同server、相同的path,可以实现读取上一个pod的volume的数据。这样做有一些弊端,比如如果NFS的地址发生了改变,name需要对所有涉及的pod进行全量的重启,导致断服,所以一种比较好的方式是将的volume存储提供服务与pod的配置分离开,当底层发生变化时,不影响上层的服务。
结合两个目标:

  1. 提供可持久化的volume
  2. 屏蔽底层存储技术,底层与pod解耦
    产生两种资源对象:PV(persist volume),PVC(persist volume claim)

使用NFS的 volume和Persist volume是两个概念,NFS的volume是卷的一种类型,支持持久化存储;Persist volume是Kubernetes的一种资源对象,在pod的使用逻辑上存在一定的区别,两种流程(流程1无PV/PVC,只有volume):
1、使用NFS的volume:用户创建pod,pod内定义了基于NFS的volume,其中包括server的ip和NFS的path,pod将自己的路径挂载在该volume上。
2、使用NFS类型的PV,用户创建pod,pod定义了pod关联的 PVC;用户定义PVC,PVC传递给api server,kubernetes基于PVC的描述,寻找或创建合适的PV(基于NFS进行创建),并将PVC绑定到对应的PV上;

与卷(volume)不同,持久卷(PV)/持久卷声明(PVC)都是Kubernetes的资源对象,kubernetes可以对PV/PVC进行管理,举一个PVC的例子:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: xxxxx-pv
spec:
  capacity: 
    storage: 5G
  accessModes:
  - ReadWriteOnce
  - ReadOnlyMany
persistentVolumeReclaimRolicy: Retain
gcePersistentDisk:
  pdName: volumePD
  fsType: ext4
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

如果在pod中要引用,则需要:

spec:
  volumes:
  - name: volumePD-data
    gcePersistentDisk:
      pdName: volumePD
      fsType: ext4 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

pod在使用PV时的步骤可以理解为以下:

  1. 手动创建PV
  2. 创建pod,yaml中的volume关联到创建的PV
  3. 创建pod过程中会等待绑定PV

经过如上操作,当pod删除后,PV仍然存在,当pod删除后下次创建,仍然能绑定到相同的PV,此时的PV如果发生改变(比如NFS的地址发生改变),pod不需要重启,这是使用PV优于直接创建volume挂载NFS的好处

使用PV解决了开发者自己生命volume带来的底层存储和上层应用的强耦合,那么每次开发者使用磁盘时,都得自己创建自己的PV吗?一个集群内的不同开发者可能会使用不同的PV,每种PV都有自己的定义方式,这对开发者来说提高了开发和学习的成本,所以引入PVC(persistentVolumeClaim)的概念,来解决这个问题。

看一个persistentVolumeClaim的例子:

aoiVersion:
kind: persistentVolumeClaim
metadata:
  name: my-pvc
spec:
  resources:
    requests:
      storage: 1G
  accessModes:
  - ReadWriteOnce
  storageClassName: ""//主要通过这个来隔离开发者与底层存储细节,开发者只需要关心resources的内容,申请过程由storageClass来完成,如果不填,那么PVC会默认的从已有的PV中寻找能够和resource匹配的对象来进行绑定,如果找不到就悲剧了
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

在pod中引用PVC时,如下:

apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  containers:
  - image: myImage
    name: imageName
    volumeMounts:
    - name: my-volume-data
      mountPath: /data
volumes:
- name: my-volume-data
  persistenVolumeClaim:
    claimName: my-pvc
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

其实和最开始我们使用volume自己挂NFS、emptyDir啥的很像,只是volumes的创建(绑定)是通过PVC来完成的,除此之外,不需要单独创建PV,但需要的单独创建PVC,pod绑定到PVC,由PVC来想办法创建或绑定到对应的PV。

当我们创建并使用一个PVC后,如果persistentVolumeClaimPolicy如果是Retain,PVC对应的PV会持久的绑定,如果手贱在pod删除后,把PVC删除了,那么再次创建的pod mount的PVC会一直pending,无法获得对应的PV(PV对应的状态时Released)
Retain的意思就是希望在PVC删除的情况下仍然保留PV的数据,如果还想用之前的PVC,那么只能手动删除对应的PV,PVC还提供delete、recycle类型的PVC,当配置为delete或recycle后,PVC创建或挂在的PV可以被不同的PVC反复使用,不会一直保留上一次的数据。但是不是所有PVC的持久化存储class都支持,需要具体去调研

StorageClass(置备程序)

截止目前我们对PVC的使用,已经将开发者对PV具体存储细节隔离开了,但是仅仅按照上述方式,那么PV的创建仍然需要一个管理员来完成,管理员完成PV的创建后,其他开发者通过定义自己的PVC(resources),获得对应的磁盘资源,如果希望持久获得就配置Retain,如果希望共享使用,就配置delete/recycle,当我们使用storageClass这个kubernetes资源对象时,就可以解放团队中的PV管理员角色了。

一个storageClass的例子:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: my-storage-class
provisioner: xxxxxx
paramters: 
  type: xxxx
  zone: xxxx
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

StorageClass定义了用哪个置备程序来创建或绑定持久卷,StorageClass是kubernetes的一个资源对象,我们甚至可以自己定义自己的置备程序,例如创建一个myStorageProvider作为pod在kubernetes,定期通过api server获取当前有哪些PVC使用了自己,确定后通过自己的逻辑为对应的pod创建PV并实现PV-PVC的绑定过程,当然这是猜测,后续如果这部分源码才能肯定。

之前的例子中仅仅使用了PVC,但storageClass字段对应是空,kubernetes会从已有的满足条件的PV中寻找合适的进行绑定,如果没有则不会创建新的,这部分逻辑其实是有默认定义的:一个默认的StorageClass,会定义如果在PVC中没有对应的StorageClass,那么就会通过该置备程序来实现PV的创建或绑定。

在这里插入图片描述

开发者角度,从volume到StorageClass

回看关于pod挂载磁盘的过程,目前可以看到从简单粗暴到逐步合理使用kubernetes特性:

L1:我的一个pod内多个容器想共享一部分数据,怎么破?创建一个volume,pod内的每个container都volumeMount上就好了

L2:pod重启了,数据都丢了,怎么破?创建volume的时候,别用emptyDir类型,用hostPath将数据存储在主机上就好了

L3:一个节点坏了,被删掉了,在之前node上的数据就再也找不到了(在hostPath上),创建volume的时候,用NFS这种远程的存储就好了

L4:NFS节点坏了,换了个集群,ip全变了,pod上再也找不到之前的数据,怎么破?不要再创建volume了,创建一个PV(persistentVolume)这样 的kubernetes资源,PV的类型写为NFS,当NFS的服务ip变更时,修改PV中的NFS server地址就好了

L5:
用户A使用时,自己创建了PV-A
用户B使用时,也需要PV,但PV创建比较麻烦,照抄了PV-A
用户C使用时,也需要PV,但存储类型和A/B不同,所以得自己去研究一下自己需要用到的存储类型PV应该如何创建
使用PVC,A/B/C三个用户只需要定义自己对资源的需求(resource字段定义),同时指定自己所用的存储底层支持的StorageClass,这样在开发者界面看到的就是“所需资源+置备程序Class名称

L6:市面上没有合适自己产品的PVC置备程序,用户想自己定义一个,用户可以搭建自己的置备程序并按照标准接入kubernetes;其他用户在使用自研的存储置备程序时(自研的置备程序在安装时会创建对应的StorageClass),直接在PVC中指定自研置备程序的storageClassName,同时还可以修改kubernetes默认的置备程序(当用户的PVC中的StorageClass没有定义时生效)

当前项目产品使用的置备程序是rook,回头可以就rook简单写一下流程。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/162389
推荐阅读
相关标签
  

闽ICP备14008679号