【k8s】底层逻辑:K8S选主实现
底层逻辑:K8S选主实现
client-go中的leaderelection支持5种类型的资源锁:
const (
LeaderElectionRecordAnnotationKey = "control-plane.alpha.kubernetes.io/leader"
EndpointsResourceLock = "endpoints"
ConfigMapsResourceLock = "configmaps"
LeasesResourceLock = "leases"
EndpointsLeasesResourceLock = "endpointsleases"
ConfigMapsLeasesResourceLock = "configmapsleases"
)
这 5 种资源锁也是随着时间发展不断完善的。
早期版本的 client-go 只支持使用 Endpoints 和 ConfigMaps 作为资源锁。
由于 Endpoints 和 ConfigMaps 本身需要被集群内多个组件监听,使用这两种类型资源作为选主锁会显着增加监听他们的组件的事件数,如 Kube-Proxy。
这个问题在社区也被多次讨论。
为了解决这个问题,社区新增了 Leases 类型的资源锁。
对于之前已经存在使用 Endpoints/ConfigMaps 作为选主资源锁的组件,如 kube-scheduler,kube-controller-manajer 等,社区也提出了一个保证稳定性的迁移方案:Migrate all uses of leader-election to use Lease API
也就是说,在阶段的过渡期,需要同时获取 Endpoints/Configmap 和 Lease 两种类型的资源锁(MultiLock),任一资源锁的丢失都会导致组件的重启。
当更新锁时,先更新 Endpoints/Configmap,再更新 Lease。
在判断丢失时,如果两种资源都有 holder 但是不一致,则返回异常,重新选主。
$ kubectl get nodes -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
k8s-master01 Ready master 186d v1.17.9 192.168.32.118 <none> CentOS Linux 7 (Core) 3.10.0-957.el7.x86_64 docker://18.9.3
k8s-master02 Ready master 186d v1.17.9 192.168.32.184 <none> CentOS Linux 7 (Core) 3.10.0-957.el7.x86_64 docker://18.9.3
k8s-master03 Ready master 186d v1.17.9 192.168.32.120 <none> CentOS Linux 7 (Core) 3.10.0-957.el7.x86_64 docker://18.9.3
k8s-node01 Ready node 186d v1.17.9 192.168.32.250 <none> CentOS Linux 7 (Core) 3.10.0-957.el7.x86_64 docker://18.9.3
k8s-node02 Ready node 186d v1.17.9 192.168.32.226 <none> CentOS Linux 7 (Core) 3.10.0-957.el7.x86_64 docker://18.9.3
# kubectl describe endpoints -n kube-system kube-scheduler
Name: kube-scheduler
Namespace: kube-system
Labels: component=kube-scheduler
k8s-app=kube-scheduler
Annotations: control-plane.alpha.kubernetes.io/leader:
{"holderIdentity":"k8s-master02_216f9c60-02b5-4e8c-ada1-e4a4f307fc94","leaseDurationSeconds":15,"acquireTime":"2022-12-05T17:22:54Z","renew...
Subsets:
Addresses: 192.168.32.118,192.168.32.120,192.168.32.184
NotReadyAddresses: <none>
Ports:
Name Port Protocol
---- ---- --------
http-metrics 10251 TCP
Events: <none>
# kubectl describe endpoints -n kube-system kube-controller-manager
Name: kube-controller-manager
Namespace: kube-system
Labels: component=kube-controller-manager
k8s-app=kube-controller-manager
service.kubernetes.io/headless=
Annotations: control-plane.alpha.kubernetes.io/leader:
{"holderIdentity":"k8s-master02_7a9bfa6b-fde8-4f08-aab0-377c686cc9c9","leaseDurationSeconds":15,"acquireTime":"2023-05-06T10:14:30Z","renew...
Subsets:
Addresses: 192.168.32.118,192.168.32.120,192.168.32.184
NotReadyAddresses: <none>
Ports:
Name Port Protocol
---- ---- --------
http-metrics 10252 TCP
Events: <none>
# kubectl get leases -n kube-system
NAME HOLDER AGE
kube-controller-manager k8s-master02_7a9bfa6b-fde8-4f08-aab0-377c686cc9c9 441d
kube-scheduler k8s-master02_216f9c60-02b5-4e8c-ada1-e4a4f307fc94 441d
# etcdctl endpoint status -w table
+-------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| ENDPOINT | ID | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS |
+-------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| 192.168.32.118:2379 | 6e09d29c207ffc94 | 3.4.3 | 75 MB | false | false | 31 | 275734053 | 275734053 | |
| 192.168.32.184:2379 | b04d0e2fbb23fcb9 | 3.4.3 | 75 MB | false | false | 31 | 275734053 | 275734053 | |
| 192.168.32.120:2379 | 711b911203cfba91 | 3.4.3 | 75 MB | true | false | 31 | 275734053 | 275734053 | |
+-------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
image.png
在第二阶段,可以移除 Endpoints/Configmap 的资源锁,完成向 Lease 资源锁的迁移。
为了支持该迁移方案,社区在 1.17 版本新增了 EndpointsLeasesResourceLock 和 ConfigMapsLeasesResourceLock,完成过渡期的锁获取。
没有 svc 的 endpoints 通过 leader 创建的。
同时,在 1.17 版本中,将 controller-manager 和 scheduler 的资源锁从 Endpoints 切换成 EndpointsLeases。
在 1.20 版本中,将 controller-manager 和 scheduler 的资源锁从 EndpointsLeases 切换成 Leases。
而在 1.24 版本,社区也彻底移除了对 Endpoints/ConfigMaps 作为选主资源锁的支持。
综上,社区整体的趋势是使用 Leases 类型替代原先 Endpoints/Configmaps 作为资源锁的方式。
而对于在低版本下使用 Endpoints/Configmaps 作为选主实现的 K8S,很多组件也采取了不处理这些选主Endpoints/Configmaps 的方式,以屏蔽频繁的 Endpoints 更新带来的事件处理开销。
因此,对于需要选主的组件,可以采取如下方式来规避:使用 Leases Object 作为选主资源锁,这也符合社区的演进趋势; 对着这个组件(原生调度器),配置 resourceLock 类型就行。
参考
底层逻辑:K8S选主实现
https://z.itpub.net/article/detail/6A9B0A3B07E4D9E91F2ADBCD1B276739
https://edwardesire.com/posts/crash-into-endpoints-between-cni-in-k8s/
Kubernetes高可用部署下组件选主的机制分析
https://www.jianshu.com/p/3c209e33bcc8·