kubernetes

【k8s】底层逻辑:K8S选主实现

2023-05-20  本文已影响0人  Bogon

底层逻辑: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·

上一篇 下一篇

猜你喜欢

热点阅读