如何将 Kubernetes 支持的领导者选举添加到您的 Go 应用程序中
你在学习Golang相关的知识吗?本文《如何将 Kubernetes 支持的领导者选举添加到您的 Go 应用程序中》,主要介绍的内容就涉及到,如果你想提升自己的开发能力,就不要错过这篇文章,大家要知道编程理论基础和实战操作都是不可或缺的哦!
最初由博客发布
kubernetes 标准库充满了宝石,隐藏在生态系统中的许多不同的子包中。我最近发现了一个这样的例子 k8s.io/client-go/tools/leaderelection,它可用于向 kubernetes 集群内运行的任何应用程序添加领导者选举协议。本文将讨论什么是领导者选举,它是如何在这个 kubernetes 包中实现的,并提供一个示例来说明如何在我们自己的应用程序中使用这个库。
领导人选举
领导者选举是一个分布式系统概念,是高可用软件的核心构建块。它允许多个并发进程相互协调并选举一个“领导者”进程,然后该进程负责执行同步操作,例如写入数据存储。
这在分布式数据库或缓存等系统中非常有用,其中多个进程正在运行以针对硬件或网络故障创建冗余,但无法同时写入存储以确保数据一致性。如果领导者进程在未来某个时刻变得无响应,剩余进程将启动新的领导者选举,最终选择一个新进程作为领导者。
利用这个概念,我们可以创建具有单个领导者和多个备用副本的高可用软件。
在 kubernetes 中,controller-runtime 包使用领导者选举来使控制器具有高可用性。在控制器部署中,仅当进程是领导者并且其他副本处于等待状态时才会发生资源协调。如果leader pod没有响应,剩余的副本将选举一个新的leader来执行后续的协调并恢复正常运行。
kubernetes 租赁
这个库使用 kubernetes lease,或者分布式锁,可以由进程获取。租约是由单一身份在给定期限内持有的原生 kubernetes 资源,并具有续订选项。 这是文档中的示例规范:
apiversion: coordination.k8s.io/v1 kind: lease metadata: labels: apiserver.kubernetes.io/identity: kube-apiserver kubernetes.io/hostname: master-1 name: apiserver-07a5ea9b9b072c4a5f3d1c3702 namespace: kube-system spec: holderidentity: apiserver-07a5ea9b9b072c4a5f3d1c3702_0c8914f7-0f35-440e-8676-7844977d3a05 leasedurationseconds: 3600 renewtime: "2023-07-04t21:58:48.065888z"
k8s 生态系统通过三种方式使用租约:
- 节点心跳:每个节点都有对应的lease资源,并不断更新其renewtime字段。如果 lease 的 renewtime 一段时间没有更新,该 node 将被污染为不可用,并且不会再为其调度 pod。
- leader election:在这种情况下,lease 用于通过让 leader 更新 lease 的holderidentity 来协调多个进程。具有不同身份的备用副本陷入等待租约到期的状态。如果租约确实到期,并且领导者没有续订,则会进行新的选举,其中剩余的副本尝试通过用自己的持有人身份更新其持有者身份来获得租约的所有权。由于 kubernetes api 服务器不允许更新过时的对象,因此只有一个备用节点能够成功更新租约,此时它将作为新的领导者继续执行。
- api 服务器身份:从 v1.26 开始,作为测试功能,每个 kube-apiserver 副本将通过创建专用租约来发布其身份。由于这是一个相对较小的新功能,因此除了运行的 api 服务器数量之外,无法从 lease 对象派生出太多其他内容。但这确实为未来的 k8s 版本中的这些 lease 添加更多元数据留下了空间。
现在让我们通过编写示例程序来探索租赁的第二个用例,以演示如何在领导者选举场景中使用它们。
示例程序
在此代码示例中,我们使用 leaderelection 包来处理领导者选举和租约操作细节。
package main import ( "context" "fmt" "os" "time" "k8s.io/client-go/tools/leaderelection" rl "k8s.io/client-go/tools/leaderelection/resourcelock" ctrl "sigs.k8s.io/controller-runtime" ) var ( // lockname and locknamespace need to be shared across all running instances lockname = "my-lock" locknamespace = "default" // identity is unique to the individual process. this will not work for anything, // outside of a toy example, since processes running in different containers or // computers can share the same pid. identity = fmt.sprintf("%d", os.getpid()) ) func main() { // get the active kubernetes context cfg, err := ctrl.getconfig() if err != nil { panic(err.error()) } // create a new lock. this will be used to create a lease resource in the cluster. l, err := rl.newfromkubeconfig( rl.leasesresourcelock, locknamespace, lockname, rl.resourcelockconfig{ identity: identity, }, cfg, time.second*10, ) if err != nil { panic(err) } // create a new leader election configuration with a 15 second lease duration. // visit https://pkg.go.dev/k8s.io/client-go/tools/leaderelection#leaderelectionconfig // for more information on the leaderelectionconfig struct fields el, err := leaderelection.newleaderelector(leaderelection.leaderelectionconfig{ lock: l, leaseduration: time.second * 15, renewdeadline: time.second * 10, retryperiod: time.second * 2, name: lockname, callbacks: leaderelection.leadercallbacks{ onstartedleading: func(ctx context.context) { println("i am the leader!") }, onstoppedleading: func() { println("i am not the leader anymore!") }, onnewleader: func(identity string) { fmt.printf("the leader is %s\n", identity) }, }, }) if err != nil { panic(err) } // begin the leader election process. this will block. el.run(context.background()) }
leaderelection 包的优点在于它提供了一个基于回调的框架来处理领导者选举。这样,您可以以精细的方式对特定的状态变化采取行动,并在选举新领导者时适当地释放资源。通过在单独的 goroutine 中运行这些回调,该包利用 go 强大的并发支持来有效地利用机器资源。
测试一下
为了测试这一点,让我们使用 kind 启动一个测试集群。
$ kind create cluster
将示例代码复制到 main.go 中,创建一个新模块(go mod init leaderelectiontest)并整理它(go mod tidy)以安装其依赖项。运行 go run main.go 后,您应该看到如下输出:
$ go run main.go i0716 11:43:50.337947 138 leaderelection.go:250] attempting to acquire leader lease default/my-lock... i0716 11:43:50.351264 138 leaderelection.go:260] successfully acquired lease default/my-lock the leader is 138 i am the leader!
确切的领导者身份将与示例(138)中的不同,因为这只是撰写本文时在我的计算机上运行的进程的 pid。
这是在测试集群中创建的租约:
$ kubectl describe lease/my-lock name: my-lock namespace: default labels:annotations: api version: coordination.k8s.io/v1 kind: lease metadata: creation timestamp: 2024-07-16t15:43:50z resource version: 613 uid: 1d978362-69c5-43e9-af13-7b319dd452a6 spec: acquire time: 2024-07-16t15:43:50.338049z holder identity: 138 lease duration seconds: 15 lease transitions: 0 renew time: 2024-07-16t15:45:31.122956z events:
看到“holder identity”与进程的pid相同,138。
现在,让我们打开另一个终端并在单独的进程中运行相同的 main.go 文件:
$ go run main.go i0716 11:48:34.489953 604 leaderelection.go:250] attempting to acquire leader lease default/my-lock... the leader is 138
第二个进程将永远等待,直到第一个进程没有响应。让我们终止第一个进程并等待大约 15 秒。现在,第一个进程不再更新其对租约的声明,因此 .spec.renewtime 字段将不再更新。这最终将导致第二个进程触发新的领导者选举,因为租约的更新时间早于其持续时间。因为这个进程是唯一正在运行的进程,所以它将选举自己作为新的领导者。
the leader is 604 I0716 11:48:51.904732 604 leaderelection.go:260] successfully acquired lease default/my-lock I am the leader!
如果初始 leader 退出后还有多个进程仍在运行,则第一个获得 lease 的进程将成为新的 leader,其余进程继续处于待命状态。
没有单一领导者的保证
这个包并不是万无一失的,因为它“不能保证只有一个客户端充当领导者(又名击剑)”。例如,如果领导者暂停并让其租约到期,则另一个备用副本将获取租约。然后,一旦原来的领导者恢复执行,它就会认为自己仍然是领导者,并继续与新当选的领导者一起工作。这样,你最终可以有两个领导者同时运行。
要解决此问题,需要在向服务器发出的每个请求中包含引用租约的隔离令牌。隔离令牌实际上是一个整数,每次租约易手时该整数就会增加 1。因此,具有旧防护令牌的客户端的请求将被服务器拒绝。在这种情况下,如果旧领导者从睡眠中醒来,并且新领导者已经增加了防护令牌,则旧领导者的所有请求都将被拒绝,因为它发送的令牌比服务器从服务器看到的令牌更旧(更小)。新领导者。
如果不修改核心 api 服务器来考虑每个 lease 的相应 fencing 令牌,那么在 kubernetes 中实现 fencing 将会很困难。然而,k8s api 服务器本身在一定程度上减轻了拥有多个领导者控制器的风险。由于对过时对象的更新会被拒绝,因此只有拥有最新版本对象的控制器才能修改它。因此,虽然我们可以运行多个控制器领导者,但如果一个控制器错过了另一个领导者所做的更改,资源的状态将永远不会回归到旧版本。相反,协调时间将会增加,因为两位领导者都需要刷新自己的内部资源状态,以确保他们正在执行最新版本。
不过,如果您使用此包使用不同的数据存储来实现领导者选举,这是一个需要注意的重要警告。
结论
领导者选举和分布式锁定是分布式系统的关键构建块。当尝试构建容错和高可用性的应用程序时,拥有此类工具至关重要。 kubernetes 标准库为我们提供了一个经过实战检验的原语包装器,允许应用程序开发人员轻松地将领导者选举构建到他们自己的应用程序中。
虽然这个特定库的使用确实限制了您在 kubernetes 上部署应用程序,但这似乎是最近世界的发展方向。如果事实上这是一个破坏者,您当然可以分叉该库并修改它以适用于任何符合 acid 且高度可用的数据存储。
请继续关注更多 k8s 源码深入研究!
今天带大家了解了的相关知识,希望对你有所帮助;关于Golang的技术知识我们会一点点深入介绍,欢迎大家关注golang学习网公众号,一起学习编程~

