Kubernetes源码分析之存储相关

本节全部的代码基于1.13.4版本。缓存

前言

在kubernetes中,与存储相关的controller主要由三种:
一、AttachDetachController,简称AD Controller,主要处理真实的与volume相关的操做;
二、PersistentVolumeBinderController,其实就是PV Controller,主要负责pv和pvc的生命周期以及状态的切换;
三、VolumeExpandController,主要负责volume的扩容操做。
oop

PersistentVolumeBinderController

首先追踪PersistentVolumeBinderController方法,直接进入其Run方法。 插件

很直观,依赖于三个goroutine:
一、resync;
二、volumeWorker;
三、claimWorker。

resync

进入resync,代码很简单,以下: code

resync的主要做用就是不停获取pvc和pv的信息,传入到相应的缓存队列中去。这两个队列就是在volumeWorker和claimWorker用到的数据源的信息。

volumeWorker

volumeWorker经过for循环,不停获取resync缓冲的队列信息,对pv,即volume作相应的更新操做。主要实现方法updateVolume cdn

进入 updateVolume方法,主要调用 syncVolume方法,这个方法是整个volumeWorker的核心。工做流程以下:
一、若是volume没有被使用,更新PV的状态为 Available
二、volume已经被pvc持有:

  • 若是volume尚未被绑定到pvc上,更新PV状态为Available
  • 若是pvc信息为空,pv的状态不为Released且不为Failed,更新PV状态为Released,按照配置的回收策略执行pv的回收(调用reclaimVolume方法);
  • pvc中指定volume的字段和当前volume一致,更新PV状态为Bound
  • 若是都不知足,根据状态判断是执行回收策略仍是解绑(unbindVolume)操做。

claimWorker

claimWorker的工做流程和volumeWorker相似,核心调用方法为updateClaim-->syncClaim,主要处理的是pvc生命周期中的各类状态:Pending、Bound以及Lost。不作过多赘述。
blog

总结

PersistentVolumeBinderController的执行流程很清晰,依赖三个goroutine的协做,分别处理数据的获取、pv的生命周期的状态更新和pvc的生命周期的状态更新。整个逻辑中,没有对具体的volume作操做,更新的仅仅是kubernetes中定义的pv和pvc资源的信息,说白了就是etcd中的数据。具体干活的主要仍是AttachDetachController,即AD Controller。接口

AttachDetachController

首先由Run方法进入AD Controller的启动方法,以下: 生命周期

主要有如下几个步骤构成启动步骤:
一、同步各资源的信息,包括Pod、Node、PV、PVC;
二、调用 populateActualStateOfWorld方法获取Node上Volume的信息;
三、调用 populateDesiredStateOfWorld方法获取Pod须要对应的Volume信息;
四、 reconciler.Run负责检查挂载状态,判断是否须要挂载或卸载(真正干活的);
五、 desiredStateOfWorldPopulator.Run同步Pod与Volume的挂载信息,相应信息输送给 reconciler.Run使用;
六、 pvcWorker控制pvc的流控;
七、相应的信息注册到 metrics中,供Prometheus采集数据使用。

populateActualStateOfWorld

populateActualStateOfWorld方法主要处理的是Node与Volume之间的关系,主要做用是将Node Volume当前的状态存入到actualStateOfWorld中。主要方法以下: 队列

主要步骤以下:
一、获取全部的Node信息;
二、一一遍历获取到的全部的Node,针对Node上已经 attached的Volume,分别置于已经attached状态和 in-user状态,将Volume信息添加到 actualStateOfWorld中,并将Node添加到 desiredStateOfWorld中。 actualStateOfWorlddesiredStateOfWorld的数据会在 reconciler.Run使用。

populateDesiredStateOfWorld

populateDesiredStateOfWorld方法主要处理的是Pod与Volume之间的关系,主要做用是将Pod Volume指望的状态添加到desiredStateOfWorld中去。和populateActualStateOfWorld相似,主要就是针对Volume作标记操做,并将相应的Pod信息缓存到desiredStateOfWorld中或者从desiredStateOfWorld中剔除不匹配的Pod信息。事件

desiredStateOfWorldPopulator.Run

desiredStateOfWorldPopulator.Run方法经过不停的循环,调用findAndAddActivePods方法,经过获取全部的Pod,判断是否须要添加到desiredStateOfWorld中去。

reconciler.Run

前面几步主要的目的是为了获取Node Volume和Pod Volume的状态。其中,Node上的Volume是已经存在的,故称做为actualStateOfWorld,而Pod Volume是最终须要生效的资源,故称之为desiredStateOfWorldreconciler.Run的做用就是经过不停获取actualStateOfWorlddesiredStateOfWorld状态,将Pod与Volume置于相对应的状态,保证磁盘的最终挂载成功或者卸载成功。主要方法以下:

不停循环调用 reconciliationLoopFunc方法。
首先进入 reconcile方法,这是真正干活的地方。
reconcile使用了三个大的for循环,处理三类事件:
一、首先剔除须要解绑的Volume,调用 UnmountVolume方法最终调用后台存储的解绑接口;
二、将须要Attach或者Mount的volumes调用后台存储接口执行Attach或者Mount操做;
三、将须要Detach或者Unmount的devices调用后台存储接口执行Detach或者Unmount操做。
其中,Attach操做指的是将Volume在Node上生成卷标,如常见的 /dev/xx等。Mount操做包含了MountDevice和Mount两部分,其中,MountDevice将生成的卷标挂载成Node的路径,通常在 /var/lib/kubelet/xx/kubernetes.io/xx下,依赖于不一样的存储,Mount最终将MountDevice生成的路径和Pod须要使用的路径Mount起来,通常路径为 /var/lib/kubelet/pods/xx/volumes/xx
sync方法主要完成Volume的后续操做。若是Volume未被成功绑定,将Volume进行重建或者解绑操做。

ExpandController

Kubernetes在1.8开始支持卷的扩容操做,1.11功能已经处于Beta阶段。主要代码以下:

pvcPopulator.Run监听PVC的变化,只要PVC中Request字段的Storage值比Status中的大,即表示PVC容量发生了变化,须要扩容。此时,将相应的PV和PVC的信息缓存到 resizeMap中去。以下:
syncResize则是不停获取 resizeMap中的数据,若是有变化,则调用 ExpandVolume方法生成扩展动做,完成磁盘的扩容和PV、PVC的状态更新操做。代码以下:

总结

Kubernetes的存储主要针对Node、Pod、PV以及PVC四类资源。经过获取Node上Volume状态,将其与Pod中的Volume进行绑定,完成卷的加载。最终的绑定或者解绑等操做依赖的是后台的存储,包括内置的开源存储插件或者本身实现的插件(FlexVolume或者CSI)。
在kubelet中,同时存在VolumeManager去管理其节点上的Volume资源信息,基本功能与AD Controller一致。能够经过kube-controller-manager的--disable-attach-detach-reconcile-sync参数或者kubelet的--enable-controller-attach-detach参数控制是由kube-controller-manager执行volume的attach/detach操做仍是kubelet执行相应的操做。

相关文章
相关标签/搜索