惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

腾讯CDC
Hacker News: Ask HN
Hacker News: Ask HN
S
Securelist
Security Latest
Security Latest
S
Schneier on Security
T
Threat Research - Cisco Blogs
Latest news
Latest news
Cyberwarzone
Cyberwarzone
A
Arctic Wolf
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
NISL@THU
NISL@THU
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
I
Intezer
T
The Exploit Database - CXSecurity.com
N
News and Events Feed by Topic
Simon Willison's Weblog
Simon Willison's Weblog
T
Tor Project blog
Blog — PlanetScale
Blog — PlanetScale
C
Cyber Attacks, Cyber Crime and Cyber Security
C
CERT Recently Published Vulnerability Notes
The Hacker News
The Hacker News
月光博客
月光博客
WordPress大学
WordPress大学
博客园 - 叶小钗
Hugging Face - Blog
Hugging Face - Blog
美团技术团队
量子位
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
C
Cisco Blogs
博客园 - 三生石上(FineUI控件)
Google DeepMind News
Google DeepMind News
Project Zero
Project Zero
Webroot Blog
Webroot Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Application and Cybersecurity Blog
Application and Cybersecurity Blog
云风的 BLOG
云风的 BLOG
L
LINUX DO - 最新话题
Schneier on Security
Schneier on Security
Engineering at Meta
Engineering at Meta
www.infosecurity-magazine.com
www.infosecurity-magazine.com
aimingoo的专栏
aimingoo的专栏
D
Docker
有赞技术团队
有赞技术团队
Google DeepMind News
Google DeepMind News
宝玉的分享
宝玉的分享
T
Troy Hunt's Blog
L
Lohrmann on Cybersecurity
T
The Blog of Author Tim Ferriss
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
L
LangChain Blog

博客园 - 左扬

