多实例部署与协同(Leader 选举 + Lease 同步)
November 15, 2025 · View on GitHub
K8M 支持同时运行多个实例以提高可靠性与扩展性。在多实例模式下,平台通过两项机制完成协同:
- Leader 选举:确保只有一个实例执行定时任务(如集群巡检、Helm 仓库更新)。
- Lease 同步:为每个连接的集群建立租约对象,驱动所有实例对该集群的本地连接/断开保持一致。
本文基于以下实现参考:pkg/leader/leader.go、pkg/lease/manager.go、main.go。
原理概述
- 实例标识:每个 K8M 实例在启动时生成唯一的
InstanceID(参考utils.GenerateInstanceID())。 - Leader 选举(
leader.Run):- 采用 Kubernetes
LeaseLock进行选举,锁名为k8m-leader-lock,命名空间默认自动检测(参考utils.DetectNamespace())。 - 默认时序为:
LeaseDuration=60s、RenewDeadline=50s、RetryPeriod=10s,仅当有可用的集群配置时参与选举;否则直接本地运行为 Leader(不选举)。 - 成为 Leader 后启动定时任务:集群巡检(Lua)与 Helm 仓库更新;失去 Leader 后停止这些任务(参考
main.go)。
- 采用 Kubernetes
- Lease 同步(
lease.Manager):- 连接某个集群前,实例调用
EnsureOnConnect在宿主集群的指定命名空间创建一个Lease,用于声明“该集群处于连接状态”。 Lease名称格式:<product>-cluster-<sha1(clusterID)前4字节>,其中<product>来自--product-name(参考flag.Config.ProductName)。Lease标签固定包含:app=k8m、type=cluster-sync、clusterID=<Base64编码>;HolderIdentity为当前实例的InstanceID。- 所有实例通过共享 Informer 监听该命名空间下的
Lease增删改:- 有效
Lease新增/更新 → 非责任实例触发本地Connect(clusterID)。 Lease删除 → 所有实例触发本地Disconnect(clusterID)。
- 有效
- Leader 以 30s 周期清理过期的
Lease,从而统一触发断开(参考StartLeaderCleanup)。
- 连接某个集群前,实例调用
行为流程
- 连接:
- A 实例欲连接某集群 → 调用
EnsureOnConnect创建该集群的Lease并开始续约循环。 - 若已有其他实例持有有效
Lease,A 实例不会重复创建,日志提示“已连接”,并等待 Watcher 驱动本地连接。 - 其他实例通过 Watcher 看到有效
Lease新增后执行Connect(clusterID),从而实现所有实例的本地连接保持一致。
- A 实例欲连接某集群 → 调用
- 断开:
- 责任实例在本地断开时删除对应
Lease(EnsureOnDisconnect)。 - 其他实例收到删除事件后执行
Disconnect(clusterID),一致断开。
- 责任实例在本地断开时删除对应
- 过期清理:
- 若责任实例异常退出,其
Lease不再续约;Leader 检测到过期后删除该Lease,驱动所有实例断开,保证状态一致性与自愈。
- 若责任实例异常退出,其
参数与配置
以下参数均可通过启动参数或环境变量设置(参考 pkg/flag/flag.go)。
- 宿主集群选择:
--host-cluster-id或HOST_CLUSTER_ID:指定用于存储Lease和进行 Leader 选举的宿主集群 ID(从“多集群管理”复制)。- 未指定时回退使用 InCluster(
--in-cluster/IN_CLUSTER)。
- Lease 参数:
--lease-namespace/LEASE_NAMESPACE:Lease命名空间,默认自动检测。--lease-duration-seconds/LEASE_DURATION_SECONDS:Lease有效时长,默认60。--lease-renew-interval-seconds/LEASE_RENEW_INTERVAL_SECONDS:续约周期,默认20;若未设置或不合法,自动回退为有效时长的 1/3(不低于 20)。
- 监听与重同步:
- 代码内默认
ResyncPeriod=30s(参考main.go中传入的lease.Options)。
- 代码内默认
- 启动连接行为:
--connect-cluster/CONNECT_CLUSTER:程序启动后是否自动连接已发现的集群,默认关闭。
- 选举锁:
- 锁名固定为
k8m-leader-lock,命名空间默认自动检测。需要该命名空间在宿主集群中可访问。
- 锁名固定为
部署建议
- 在同一或不同节点运行多个 K8M 实例,确保它们能访问相同的宿主集群。
- 建议所有实例共享数据库,以保证平台管理数据的一致性;连接状态由
Lease同步保证,无需依赖单点。 - 将实例置于负载均衡之后对外提供服务。所有实例都会根据
Lease同步进行本地连接/断开;只有 Leader 执行巡检与 Helm 仓库更新等定时任务。 - 日志建议设置
LOG_V=6以获得更详细的中文日志(系统内部使用klog.V(6).Infof输出)。
示例
环境变量示例(可写入 .env 或容器环境):
IN_CLUSTER=true
HOST_CLUSTER_ID=your-cluster-id # 可选;留空则优先 InCluster
LEASE_NAMESPACE=k8m # 可选;留空自动检测
LEASE_DURATION_SECONDS=60
LEASE_RENEW_INTERVAL_SECONDS=20
CONNECT_CLUSTER=true
PRODUCT_NAME=K8M
LOG_V=6
启动参数示例(仅示例,按需调整):
./k8m \
--in-cluster \
--connect-cluster \
--lease-namespace k8m \
--lease-duration-seconds 60 \
--lease-renew-interval-seconds 20 \
--product-name K8M
以上配置即可在多实例部署下,通过 Leader 选举与 Lease 同步机制,实现集群连接状态一致、任务单点执行与异常自愈。