Skip to content

Leader Election 领导者选举

为什么需要领导者选举

控制器多副本部署时,需要确保只有一个实例真正执行 Reconcile,避免并发冲突。K8s 通过 Lease 对象实现分布式锁。

实现原理

多个 Controller 实例竞争创建/更新 Lease 对象


成功获取 Lease → 成为 Leader → 执行控制器逻辑


定期续约 Lease(renewDeadline 内)


Leader 宕机 → Lease 过期 → 其他实例竞争成为新 Leader

完整示例

go
package main

import (
    "context"
    "os"
    "time"

    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    "k8s.io/client-go/kubernetes"
    "k8s.io/client-go/rest"
    "k8s.io/client-go/tools/leaderelection"
    "k8s.io/client-go/tools/leaderelection/resourcelock"
)

func main() {
    config, _ := rest.InClusterConfig()
    clientset, _ := kubernetes.NewForConfig(config)

    // 获取当前 Pod 名称作为 ID
    id := os.Getenv("POD_NAME")
    if id == "" {
        id, _ = os.Hostname()
    }

    // 创建 Lease 锁
    lock := &resourcelock.LeaseLock{
        LeaseMeta: metav1.ObjectMeta{
            Name:      "my-controller-leader",
            Namespace: "kube-system",
        },
        Client: clientset.CoordinationV1(),
        LockConfig: resourcelock.ResourceLockConfig{
            Identity: id,
        },
    }

    ctx, cancel := context.WithCancel(context.Background())
    defer cancel()

    leaderelection.RunOrDie(ctx, leaderelection.LeaderElectionConfig{
        Lock:            lock,
        LeaseDuration:   15 * time.Second,  // 租约时长
        RenewDeadline:   10 * time.Second,  // 续约截止时间
        RetryPeriod:     2 * time.Second,   // 重试间隔
        ReleaseOnCancel: true,

        Callbacks: leaderelection.LeaderCallbacks{
            OnStartedLeading: func(ctx context.Context) {
                // 成为 Leader,启动控制器
                runController(ctx, clientset)
            },
            OnStoppedLeading: func() {
                // 失去 Leader,退出进程(让 K8s 重启)
                os.Exit(0)
            },
            OnNewLeader: func(identity string) {
                if identity == id {
                    return
                }
                fmt.Printf("当前 Leader: %s\n", identity)
            },
        },
    })
}

查看 Lease 对象

bash
# 查看 Leader 信息
kubectl get lease -n kube-system my-controller-leader -o yaml

# 输出示例
spec:
  acquireTime: "2024-01-01T00:00:00Z"
  holderIdentity: my-controller-pod-abc123  # 当前 Leader
  leaseDurationSeconds: 15
  leaseTransitions: 3
  renewTime: "2024-01-01T00:01:00Z"

本站内容由 褚成志 整理编写,仅供学习参考