Kubernetes 编程 / Operator 专题【左扬精讲】—— Client-go 源代码分析:生产级 Controller 实践:并发安全、资源清理与高可用设计 Kubernetes 编程 / Operator 专题【左扬精讲】—— Client-go 源代码分析: Controller 调试与诊断工具:从日志分析到问题定位 Kubernetes 编程 / Operator 专题【左扬精讲】—— Client-go 源代码分析:DynamicClient 操作 CRD:无需代码生成的动态操作 Kubernetes 编程 / Operator 专题【左扬精讲】—— Client-go 源代码分析:控制器与 APIServer 完整交互流程:从 Watch 到缓存同步 Kubernetes 编程 / Operator 专题【左扬精讲】—— Client-go 源代码分析:错误处理与重试机制:WorkQueue 限速器详解 Kubernetes 编程 / Operator 专题【左扬精讲】—— Client-go 源代码分析:Controller 开发模式完整实战 Kubernetes 编程 / Operator 专题【左扬精讲】—— Client-go 源代码分析:SharedInformerFactory 与等待缓存同步 Kubernetes 编程 / Operator 专题【左扬精讲】—— Client-go 源代码分析:从认证配置到 Deployment 操作 Kubernetes 编程 / Operator 专题【左扬精讲】—— Client-go 源代码分析:版本对应、架构组件与组件关系 Kubernetes 编程 / Operator 专题【左扬精讲】—— Client-go 源代码分析:Informer 源码深度解析:从底层原理到实战应用 Kubernetes 编程 / Operator 专题【左扬精讲】—— Client-go 源代码分析:Reflector 源码深度解析 Kubernetes 编程 / Operator 专题【左扬精讲】—— Client-go 源代码分析:ListWatcher 源码深度解析 Kubernetes 编程 / Operator 专题【左扬精讲】—— Client-go 源代码分析:Indexer 与 ThreadSafeStore 核心原理与源码深度剖析 Kubernetes 编程 / Operator 专题【左扬精讲】—— Client-go 源代码分析:DeltaFIFO 核心原理与源码深度剖析 Kubernetes 编程 / Operator 专题【左扬精讲】—— workqueue 核心原理与实战 Kubernetes 编程 / Operator 专题【左扬精讲】—— runtime.Codec 资源编解码:serializer 与 codec 差异、编解码数据结构、codec 核心调用链路 Kubernetes 编程 / Operator 专题【左扬精讲】—— Scheme 资源注册机制全解 Kubernetes 编程 / Operator 专题【左扬精讲】—— Kubernetes 自定义资源的内部版本与外部版本:从源码看版本定义机制 Kubernetes 编程 / Operator 专题【左扬精讲】—— Kubernetes 1.36.1 核心 API 数据结构全解 Kubernetes 编程 / Operator 专题【左扬精讲】—— Kubernetes 构建过程 【AIOPS】一文读懂LLM【左扬精讲】:从诞生到普及,解锁大语言模型的核心密码 【AIOPS】AI Agent 专题【左扬精讲】核心功能篇:MCP-VictoriaMetrics Hooks 源码精讲:Hooks 可观测性的无侵入式实现 【AIOPS】AI Agent 专题【左扬精讲】核心功能篇:MCP-VictoriaMetrics Golang 配置解析源码精讲 ——SRE 自定义 Agent 核心技巧 【AIOPS】AI Agent 专题【左扬精讲】核心功能篇:MCP-VictoriaMetrics Golang 并发模型解析 ——SRE 应对高并发采集的调优思路 【AIOPS】AI Agent 专题【左扬精讲】基础架构篇:MCP-VictoriaMetrics Golang 源码整体架构拆解 ——SRE 必懂的核心模块与数据流 OpenTelemetry 开发实战【左扬精讲】—— 云原生可观测体系构建与分布式追踪二次开发 Kubernetes 编程 / Operator 专题【左扬精讲】—— Operator 开发实战项目 7 —— 基于流量预测模型的智能弹性扩缩容 Operator 实战(AIOps 模型训练与智能扩容(下篇)—— 预测式弹性扩缩容 Operator 落地实现) Kubernetes 编程 / Operator 专题【左扬精讲】—— Operator 开发实战项目 7 —— 基于流量预测模型的智能弹性扩缩容 Operator 实战(AIOps 模型训练与智能扩容(上篇)—— 时序预测模型构建与离线训练) Kubernetes 编程 / Operator 专题【左扬精讲】—— Operator 开发实战项目 6 —— 基于运维专家知识库的智能故障诊断与排查 Operator 实战 Kubernetes 编程 / Operator 专题【左扬精讲】—— Operator 开发实战项目 5 —— 基于大语言模型(LLM)的实时日志流智能监测 Operator 实现 Kubernetes 编程 / Operator 专题【左扬精讲】—— Operator 开发实战项目 4 —— 基于 Operator 实现大模型私有化部署与管理 Kubernetes 编程 / Operator 专题【左扬精讲】—— Operator 开发实战项目 3 —— 面向 AI / 算力调度场景:GPU 竞价实例资源池统一调度管理 Operator 开发 Kubernetes编程 / Operator专题【左扬精讲】—— Operator 开发实战项目 2 —— 面向零售 / 电商潮汐流量难题:多云多集群数据中心级全链路弹性伸缩 DataCenter Scaler Operator 从 0 到 1 全链路开发 Kubernetes编程 / Operator专题【左扬精讲】—— 深入理解Kubebuilder注解:为什么Operator开发离不开这些特殊注释 Kubernetes编程 / Operator专题【左扬精讲】—— Operator 开发实战项目1 —— Applicaion Operator(通用应用生命周期管理 Operator 实战) Pod 镜像拉取失败?kubectl edit pods修改镜像地址的底层原理与实操 (该方法仅为临时应急方案,并非长期解决方案) Kubernetes编程/Operator专题精讲—— 理解控制器模式 —— 控制器模式的核心原理与实现逻辑(从原理到实践) 【AIOPS】AI Agent 专题【左扬精讲】模型微调实战:一站式平台 LLaMA-Factory 【AIOPS】AI Agent 专题【左扬精讲】基于 k8s+vLLM+Ray 分布式部署全指南:架构设计、资源调度与性能优化 【AIOPS】AI Agent专题【左扬精讲】非量化版DeepSeek分布式部署全指南:精度保障、显存规划与Ollama/vLLM选型 【AIOPS】AI Agent 专题【左扬精讲】零开发框架实现 ReAct Agent(Go SRE友好)
Kubernetes 编程 / Operator 专题【左扬精讲】—— Client-go 源代码分析:Leader 选举机制:高可用控制器的必备技能
左扬 · 2026-06-13 · via 博客园 - 左扬

Kubernetes 编程 / Operator 专题【左扬精讲】—— Client-go 源代码分析:Leader 选举机制:高可用控制器的必备技能

当我们部署一个高可用的 Kubernetes Controller 时,通常会部署多个副本。