- 上一篇
- JavaScript 中的对象可变性

- 下一篇
- 我的反应和下一步
-
- Golang · Go教程 | 2小时前 |
- Debian下Tomcat备份恢复攻略
- 197浏览 收藏
-
- Golang · Go教程 | 5小时前 |
- Flutter在Debian官方支持揭秘
- 338浏览 收藏
-
- Golang · Go教程 | 6小时前 |
- Debian下Dumpcap流量整形实用指南
- 370浏览 收藏
-
- Golang · Go教程 | 7小时前 |
- DebianSyslog提升系统安全性指南
- 338浏览 收藏
-
- Golang · Go教程 | 7小时前 |
- Debian上Apache2的SEO优化配置指南
- 370浏览 收藏
-
- Golang · Go教程 | 7小时前 |
- Debian上Hadoop日志管理实用技巧
- 268浏览 收藏
-
- Golang · Go教程 | 18小时前 |
- Go语言time.Ticker与time.After使用差异及问题详解
- 103浏览 收藏
-
- Golang · Go教程 | 18小时前 |
- DebianSyslog在容器技术中的应用实战
- 186浏览 收藏
-
- Golang · Go教程 | 21小时前 |
- Debian系统FlutterSDK安装详细指南
- 380浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 542次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 508次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 497次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 484次学习
-
- AI Make Song
- AI Make Song是一款革命性的AI音乐生成平台,提供文本和歌词转音乐的双模式输入,支持多语言及商业友好版权体系。无论你是音乐爱好者、内容创作者还是广告从业者,都能在这里实现“用文字创造音乐”的梦想。平台已生成超百万首原创音乐,覆盖全球20个国家,用户满意度高达95%。
- 10次使用
-
- SongGenerator
- 探索SongGenerator.io,零门槛、全免费的AI音乐生成器。无需注册,通过简单文本输入即可生成多风格音乐,适用于内容创作者、音乐爱好者和教育工作者。日均生成量超10万次,全球50国家用户信赖。
- 9次使用
-
- BeArt AI换脸
- 探索BeArt AI换脸工具,免费在线使用,无需下载软件,即可对照片、视频和GIF进行高质量换脸。体验快速、流畅、无水印的换脸效果,适用于娱乐创作、影视制作、广告营销等多种场景。
- 8次使用
-
- 协启动
- SEO摘要协启动(XieQiDong Chatbot)是由深圳协启动传媒有限公司运营的AI智能服务平台,提供多模型支持的对话服务、文档处理和图像生成工具,旨在提升用户内容创作与信息处理效率。平台支持订阅制付费,适合个人及企业用户,满足日常聊天、文案生成、学习辅助等需求。
- 13次使用
-
- Brev AI
- 探索Brev AI,一个无需注册即可免费使用的AI音乐创作平台,提供多功能工具如音乐生成、去人声、歌词创作等,适用于内容创作、商业配乐和个人创作,满足您的音乐需求。
- 14次使用
-
- Golangmap实践及实现原理解析
- 2022-12-28 505浏览
-
- 试了下Golang实现try catch的方法
- 2022-12-27 502浏览
-
- Go语言中Slice常见陷阱与避免方法详解
- 2023-02-25 501浏览
-
- Golang中for循环遍历避坑指南
- 2023-05-12 501浏览
-
- Go语言中的RPC框架原理与应用
- 2023-06-01 501浏览