一个“看不见摸不着”的 Leader

简介: 记录了一次线上 volume provisioner 选举(LeaderElection)失败的问题,对问题进行了模拟场景复现

前言

团队的产品中有一个组件叫做 volume-provisioner,主要实现了 provsioner 的能力:挂载目录,根据 pvc 申请去创建 pv 以及对应的目录。


组件是 Daemonset 资源,通过 LeaderElection 进行选主,实现逻辑也较为简单,主实例根据请求中的目标节点,去 exec 到该节点的实例中,在挂载目录下执行操作。


这样一个稳定跑了三四年的组件,突然一天在某个客户的环境中崩掉了,所有实例卡在选举过程中,导致流水线任务、Addon创建失败,为此研究了一下。


排查过程

集群环境是阿里云托管版,一开始的确怀疑过这个方向,因为 kubernetes 中的选举大概率与 ETCD 脱不了干系,托管版又无法直接看到 Master 组件相关的信息,于是直接从代码下手。

首先来说,所有的实例都卡在选主的过程中,怀疑的一个方向就是已经有人持锁当 leader 了,所以先从选举的方式来看起,抓出这个 leader 来。

选举方式

组件通过这个包实现的:https://github.com/kubernetes-sigs/sig-storage-lib-external-provisioner

从代码中可以看到,选举是通过 endpoints 作为资源锁来进行的,leader 持有锁以后会不断的进行续租。

LeaderElection 同样可以通过 configmap 作为资源锁

image.png

这时候查看 ep 资源,的确有两个与 sc 相关的 endpoint

image.png

查看具体的信息,在 annotaion 中可以看到当前持锁的实例是谁,如下两个字段是主要信息

  • holderIdentity:当前的持锁的实例信息
  • renewTime:最近一次的续租时间
control-plane.alpha.kubernetes.io/leader: '{"holderIdentity":"xxxxxxxxxxx_5928a5b2-968a-42c5-b5b0-85123e027030","leaseDurationSeconds":15,"acquireTime":"2021-12-14T06:05:15Z","renewTime":"2022-02-12T14:29:03Z","leaderTransitions":15}'

这个名称是怎么组成的,继续查看代码,发现由 hostname + _ + uuid  的格式组成

image.png


消失的 Pod

了解了命名规则就好说了,hostname 对于 pod 来说就是 pod 的名称,也就是 uuid 前面这部分就是当前主实例的 pod 名称。可找到你了,当兴奋的去查这个 pod 的时候,发现集群中并没有这个 pod

稍微懵了一下,想到了下一个排查的方向,会不会某个节点上有进程没有退出,一直在参与选举,之后的一个操作让我更加的确信了这个想法。

首先给组件的 ds 增加亲和性,停掉所有的实例,这时候删除两个 ep 资源,马上会创建出新的 ep,并且查看锁持有者仍是那个 Pod,确认了这一点,快速遍历了一下所有节点的进程,奇怪的是并没有发现有残留的进程在 :(


临时解决方法

这时候客户急着用,加上手上还有很多其他工作。就关掉了选举,每个实例通过事件请求中的节点信息与自己的所在的节点是否匹配,来决定是否消费这个事件执行操作。

大概操作如下,如果你也有类似的问题可以临时这样解决掉, 传入 controller.LeaderElection(false) 即可

pc = controller.NewProvisionController(client, config.LocalProvisionerName, lvp, version.GitVersion,
      controller.LeaderElection(false))

可以通过环境变量注入来知道当前 ds 所在的节点信息

- name: NODE_NAME
  valueFrom:    fieldRef:      fieldPath: spec.nodeName


二次排查

问题原因

手里工作宽松后,又继续看起了这个问题,这次找到了一些眉目。进入集群查看 ep 信息,发现锁已经被释放掉了,正是这个关键的锁,解开了疑惑。

可以看到锁是 2月12日申领的,到2月18日是最后的续约时间,与同事确认过,在 2月18日左右客户下线了一部分机器并且对部分机器进行了重启。

image.png

所以之前的怀疑方向没什么太大的问题,就是有残留的进程在不断的持锁。但是为什么当时没有搜到这个进程呢。

其中有个比较值得注意的地方,客户本次下线机器并没有按照我们提供的标准流程去进行,具体的操作已经不得而知了,根据这点,我进行了一种场景的模拟,得到了一样的结果。


场景复原

之前对所有节点的进程进行了排查,并没有发现异常,所以大概率这个进程并不在集群的节点中了。

但是不在集群中的节点 kubelet 会自动的去清理驱逐掉节点上的容器,如果这时候 kubelet 是异常的呢,容器并没有被清理掉,仍然在与 apiserver 进行通信,参与选举,带着这个疑问进行了一个场景复原,具体流程如下。


  1. 首先确认实验环境中持锁的 pod 以及其所在的节点。可以确认的是 zkb5w 这个 POD,在 node132  这个节点

image.pngimage.png

  1. 这时候我们到 132 节点,停止到它的 kubelet。此时查看 ep 发现还是在正常的进行续约。

image.png

  1. 此时从集群中移除掉 node132  这个节点

image.png

  1. 这时候我们再次查看 ep 中锁的持有者,仍然是 zkb5w 这个实例,多次查看,发现仍然在进行续约。此时从集群中已经找不到这个 Pod 了。

image.png


场景到这里基本就完毕了,这只是一种可能性。但是可以确定的是,集群中的实例都停止的情况下,资源锁仍然被持有被续约,是有其他的进程在作祟。这个 “看不见摸不着” 的 Leader 在背后抢占着这一切。

虽然无法查找到当时导致问题的详细步骤了,但是对于 LeaderElection 有了一个新的了解,还是很值得的。

目录
相关文章
|
10月前
|
存储 Kubernetes 前端开发
2023年如何成为一名优秀的大前端Leader?
2023年如何成为一名优秀的大前端Leader?
|
算法 Java 数据处理
不是我吓唬你,写不出这种代码,那就等着被leader开除吧
这种代码,对于我们自己练习编程或者解决一个算法题,当然没有问题。但是如果是在一个工程中,尤其是几十上百人维护了几年的工程中,还使用这种写法,倾泻自己天马行空的才华,保证leader不打死你哦。 所以,对于代码的整洁性,可读性,自古以来就有很多大神做出过总结,比如这本《clean code》,中文名叫做《代码整洁之道》,今天,我们就来看看吧。
|
架构师 数据库
受不了了!是leader都管得这么细么???
每一个设计师背后,都有无数个指点江山的神。
419 0
|
架构师
站在leader的角度思考问题,才有可能成为leader
多站在leader的角度思考问题。
256 1
|
架构师
为什么我就遇不到,手摸手指导我的leader?
把员工讲懂,leader要提高自身的表达能力。
245 0
|
架构师 项目管理
会沟通才可能找到女友 | 新晋leader
如果你的职业规划,就是往专业深度上走,成长为一名专家,如何增大职场成功的概率呢?
257 0
|
消息中间件
6句话说清楚Leader/Follower线程模型
仅仅6句话,如果你弄明白了F/L线程模型。
469 0
|
程序员 Android开发
996:只要能活着就好,不管活得多么糟糕
划重点: 996 是指每天早上 9 点上班,晚上 9 点下班,每周上 6 天班 至于剩下的那天能不能休息,全靠天意 没有家,即使有,也只是个补充睡眠的窝 01、 最近,我这个程序员所在的圈子里发生了一件天大的事。