但问题是:如果每个副本都独立运行,都会执行 Reconcile 逻辑,会不会导致重复操作、数据不一致?Leader 选举机制就是为了解决这个问题:同一时间只有一个副本在真正工作,其他副本处于待机状态。当主副本挂掉后,其他副本会自动选举出新的 Leader,继续工作。

Kubernetes Leader Election 高可用 Lease v1.36.1

🔓 学习重点提示  — 建议先通读全文,再重点回顾标注内容

★ 重点掌握(必须)
   • LeaderElectionConfig 核心字段:LeaseDuration、RenewDeadline、RetryPeriod 的含义与调优
   • Leader 选举流程:获取锁 → 更新锁 → 续约 → 释放锁
   • Callbacks 回调:OnStartedLeading、OnStoppedLeading、OnNewLeader 的使用场景

☆ 次重点(了解即可)
   • 多锁机制(MultiLock)


一、为什么需要 Leader 选举?

想象一个场景:我们部署了 3 个 Controller 副本,每个都监听同一个 Deployment。当用户修改了 Deployment 的副本数时:

  • 如果没有 Leader 选举:3 个副本都收到事件,都执行 Reconcile,都去更新 ReplicaSet。造成竞态条件、资源冲突、甚至多次更新导致状态不一致。
  • 如果有 Leader 选举:只有 Leader 副本处理事件,其他副本处于待机状态。主副本挂掉后,选举出新 Leader 继续工作。

Leader 选举就像公司的 CEO 职位:同一时间只有一个 CEO,当 CEO 辞职或被解雇后,董事会选举新的 CEO。Kubernetes 内置组件(kube-controller-manager、kube-scheduler)都使用了 Leader 选举。

二、LeaseLock:Leader 选举的实现原理

Kubernetes 的 Leader 选举依赖 Lease(续约锁)对象。Lease 是 Kubernetes 1.14 之后引入的新机制,比之前的 Endpoints/ConfigMaps 锁更轻量。

在 Kubernetes 源码中,resourcelock.Interface 定义了锁的抽象:

// staging/src/k8s.io/client-go/tools/leaderelection/resourcelock/interface.go

// Interface 定义了 Leader 选举锁的抽象
type Interface interface {
    // Get 获取当前的 Leader 选举记录
    Get(ctx context.Context) (*LeaderElectionRecord, []byte, error)

    // Create 创建 Leader 选举记录
    Create(ctx context.Context, ler LeaderElectionRecord) error

    // Update 更新 Leader 选举记录(核心!续约操作)
    Update(ctx context.Context, ler LeaderElectionRecord) error

    // RecordEvent 记录事件到资源上
    RecordEvent(string)

    // Identity 返回当前锁持有者的唯一标识
    Identity() string

    // Describe 返回锁的描述信息
    Describe() string
}

LeaderElectionRecord 存储在 Lease 对象的 Annotation 中:

// LeaderElectionRecord 结构体

// LeaderElectionRecord 存储 Leader 选举的状态
type LeaderElectionRecord struct {
    // HolderIdentity:当前 Leader 的标识(通常是 Pod 名称)
    HolderIdentity string `json:"holderIdentity"`

    // LeaseDurationSeconds:租约时长(秒)
    LeaseDurationSeconds int `json:"leaseDurationSeconds"`

    // AcquireTime:获取 Leader 位置的时间
    AcquireTime metav1.Time `json:"acquireTime"`

    // RenewTime:最后一次续约的时间
    RenewTime metav1.Time `json:"renewTime"`

    // LeaderTransitions:Leader 切换次数(用于监控)
    LeaderTransitions int `json:"leaderTransitions"`

    // Strategy:协调策略
    Strategy v1.CoordinatedLeaseStrategy `json:"strategy"`

    // PreferredHolder:优先持有者(用于有状态选举)
    PreferredHolder string `json:"preferredHolder"`
}

三、LeaderElectionConfig:配置详解

NewLeaderElector 函数负责创建 LeaderElector,它需要传入一个 LeaderElectionConfig 配置:

// staging/src/k8s.io/client-go/tools/leaderelection/leaderelection.go(行 116-166)

