kubernetes_PV_PVC

Kubernetes PV & PVC


概念

PV: Persistent Volume,持久化存储数据卷,Pod想要使用的持久化存储的属性,比如存储的大小、读写权限等

PVC: Persistent Volume Claim,是一个具体的Volume的属性,比如Volume类型、挂载目录、远程存储服务器地址等


为什么需要Persistent Volume

所谓容器的Volume,就是将一个宿主机上的目录,跟一个容器里的目录绑定挂载在一起。而所谓的“持久化Volume”,指的就是这个宿主机上的目录,具备“持久性”。就是这个目录里面的内容,既不会因为容器的删除而被清理掉,也不会跟当前的宿主机绑定。这样,当容器被重启或者在其他节点上重建出来之后,它仍然能够通过挂载这个Volume,访问到这些内容。而仅仅通过hostPath和emptyDir类型的Volume无法达到持久化,因为他们既有可能被kubelet清理掉,也不能被“迁移”到其他节点上。因此,大多数情况下,持久化Volume的实现,往往依赖于一个远程存储服务。


为什么还需要Persistent Volume Claim

场景:开发人员想使用Volume但是不知道有什么类型的Volume可以用。

更具体说,作为一个应用开发者,我可能对持久化存储项目一窍不通,也不知道公司的kubernetes集群里到底是怎么搭建的,自然也不会编写它们对应的Volume定义文件。这些关于Volume的管理和远程持久化存储的知识,不仅超越了开发者的知识储备,还会暴露公司基础设施秘密的风险。

apiVersion: v1
kind: Pod
metadata:
	name: rbd
spec:
	containers:
	- image: kubernetes/pause
	  name: rbd-rw
	  volumeMounts:
	  - name: rbdpd
	    mountPath: /mnt/rbd
	volumes:
	- name: rbdpd
	  rbd:
	  monitors:
	  - '10.16.154.78:6789'
	  - '10.16.154.82:6789'
	  - '10.16.154.83:6789'
	  pool: kube
	  image: foo
	  fsType: ext4
	  readOnly: true
	  user: admin
	  keyring: /etc/ceph/keyring
	  imageformat: "2"
	  imagefeatures: "layering"

例如上面这个Ceph RBD类型Volume的Pod。如果不懂得Ceph RBD的使用方法,volumes里面绝大部分参数都是不清楚在干嘛的。另外这个RBD对应的存储服务器的地址、用户名、授权文件的位置,也都被轻易地暴露给了全公司的所有开发人员,“过渡暴露”。

因此,为了降低开发人员使用Volume的门槛,及避免“过渡暴露”,kubernetes提出了PVC,来解耦声明volume和使用volume的动作。


使用PV和PVC

通过分别声明PV和PVC,然后在Pod的yaml声明要用的PVC,完成volume挂载。

PV yaml

声明一个类型为nfs的PV,一个PV yaml定义,主要是定义存储大小,读写权限及存储方式的参数。这里nfs,就是要指定服务器地址,磁盘位置。

PV一般由运维人员声明。

apiVersion: v1
kind: PersistentVolume
metadata:
	name: nfs
spec:
	storageClassName: manual
	capacity:
		storage: 1Gi
		accessModes:
		- ReadWriteMany
	nfs:
		server: 10.244.1.4
		path: "/"
PVC yaml

首先,定义一个PVC,PVC yaml文件主要声明要使用的volume的需求是什么,比如存储空间大小,可读写权限等。

PVC一般由开发人员声明。

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
	name: nfs
spec:
	accessModes:
	- ReadWriteMany
	storageClassName: manual
	resources:
		requests:
			storage: 1Gi

然后,Pod声明使用PVC,在volumes里申明要使用PVC的名字,即persistentVolumeClaim。等这个Pod创建之后,kubelet就会把这个PVC对应的PV,挂载在这个Pod容器内的目录上。

apiVersion: v1
kind: Pod
metadata:
	labels:
	role: web-frontend
spec:
	containers:
	- name: web
	  image: nginx
	  ports:
	  - name: web
	    containerPort: 80
	  volumeMounts:
	  - name: nfs
 	    mountPath: "/usr/share/nginx/html"
	volumes:
	- name: nfs
	  persistentVolumeClaim:
	  	claimName: nfs

PV不满足PVC

在上面的例子中,我们先声明了一个PV,然后再声明一个PVC,这种情况下PVC一定会会找到对应的PV来绑定。然后,有种情况是,开发人员先声明了PVC,创建Pod的时候报错表示没有符合的PV。很明显,运维人员还没有声明PV。

持久化存储控制器

运维人员发现后马上创建一个符合开发人员需求的PV,此时kubernetes会完成PVC和PV的绑定操作,然后启动Pod。

