4. Leader Election 原理:endpoint/lease 对象、选举算法、leader 任期与心跳
Kubernetes 控制面高可用的核心机制是 Leader Election(领导者选举)。控制器管理器(kube-controller-manager)和调度器(kube-scheduler)作为有状态服务,同一时刻只能有一个活跃实例执行实际的控制逻辑,其余实例处于热备状态。Leader Election 确保在 Leader 故障时,备机能够快速接管,且不会出现多个 Leader 同时工作的“脑裂”场景。
4.1 选举载体:Endpoint 与 Lease 对象
Leader Election 依赖存储在 etcd 中的 API 对象作为“锁”。历史上 Kubernetes 使用 Endpoint 对象,从 v1.14 开始引入更轻量的 Lease 对象(coordination.k8s.io/v1),目前两者并存,但 Lease 已成为默认和推荐方式。
| 特性 | Endpoint 锁 | Lease 锁 |
|---|---|---|
| API 组 | v1(核心) |
coordination.k8s.io/v1 |
| 资源名称 | kube-controller-manager |
kube-controller-manager |
| 命名空间 | kube-system |
kube-system |
| 存储内容 | Annotations + Endpoint 地址 | 专用字段(holderIdentity, leaseDurationSeconds, acquireTime, renewTime, leaseTransitions) |
| 更新开销 | 较大(整个 Endpoint 对象) | 较小(仅 Lease 对象) |
| 推荐程度 | 兼容旧版本 | 默认(v1.14+) |
--leader-elect-resource-lock=endpoints 参数显式指定。
4.2 选举算法:基于租约的抢占式选举
Kubernetes 的 Leader Election 采用 基于租约(Lease-based)的抢占式算法,并非 Paxos 或 Raft。其核心思想是:所有候选者尝试更新同一个 Lease 对象,成功更新者成为 Leader,并定期续约;其他候选者通过观察 Lease 的更新时间来判断 Leader 是否存活。
选举流程如下:
- 初始化: 每个控制器管理器实例启动时,生成唯一的身份标识(
identity),通常为<hostname>_<random-string>。 - 尝试获取锁: 实例读取 Lease 对象,检查当前
holderIdentity是否为空,或renewTime是否已过期(超过leaseDuration)。 - 抢占: 如果锁空闲或过期,实例尝试通过
Update操作将自己的 identity 写入 Lease 对象。由于 etcd 的乐观锁机制(resourceVersion),只有一个实例能成功。 - 成为 Leader: 更新成功的实例成为 Leader,开始执行控制循环,并定期(每
renewDeadline内)续约。 - 失败重试: 未获取锁的实例进入等待状态,持续观察 Lease 对象,一旦发现 Leader 停止续约(renewTime 过期),立即发起新一轮抢占。
--leader-elect-lease-duration(默认 15s):Lease 的租约时长。超过此时间未续约,锁被视为释放。--leader-elect-renew-deadline(默认 10s):Leader 必须在此时长内完成续约,否则视为失联。--leader-elect-retry-period(默认 2s):候选者尝试获取锁或 Leader 尝试续约的间隔。
4.3 Leader 任期与心跳机制
Leader 任期从成功获取锁开始,到主动释放或失联结束。心跳通过定期更新 Lease 对象的 renewTime 字段实现。
下图展示了 Leader 正常任期与故障转移的时间线:
4.4 脑裂防护与优雅降级
Leader Election 通过以下机制防止脑裂:
- 乐观锁(resourceVersion): 所有更新操作携带 etcd 的 resourceVersion,只有版本匹配的请求才能成功,确保同一时刻只有一个实例能写入 Lease。
- 租约过期(leaseDuration): 即使 Leader 因网络分区与 etcd 失联,旧 Leader 也不会立即释放锁,而是等待 leaseDuration 超时。这避免了网络抖动导致的频繁切换。
- Stale Leader 检测: 旧 Leader 在失联后,其本地控制循环仍可能短暂运行。但 Lease 锁已被新 Leader 获取,旧 Leader 的更新操作会因 resourceVersion 冲突而失败,从而自动停止控制逻辑。
leaseDuration 设置过小(如 <5s),网络抖动可能导致频繁的 Leader 切换,增加控制面抖动。如果设置过大(如 >60s),Leader 故障后故障转移时间会变长。生产环境建议保持默认值(15s)。
4.5 选举状态查看与调试
可以通过以下命令查看当前 Leader 信息:
# 查看 Lease 对象(推荐)
kubectl get lease -n kube-system kube-controller-manager -o yaml
# 输出示例(关键字段):
# spec:
# holderIdentity: "master-01_abc123"
# leaseDurationSeconds: 15
# acquireTime: "2025-03-20T10:00:00Z"
# renewTime: "2025-03-20T10:00:10Z"
# leaseTransitions: 3
# 查看 Endpoint 对象(兼容旧版本)
kubectl get endpoints -n kube-system kube-controller-manager -o yaml
通过 leaseTransitions 字段可以统计 Leader 切换次数,如果该值在短时间内快速增长,说明控制面存在稳定性问题。
4.6 多锁兼容与迁移策略
在集群升级过程中,可能同时存在使用 Endpoint 锁和 Lease 锁的组件。Kubernetes 支持 多锁(MultiLock) 模式,允许组件同时竞争多个锁,确保平滑迁移。
| 锁模式 | 参数设置 | 适用场景 |
|---|---|---|
| Endpoint 锁 | --leader-elect-resource-lock=endpoints |
v1.13 及以下集群 |
| Lease 锁 | --leader-elect-resource-lock=leases |
v1.14+ 集群(默认) |
| 多锁(Endpoint + Lease) | --leader-elect-resource-lock=endpointsleases |
集群升级过渡期,确保新旧版本组件互认 Leader |