type LeaderElectionConfig struct {
    // Lock:锁对象,用于存储 Leader 状态
    Lock rl.Interface

    // LeaseDuration:租约有效期
    // 非 Leader 节点在 LeaseDuration 时间内没有观察到 Leader 更新,
    // 就可以认为 Leader 丢失,从而尝试获取 Leader
    LeaseDuration time.Duration

    // RenewDeadline:续约间隔
    // Leader 每隔 RenewDeadline 时间就要续约一次
    // 如果续约失败(超过 RenewDeadline 没有续约),其他节点会认为 Leader 丢失
    RenewDeadline time.Duration

    // RetryPeriod:重试间隔
    // 节点尝试获取锁或观察 Leader 状态的重试间隔
    RetryPeriod time.Duration

    // Callbacks:选举状态变化的回调函数
    Callbacks LeaderCallbacks

    // WatchDog:健康检查器(可选)
    WatchDog *HealthzAdaptor

    // ReleaseOnCancel:收到取消信号时是否主动释放锁
    ReleaseOnCancel bool

    // Name:锁的名称(用于调试和监控)
    Name string

    // Coordinated:是否使用协调 Leader 选举(Alpha 特性)
    Coordinated bool
}

三个时间参数的关系非常重要:

LeaseDuration(租约时长)
│────────────────────────────────────────────────│
       ▲                    ▲
       │                    │
RenewDeadline           LeaseExpires
(续约间隔)            (过期时间)
       │                    │
       └──────────┬─────────┘
                  │
         Leader 续约(每 RENEW_DEADLINE 一次)
                  │
                  │ 正常情况下 Leader 一直续约
                  ▼
         如果 Leader 挂了,没有续约
         等待 LEASE_DURATION 后,其他节点认为 Leader 丢失
         开始选举新的 Leader

时间参数的经验公式

  • LeaseDuration > RenewDeadline:必须满足,否则代码会报错
  • RenewDeadline > RetryPeriod × 1.2:必须满足,确保重试有足够时间
  • 建议比例:LeaseDuration : RenewDeadline : RetryPeriod = 15s : 10s : 2s

四、LeaderCallbacks:回调函数

LeaderCallbacks 定义了 Leader 选举状态变化时的回调函数:

// LeaderCallbacks 定义

type LeaderCallbacks struct {
    // OnStartedLeading:当节点成为 Leader 时调用
    // ctx 是可取消的 context,当不再是 Leader 时会被取消
    OnStartedLeading func(context.Context)

    // OnStoppedLeading:当节点失去 Leader 地位时调用
    // 注意:这个回调不仅在主动让出 Leader 时触发,
    //       在 Leader 意外丢失时也会触发
    OnStoppedLeading func()

    // OnNewLeader:当观察到新的 Leader 时调用
    // 包括第一次观察到 Leader
    OnNewLeader func(identity string)
}

典型的使用场景:

// 创建 LeaderElector 并传入回调
elector, err := leaderelection.NewLeaderElector(leaderelection.LeaderElectionConfig{
    Lock: lock,
    LeaseDuration: 15 * time.Second,
    RenewDeadline: 10 * time.Second,
    RetryPeriod: 2 * time.Second,
    Callbacks: leaderelection.LeaderCallbacks{
        // 成为 Leader 后,启动 Controller 主循环
        OnStartedLeading: func(ctx context.Context) {
            klog.Info("Became leader, starting controller...")
            // 启动 Controller
            controller.Run(ctx, 2)
        },
        // 失去 Leader 后,停止 Controller
        OnStoppedLeading: func() {
            klog.Info("Lost leadership, stopping controller...")
            // 清理资源
            controller.Shutdown()
        },
        // 观察到新 Leader 时打印日志
        OnNewLeader: func(identity string) {
            if identity == lock.Identity() {
                klog.Info("Still the leader")
            } else {
                klog.Infof("New leader elected: %s", identity)
            }
        },
    },
})

五、完整使用示例

下面是一个完整的 Leader 选举使用示例:

// 完整的 Leader 选举使用示例

package main

import (
    "context"
    "fmt"
    "time"

    v1 "k8s.io/api/core/v1"
    coordinationv1 "k8s.io/api/coordination/v1"
    "k8s.io/apimachinery/pkg/api/errors"
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    "k8s.io/client-go/kubernetes"
    "k8s.io/client-go/tools/leaderelection"
    "k8s.io/client-go/tools/leaderelection/resourcelock"
    "k8s.io/client-go/tools/clientcmd"
)

