Kubernetes attach/detach controller逻辑漏洞致使pod启动失败该怎么办

发布时间:2021-12-01 16:31:42 作者:柒染
来源:亿速云 阅读:154

这期内容当中小编将会给大家带来有关Kubernetes attach/detach controller逻辑漏洞致使pod启动失败该怎么办,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。

前言

通过深入学习k8s attach/detach controller源码,了解现网案例发现的attach/detach controller bug发生的原委,并给出解决方案。


现网案例现象

我们首先了解下现网案例的问题和现象;然后去深入理解ad controller维护的数据结构;之后根据数据结构与ad controller的代码逻辑,再来详细分析现网案例出现的原因和解决方案。从而深入理解整个ad controller。

问题描述
现象

Kubernetes attach/detach controller逻辑漏洞致使pod启动失败该怎么办

Kubernetes attach/detach controller逻辑漏洞致使pod启动失败该怎么办

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。每个组件分工明确:

Kubernetes attach/detach controller逻辑漏洞致使pod启动失败该怎么办

控制器模式是k8s非常重要的概念,一般一个controller会去管理一个或多个API对象,以让对象从实际状态/当前状态趋近于期望状态。

所以attach/detach controller的作用其实就是去attach期望被attach的volume,detach期望被detach的volume。

后续attach/detach controller简称ad controller。

ad controller数据结构

对于ad controller来说,理解了其内部的数据结构,再去理解逻辑就事半功倍。ad controller在内存中维护2个数据结构:

  1. actualStateOfWorld —— 表征实际状态(后面简称asw)

  2. desiredStateOfWorld —— 表征期望状态(后面简称dsw)

很明显,对于声明式API来说,是需要随时比对实际状态和期望状态的,所以ad controller中就用了2个数据结构来分别表征实际状态和期望状态。

actualStateOfWorld

actualStateOfWorld 包含2个map:

attachedVolumes

如何填充数据?

1、在启动ad controller时,会populate asw,此时会list集群内所有node对象,然后用这些node对象的node.Status.VolumesAttached 去填充attachedVolumes

2、之后只要有需要attach的volume被成功attach了,就会调用MarkVolumeAsAttachedGenerateAttachVolumeFunc 中)来填充到attachedVolumes中

如何删除数据?

1、只有在volume被detach成功后,才会把相关的volume从attachedVolumes中删掉。(GenerateDetachVolumeFunc 中调用MarkVolumeDetached)

nodesToUpdateStatusFor

如何填充数据?

1、detach volume失败后,将volume add back到nodesToUpdateStatusFor

- GenerateDetachVolumeFunc 中调用AddVolumeToReportAsAttached

如何删除数据?

1、在detach volume之前会先调用RemoveVolumeFromReportAsAttachednodesToUpdateStatusFor中先删除该volume相关信息

desiredStateOfWorld

desiredStateOfWorld 中维护了一个map:

nodesManaged:包含被ad controller管理的nodes,以及期望attach到这些node上的volumes。

nodesManaged

如何填充数据?

1、在启动ad controller时,会populate asw,list集群内所有node对象,然后把由ad controller管理的node填充到nodesManaged

2、ad controller的nodeInformer watch到node有更新也会把node填充到nodesManaged

3、另外在populate dsw和podInformer watch到pod有变化(add, update)时,往nodesManaged 中填充volume和pod的信息

4、desiredStateOfWorldPopulator 中也会周期性地去找出需要被add的pod,此时也会把相应的volume和pod填充到nodesManaged

如何删除数据?

1、当删除node时,ad controller中的nodeInformer watch到变化会从dsw的nodesManaged 中删除相应的node

2、当ad controller中的podInformer watch到pod的删除时,会从nodesManaged 中删除相应的volume和pod

3、desiredStateOfWorldPopulator 中也会周期性地去找出需要被删除的pod,此时也会从nodesManaged 中删除相应的volume和pod

ad controller流程简述

ad controller的逻辑比较简单:

1、首先,list集群内所有的node和pod,来populate actualStateOfWorld (attachedVolumes )和desiredStateOfWorld (nodesManaged)

2、然后,单独开个goroutine运行reconciler,通过触发attach, detach操作周期性地去reconcile asw(实际状态)和dws(期望状态)

3、之后,又单独开个goroutine运行DesiredStateOfWorldPopulator ,定期去验证dsw中的pods是否依然存在,如果不存在就从dsw中删除

现网案例

接下来结合上面所说的现网案例,来详细看看reconciler的逻辑。

案例初步分析

很明显,cbs要能被pod成功使用,需要ad controller和volume manager的协同工作。所以这个问题的定位首先要明确:

  1. volume manager为什么认为volume没有按照node状态挂载,ad controller却认为volume attch成功了?

  2. volumesAttachedvolumesInUse 在ad controller和kubelet之间充当什么角色?

这里只对分析volume manager做简要分析。

所以接下来主要需要看为什么ad controller那边没有更新node.Status.VolumesAttached

ad controller的reconciler详解

接下来详细分析下ad controller的逻辑,看看为什么会没有更新node.Status.VolumesAttached,但从事件看ad controller却又认为volume已经挂载成功。

从流程简述中表述可见,ad controller主要逻辑是在reconciler中。

案例详细分析
  1. 首先,删除pod时,由于某种原因cbs detach失败,失败后就会backoff重试。

    1. 由于detach失败,该volume也不会从asw的attachedVolumes中删除

  2. 由于detach时,

    1. 先从node.status.VolumesAttached中删除volume,之后才去执行detach

    2. detach时返回backoffError不会把该volumeadd back node.status.VolumesAttached

  3. 之后,我们在backoff周期中(假如就为第一个周期的500ms中间)再次创建sts,pod被调度到之前的node

  4. 而pod一旦被创建,就会被添加到dsw的nodesManaged(nodeName和volumeName都没变)

  5. reconcile()中的第2步,会去判断volume是否被attach,此时发现该volume同时存在于asw和dws中,并且由于detach失败,也会在检测时发现还是attach,从而设置attachedConfirmed为true

  6. ad controller就认为该volume被attach成功了

  7. reconcile()中第1步的detach逻辑进行判断时,发现要detach的volume已经存在于dsw.nodesManaged了(由于nodeName和volumeName都没变),这样volume同时存在于asw和dsw中了,实际状态和期望状态一致,被认为就不需要进行detach了。

  8. 这样,该volume之后就再也不会被add back到node.status.VolumesAttached。所以就出现了现象中的node info中没有该volume,而ad controller又认为该volume被attach成功了

  9. 由于kubelet(volume manager)与controller manager是异步的,而它们之间交互是依据node.status.VolumesAttached ,所以volume manager在验证volume是否attach成功,发现node.status.VolumesAttached中没有这个voume,也就认为没有attach成功,所以就有了现象中的报错Volume not attached according to node status

  10. 之后kubelet的syncPod在等待pod所有的volume attach和mount成功时,就超时了(现象中的另一个报错timeout expired wating...)。

  11. 所以pod一直处于ContainerCreating

小结

总结

上述就是小编为大家分享的Kubernetes attach/detach controller逻辑漏洞致使pod启动失败该怎么办了,如果刚好有类似的疑惑,不妨参照上述分析进行理解。如果想知道更多相关知识,欢迎关注亿速云行业资讯频道。

推荐阅读:
  1. rancher中kubernetes之如何构建标准化vmware镜像
  2. 容器化 RDS:借助 CSI 扩展 Kubernetes 存储能力

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

kubernetes

上一篇:Java 语言中的IO系统怎么使用

下一篇:Mysql注入如何写Shell读文件

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》