如何将 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: <none> annotations: <none> 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: <none>
看到“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 中的对象可变性
- 上一篇
- JavaScript 中的对象可变性
- 下一篇
- 我的反应和下一步
-
- Golang · Go教程 | 3小时前 | 接口类型 errors.Is errors.As GolangError ==比较
- Golang错误值比较为何不起作用?
- 147浏览 收藏
-
- Golang · Go教程 | 4小时前 |
- Golangifelse控制结构详解
- 400浏览 收藏
-
- Golang · Go教程 | 4小时前 |
- Golang动态赋值方法全解析
- 332浏览 收藏
-
- Golang · Go教程 | 4小时前 |
- gRPC流控与限速实战方法解析
- 297浏览 收藏
-
- Golang · Go教程 | 5小时前 |
- Golang路由分发实现全解析
- 445浏览 收藏
-
- Golang · Go教程 | 5小时前 |
- Golang享元模式复用技巧解析
- 419浏览 收藏
-
- Golang · Go教程 | 5小时前 |
- Go语言无符号整数溢出问题解析
- 329浏览 收藏
-
- Golang · Go教程 | 5小时前 |
- Golang任务队列与worker池实现详解
- 483浏览 收藏
-
- Golang · Go教程 | 5小时前 | golang 切片排序 sort包 sort.Interface sort.Slice
- Golang切片排序技巧及_sort包使用详解
- 214浏览 收藏
-
- Golang · Go教程 | 5小时前 |
- Golang竞态检测与race工具使用详解
- 262浏览 收藏
-
- Golang · Go教程 | 5小时前 |
- Golang错误处理与并发实战解析
- 432浏览 收藏
-
- Golang · Go教程 | 5小时前 |
- Golangos库文件操作技巧分享
- 440浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- ChatExcel酷表
- ChatExcel酷表是由北京大学团队打造的Excel聊天机器人,用自然语言操控表格,简化数据处理,告别繁琐操作,提升工作效率!适用于学生、上班族及政府人员。
- 3212次使用
-
- Any绘本
- 探索Any绘本(anypicturebook.com/zh),一款开源免费的AI绘本创作工具,基于Google Gemini与Flux AI模型,让您轻松创作个性化绘本。适用于家庭、教育、创作等多种场景,零门槛,高自由度,技术透明,本地可控。
- 3425次使用
-
- 可赞AI
- 可赞AI,AI驱动的办公可视化智能工具,助您轻松实现文本与可视化元素高效转化。无论是智能文档生成、多格式文本解析,还是一键生成专业图表、脑图、知识卡片,可赞AI都能让信息处理更清晰高效。覆盖数据汇报、会议纪要、内容营销等全场景,大幅提升办公效率,降低专业门槛,是您提升工作效率的得力助手。
- 3455次使用
-
- 星月写作
- 星月写作是国内首款聚焦中文网络小说创作的AI辅助工具,解决网文作者从构思到变现的全流程痛点。AI扫榜、专属模板、全链路适配,助力新人快速上手,资深作者效率倍增。
- 4564次使用
-
- MagicLight
- MagicLight.ai是全球首款叙事驱动型AI动画视频创作平台,专注于解决从故事想法到完整动画的全流程痛点。它通过自研AI模型,保障角色、风格、场景高度一致性,让零动画经验者也能高效产出专业级叙事内容。广泛适用于独立创作者、动画工作室、教育机构及企业营销,助您轻松实现创意落地与商业化。
- 3832次使用
-
- Golangmap实践及实现原理解析
- 2022-12-28 505浏览
-
- go和golang的区别解析:帮你选择合适的编程语言
- 2023-12-29 503浏览
-
- 试了下Golang实现try catch的方法
- 2022-12-27 502浏览
-
- 如何在go语言中实现高并发的服务器架构
- 2023-08-27 502浏览
-
- 提升工作效率的Go语言项目开发经验分享
- 2023-11-03 502浏览