func main() {
    // 第一步:加载 kubeconfig
    config, err := clientcmd.BuildConfigFromFlags("", "")
    if err != nil {
        panic(err)
    }

    // 第二步:创建 Kubernetes clientset
    clientset, err := kubernetes.NewForConfig(config)
    if err != nil {
        panic(err)
    }

    // 第三步:创建 Leader 选举锁
    // 使用 Lease 锁(Kubernetes 1.14+ 推荐)
    lock, err := resourcelock.New(
        resourcelock.LeasesResourceLock,         // 锁类型
        "default",                                // namespace
        "example-operator-leader",               // lock 名称
        clientset.CoordinationV1(),              // coordination client
        clientset.CoreV1(),                      // core client(用于记录 Events)
        resourcelock.ResourceLockConfig{
            Identity: fmt.Sprintf("pod-%s", getPodName()),  // 唯一标识(通常是 Pod 名)
        },
    )
    if err != nil {
        panic(err)
    }

    // 第四步:创建 Controller 实例(伪代码)
    controller := NewController(clientset)

    // 第五步:创建 LeaderElector
    leaderElector, err := leaderelection.NewLeaderElector(leaderelection.LeaderElectionConfig{
        Lock:            lock,
        LeaseDuration:   15 * time.Second,    // 租约时长
        RenewDeadline:   10 * time.Second,    // 续约间隔
        RetryPeriod:     2 * time.Second,     // 重试间隔
        ReleaseOnCancel: true,                 // 取消时释放锁
        Name:            "example-operator",
        Callbacks: leaderelection.LeaderCallbacks{
            OnStartedLeading: func(ctx context.Context) {
                // 成为 Leader 后启动 Controller
                klog.Info("Starting controller as leader")
                controller.Run(ctx, 2)
            },
            OnStoppedLeading: func() {
                // 失去 Leader 后停止 Controller
                klog.Info("Stopping controller, lost leadership")
                controller.Shutdown()
            },
            OnNewLeader: func(identity string) {
                // 观察到新 Leader
                klog.Infof("Leader changed to: %s", identity)
            },
        },
    })
    if err != nil {
        panic(err)
    }

    // 第六步:启动 Leader 选举
    // Run 函数会一直运行,直到 context 取消
    context, cancel := context.WithCancel(context.Background())
    defer cancel()
    leaderElector.Run(context)
}

// getPodName 获取当前 Pod 名称
func getPodName() string {
    // 实际环境中从 downward API 获取
    return "example-operator-abc123"
}

六、Leader 选举流程图

Leader 选举的完整流程:

┌──────────────────────────────────────────────────────────────────────────┐
│                        Leader 选举流程                                     │
├──────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  ┌─────────────┐                                                        │
│  │  非 Leader  │                                                        │
│  └──────┬──────┘                                                        │
│         │                                                                │
│         ▼ 检查 Lock                                                      │
│  ┌──────────────────────────────────────────────────────────────────┐  │
│  │ Lease 对象中存储的 HolderIdentity 是什么?                          │  │
│  └──────────────────────────┬───────────────────────────────────────┘  │
│                             │                                           │
│         ┌────────────────────┼────────────────────┐                      │
│         │                    │                    │                      │
│         ▼                    ▼                    ▼                      │
│  ┌─────────────┐      ┌─────────────┐      ┌─────────────┐              │
│  │ HolderIdentity │   │ HolderIdentity │   │ HolderIdentity │          │
│  │ = 本节点      │     │ = 其他节点    │      │ = 空(无Leader)│          │
│  └──────┬──────┘      └──────┬──────┘      └──────┬──────┘              │
│         │                    │                    │                      │
│         ▼                    ▼                    ▼                      │
│  ┌─────────────┐      ┌─────────────┐      ┌─────────────┐              │
│  │ 待机观察    │      │ 尝试获取锁  │      │ 创建锁记录  │              │
│  │ 每RetryPeriod│     │ (Update操作)│      │ (Create操作)│              │
│  │ 检查一次    │      └──────┬──────┘      └──────┬──────┘              │
│  └─────────────┘             │                    │                      │
│                              │ 成功?             │ 成功?               │
│                              ▼                    ▼                      │
│                       ┌─────────────┐       ┌─────────────┐             │
│                       │ 成为 Leader │       │ 成为 Leader │             │
│                       │ 启动 Controller│    │ 启动 Controller│           │
│                       └─────────────┘       └─────────────┘             │
│                              │                    │                      │
│                              ▼                    ▼                      │
│                       ┌─────────────────────────────────────┐           │
│                       │  Leader 主循环:                     │           │
│                       │  每 RenewDeadline 续约一次           │           │
│                       │  更新 Lease 的 RenewTime             │           │
│                       └─────────────────────────────────────┘           │
│                              │                    │                      │
│                              │ 续约失败?         │ 节点被删除?          │
│                              ▼                    ▼                      │
│                       ┌─────────────┐       ┌─────────────┐             │
│                       │ 失去 Leader │       │ 失去 Leader │             │
│                       │ 停止 Controller│    │ 停止 Controller│           │
│                       └──────┬──────┘       └──────┬──────┘             │
│                              │                    │                      │
│                              └────────────────────┴─────→ 回到起点        │
│                                                           检查 Lock       │
└──────────────────────────────────────────────────────────────────────────┘