kubernetes能够马上把PVC和PV绑定在一起,是因为在kubernetes中,存在着⼀个专⻔处理持久化存储的控制器,叫作Volume Controller。这个Volume Controller维护着多个控制循环,其中有⼀个循环,扮演的就是撮合PV和PVC的“红娘”的⻆⾊。它的名字叫作PersistentVolumeController。

PersistentVolumeController会不断地查看当前每⼀个PVC,是不是已经处于Bound(已绑定)状态。如果不是,那它就会遍历所有的、可⽤的PV,并尝试将其与这个“单身”的PVC进⾏绑定。这样,Kubernetes就可以保证⽤户提交的每⼀个PVC,只要有合适的PV出现,它就能够很快进⼊绑定状态,从⽽结束“单身”之旅。

StorageClass

在上面的例子中,我们运维人员发现了有PVC不被满足,所以马上创建了一个满足需求的PV。然后,在一个Kubernetes中可能有成千上万的PVC,对运维人员来说是一个很大的工作量。kubernetes提供了一个自动创建PV的机制,为Dynamic Provisioning。相比之前的,则被称为Static Provisioning。

Dynamic Provisioning机制的核心是StorageClass。StorageClass的目的主要是创建PV模版。

storage class yaml文件主要定义PV的属性,比如存储类型,Volume大小等。然后创建PV需要再用到存储插件。比如Ceph等。

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
	name: block-service
provisioner: kubernetes.io/gce-pd
parameters:
	type: pd-ssd

PVC指定要使用的StorageClass,相比前面的PVC yaml的storageClassName为manul,下面的PVC yaml指定了storageClassName。

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
	name: claim1
spec:
	accessModes:
	- ReadWriteOnce
	storageClassName: block-service
	resources:
		requests:
			storage: 30Gi

在PVC创建之后,kubernetes就会通过存储插件创建一个PV,并且这个PV的StorageClass值和PVC的StorageClass的值相同,就是storageClassName相同。


PV持久化实现

kubernetes需要做的就是,使用这些存储服务,来为容器准备一个持久化的宿主机目录,以供将来进行绑定挂载时使用。而所谓“持久化”,指的是容器在这个目录里面写入的文件,都会保存在远程存储中,从而使得这个目录具备了“持久性”。

这个准备“持久化”宿主机目录的过程,分为两步,Attach和Mount。

Attach

这一步主要是为虚拟机挂载远程磁盘。

这一步主要针对Volume类型为远程块存储,比如Google Cloud的Persistent Disk,那么kubelet就需要先调用Google Cloud的API,将它所提供的Persistent Disk挂载到Pod所在的宿主机上。如果Volume类型为远程文件存储,例如NFS,那就会跳过这一步,因为远程文件存储并没有一个“存储设备”需要挂载在宿主机上。

kubernetes中通过AttachDetachController执行Attach操作,不断地检查每一个Pod对应的PV,和这个Pod所在宿主机之间挂载情况。从而决定是否需要对这个PV进行Attach(或者Dettach)操作。这个Controller运行在master节点上。

Mount

Attach完成后,kubelet需要格式化磁盘设备,然后将它挂载到宿主机指定的挂载点上。

kubernetes中通过VolumeManagerReconciler执行Mount操作,是kubelet组件的一部分。它独立运行于kubelet主循环的Goroutine。

相当于执行:

# 通过lsblk命令获取磁盘设备ID
$ sudo lsblk
# 格式化成ext4格式
$ sudo mkfs.ext4 -m 0 -F -E lazy_itable_init=0,lazy_journal_init=0,discard /dev/<磁盘设备ID>
# 挂载到挂载点
$ sudo mkdir -p /var/lib/kubelet/pods/<Pod的ID>/volumes/kubernetes.io~<Volume类型>/<Volume名字>

总结

⽤户提交请求创建pod,Kubernetes发现这个pod声明使⽤了PVC,那就靠PersistentVolumeController帮它找⼀个PV配对。
没有现成的PV,就去找对应的StorageClass帮它新创建⼀个PV或让运维人员创建一个,然后和PVC完成绑定。
新创建的PV,还只是⼀个API 对象,需要经过“两阶段处理”变成宿主机上的“持久化 Volume”才真正有用:
第⼀阶段由运⾏在master上的AttachDetachController负责,为这个PV完成 Attach 操作,为宿主机挂载远程磁盘;
第⼆阶段是运⾏在每个节点上kubelet组件的内部,把第⼀步attach的远程磁盘 mount 到宿主机⽬录。这个控制循环叫VolumeManagerReconciler,运⾏在独⽴的Goroutine,不会阻塞kubelet主循环。
完成这两步,PV对应的“持久化 Volume”就准备好了,POD可以正常启动,将“持久化 Volume”挂载在容器内指定的路径。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值