问题场景
多个 pod 里有定时任务,怎么避免重复执行,才比较好?
DIY
假定,为了解决这个问题,多 pod 之间需要进行通信。
在上述假定下,按照是否有一个单点协调通信,就可以分出两类方法:一类有这单点,一类没有。
如果有单点,那问题就变成,用什么单点,于是,容易得到答案:
- redis
- mysql
- etcd
- zookeeper
- k8s 的一些特性(这其实最后也是基于 etcd 的)
- ……
如果没有单点,那么,解决问题所需要的通信,就落在 pod 身上,那就得考虑各种节点间的通信方式:
- raft ……
人家是怎么解决的?
Simple leader election with Kubernetes and Docker提到,用 k8s endpoint 的 ResourceVersions 和 Annotations 属性来做 leader election 。(按照上面的分类,这其实是使用 k8s 的单点方法。)
注意到这是一个很老的文章。它提到了一个PR,可以看到人家是怎么实现的。这 PR 的 repo 已经 retired。那是不是说,这里所说的方法,就不能用了呢?并不是,这 PR 其实使用了 "k8s.io/kubernetes/pkg/client/leaderelection"这个包。在新版本的 k8s 中,leaderelection 位于这里,应该是还在被维护着的。
leaderelection 对应的 go package 文档在这里。它在 overview 中有一些关于局限性的说明,让人想到魔鬼都住在细节中。另外,目前这 leaderelection 是处于 alpha 阶段的 API。
另外,Simple leader election with Kubernetes and Docker一文也提到了如何在应用程序中方便地使用 leader selection: 可以把 leader selection 做到 side car 中,暴露出 http 接口,应用服务访问这个接口来获取 leader 信息。
从 leaderelection 源码 中可以看到,它还有个 NewLeaderHealthzAdaptor ,能够把健康状态整合到 leader election 里面。(不过,如果使用 side car 方式,这会引入循环依赖?不过这应该是小问题。)
另外,从源码中可以看到,经过这些年, leaderelection 的实现机制,变得更加丰富。除了 endpoint , 它还可以依托于 configmap、 lease 和“锁的组合”,见这里。不过,下层实现仍然主要是 Annotations。
Deep dive into Kubernetes Simple Leader Election 对 Simple leader election with Kubernetes and Docker 进行了解说。
Leader Election inside Kubernetes 一文展示了 leaderelection 的使用。
也有人基于 leaderelection 做出了库, 但是 star 很少。
小结
在 k8s 中,可以使用leaderelection 包做 leader election 。