前言
本文主要通过深入学习k8s attach/detach controller源码,了解现网案例发现的attach/detach controller bug发生的原委,并给出解决方案。
看完本文你也将学习到:
- attach/detach controller的主要数据结构有哪些,保存什么数据,数据从哪来,到哪去等等;
- k8s attach/detach volume的详细流程,如何判断volume是否需要attach/detach,attach/detach controller和kubelet(volume manager)如何协同工作等等。
现网案例现象
我们首先了解下现网案例的问题和现象;然后去深入理解ad controller维护的数据结构;之后根据数据结构与ad controller的代码逻辑,再来详细分析现网案例出现的原因和解决方案。从而深入理解整个ad controller。
问题描述
- 一个statefulsets(sts)引用了多个pvc cbs,我们更新sts时,删除旧pod,创建新pod,此时如果删除旧pod时cbs detach失败,且创建的新pod调度到和旧pod相同的节点,就可能会让这些pod一直处于
ContainerCreating
。
现象
kubectl describe pod
- kubelet log
kubectl get node xxx -oyaml
的volumesAttached
和volumesInUse
volumesAttached:
- devicePath: /dev/disk/by-id/virtio-disk-6w87j3wv
name: kubernetes.io/qcloud-cbs/disk-6w87j3wv
volumesInUse:
- kubernetes.io/qcloud-cbs/disk-6w87j3wv
- kubernetes.io/qcloud-cbs/disk-7bfqsft5
k8s存储简述
k8s中attach/detach controller负责存储插件的attach/detach。本文结合现网出现的一个案例来分析ad controller的源码逻辑,该案例是因k8s的ad controller bug导致的pod创建失败。
k8s中涉及存储的组件主要有:attach/detach controller、pv controller、volume manager、volume plugins、scheduler。每个组件分工明确:
- attach/detach controller:负责对volume进行attach/detach
- pv controller:负责处理pv/pvc对象,包括pv的provision/delete(cbs intree的provisioner设计成了external provisioner,独立的cbs-provisioner来负责cbs pv的provision/delete)
- volume manager:主要负责对volume进行mount/unmount
- volume plugins:包含k8s原生的和各厂商的的存储插件
- 原生的包括:emptydir、hostpath、flexvolume、csi等
- 各厂商的包括:aws-ebs、azure、我们的cbs等
- scheduler:涉及到volume的调度。比如对ebs、csi等的单node最大可attach磁盘数量的predicate策略
控制器模式是k8s非常重要的概念,一般一个controller会去管理一个或多个API对象,以让对象从实际状态/当前状态趋近于期望状态。
所以attach/detach controller的作用其实就是去attach期望被attach的volume,detach期望被detach的volume。
后续attach/detach controller简称ad controller。
ad controller数据结构
对于ad controller来说,理解了其内部的数据结构,再去理解逻辑就事半功倍。ad controller在内存中维护2个数据结构:
actualStateOfWorld
—— 表征实际状态(后面简称asw)desiredStateOfWorld
—— 表征期望状态(后面简称dsw)
很明显,对于声明式API来说,是需要随时比对实际状态和期望状态的,所以ad controller