七、生产环境配置建议

在生产环境中配置 Leader 选举时,需要考虑以下因素:

高流量 APIServer 场景

如果 APIServer 负载较高,可以增加 RetryPeriod 来减少竞争:

// 保守配置:减少 APIServer 压力
leaderelection.LeaderElectionConfig{
    LeaseDuration: 30 * time.Second,  // 较长的租约
    RenewDeadline: 20 * time.Second,    // 较长的续约间隔
    RetryPeriod: 5 * time.Second,      // 较长的重试间隔
    // ...
}

快速故障转移场景

如果需要快速故障转移,可以缩短时间参数:

// 快速切换配置:减少故障恢复时间
leaderelection.LeaderElectionConfig{
    LeaseDuration: 10 * time.Second,  // 较短的租约
    RenewDeadline: 6 * time.Second,     // 较短的续约间隔
    RetryPeriod: 1 * time.Second,      // 较短的重试间隔
    // ...
}

Identity 的最佳实践

Identity 应该唯一标识每个候选者,通常使用 Pod 名称:

# Pod 中配置 downward API 获取 Pod 名称作为 Identity
spec:
  containers:
  - name: operator
    env:
    - name: POD_NAME
      valueFrom:
        fieldRef:
          fieldPath: metadata.name
    # 或使用 downward API
    env:
    - name: NODE_NAME
      valueFrom:
        fieldRef:
          fieldPath: spec.nodeName

⚠️ 警告
Identity 必须全局唯一。如果两个节点使用相同的 Identity,它们会相互覆盖对方的 Leader 记录,导致频繁的 Leader 切换。


八、监控与排查

Leader 选举可以通过以下方式监控:

# 查看 Lease 对象状态
kubectl get lease -n default example-operator-leader -o yaml

# 查看 Leader 切换次数
kubectl get lease -n default example-operator-leader -o jsonpath='{.metadata.annotations.control-plane\.alpha\.kubernetes\.io/leader}'

# 如果有 LeaderElectionRecordAnnotationKey annotation,查看详细内容
kubectl get lease -n default example-operator-leader -o jsonpath='{.metadata.annotations}' | jq

常见的 Leader 选举问题:

问题原因解决方案
Leader 频繁切换 RenewDeadline 太短,APIServer 响应慢 增加 RenewDeadline 和 RetryPeriod
没有 Leader 被选出 所有候选者都无法创建 Lease 检查 RBAC 权限和 Lease 创建权限
LeaderTransitions 异常高 网络不稳定或节点不稳定 检查网络和节点健康状态

九、总结

这一节我们深入理解了 Leader 选举机制:

  • 为什么需要 Leader 选举:确保同一时间只有一个 Controller 实例在处理事件,避免竞态条件
  • LeaseLock 实现:基于 Kubernetes Lease 对象存储 Leader 状态,比旧版 Endpoints/ConfigMaps 更轻量
  • 三个时间参数:LeaseDuration > RenewDeadline > RetryPeriod × 1.2
  • Callbacks 的使用:OnStartedLeading 启动 Controller,OnStoppedLeading 停止 Controller
  • 生产配置建议:根据 APIServer 负载和故障恢复需求调整时间参数

下一节我们将学习 错误处理与重试机制,了解 WorkQueue 的限速器如何帮助 Controller 处理失败的任务。敬请期待!


Kubernetes 编程 / Operator 专题【左扬精讲】—— Leader 选举机制 · 来源:Kubernetes v1.36.1 client-go 源码分析