Spring Cloud Kubernetes选主:为不同功能配置独立主节点
Spring Cloud Kubernetes 多任务独立选主实现方案
需求背景
已基于Spring Cloud Kubernetes实现单Pod执行定时任务的选主逻辑,现需扩展为Job1、Job2两个定时任务各自独立选主——不同Pod可分别作为两个任务的主节点,各自负责执行对应任务。
核心原理
Spring Cloud Kubernetes的Leader选举通过**独立的角色(Role)**区分不同选举组,每个角色对应一个Kubernetes ConfigMap作为锁资源。不同角色的选举完全隔离,只需为两个任务分配不同的选举角色,即可实现独立选主。
实现步骤
1. 保持Maven依赖不变
当前依赖已满足多角色选主需求,无需修改:
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.3.3</version> <relativePath/> </parent> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-kubernetes-fabric8-leader</artifactId> </dependency>
2. 配置多角色选举规则
修改application.yaml,为两个任务分别配置独立的选举角色:
spring: cloud: kubernetes: leader: enabled: true autoStartup: true # 配置多个独立选举角色 roles: - name: job1-leader namespace: ${spring.cloud.kubernetes.client.namespace:default} - name: job2-leader namespace: ${spring.cloud.kubernetes.client.namespace:default}
说明:每个角色的
name需唯一,namespace可选,默认使用Pod所在的K8s命名空间。
3. 调整定时任务代码
每个任务仅响应自身角色的选举事件,修改ScheduledJob1和ScheduledJob2的事件监听逻辑:
ScheduledJob1(对应job1-leader角色)
import lombok.log4j.Log4j2; import org.springframework.context.event.EventListener; import org.springframework.integration.leader.event.OnGrantedEvent; import org.springframework.integration.leader.event.OnRevokedEvent; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @Log4j2 @Component public class ScheduledJob1 { private boolean isJob1Leader = false; private static final String JOB1_ROLE = "job1-leader"; @EventListener(OnGrantedEvent.class) public void onLeaderGranted(OnGrantedEvent event) { if (JOB1_ROLE.equals(event.getLeaderContext().getRole())) { log.info("Job1的主节点权限已授予当前实例"); isJob1Leader = true; } } @EventListener(OnRevokedEvent.class) public void onLeaderRevoked(OnRevokedEvent event) { if (JOB1_ROLE.equals(event.getLeaderContext().getRole())) { log.info("Job1的主节点权限已从当前实例收回"); isJob1Leader = false; } } @Scheduled(fixedRate = 2000) public void foo1() { if (isJob1Leader) { log.info("我是Job1的主节点,正在执行foo1任务"); } else { log.info("当前不是Job1主节点,跳过foo1任务"); } } }
ScheduledJob2(对应job2-leader角色)
import lombok.log4j.Log4j2; import org.springframework.context.event.EventListener; import org.springframework.integration.leader.event.OnGrantedEvent; import org.springframework.integration.leader.event.OnRevokedEvent; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @Log4j2 @Component public class ScheduledJob2 { private boolean isJob2Leader = false; private static final String JOB2_ROLE = "job2-leader"; @EventListener(OnGrantedEvent.class) public void onLeaderGranted(OnGrantedEvent event) { if (JOB2_ROLE.equals(event.getLeaderContext().getRole())) { log.info("Job2的主节点权限已授予当前实例"); isJob2Leader = true; } } @EventListener(OnRevokedEvent.class) public void onLeaderRevoked(OnRevokedEvent event) { if (JOB2_ROLE.equals(event.getLeaderContext().getRole())) { log.info("Job2的主节点权限已从当前实例收回"); isJob2Leader = false; } } @Scheduled(fixedRate = 2000) public void foo2() { if (isJob2Leader) { log.info("我是Job2的主节点,正在执行foo2任务"); } else { log.info("当前不是Job2主节点,跳过foo2任务"); } } }
4. 可选:Java代码自定义LeaderCandidate(更灵活)
若需更精细控制选举逻辑,可通过Java配置类手动创建两个LeaderCandidate实例(与yaml配置二选一即可):
import org.springframework.cloud.kubernetes.fabric8.leader.Fabric8LeaderCandidate; import org.springframework.cloud.kubernetes.fabric8.leader.Fabric8LeaderProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class LeaderConfig { private static final String JOB1_ROLE = "job1-leader"; private static final String JOB2_ROLE = "job2-leader"; @Bean public Fabric8LeaderCandidate job1LeaderCandidate(Fabric8LeaderProperties properties) { return new Fabric8LeaderCandidate(properties, JOB1_ROLE); } @Bean public Fabric8LeaderCandidate job2LeaderCandidate(Fabric8LeaderProperties properties) { return new Fabric8LeaderCandidate(properties, JOB2_ROLE); } }
验证要点
- 部署至少2个Pod到K8s集群
- 查看Pod日志,确认:
- 其中一个Pod成为Job1的主节点,执行foo1任务
- 另一个Pod成为Job2的主节点,执行foo2任务
- 当某个Pod下线时,对应任务的主节点会自动切换到其他可用Pod
K8s权限说明
确保Pod拥有ConfigMap的读写权限,可通过RBAC配置:
apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: namespace: default name: leader-role rules: - apiGroups: [""] resources: ["configmaps"] verbs: ["get", "watch", "list", "create", "update", "delete"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: namespace: default name: leader-role-binding subjects: - kind: ServiceAccount name: default roleRef: kind: Role name: leader-role apiGroup: rbac.authorization.k8s.io
内容的提问来源于stack exchange,提问作者Georgii Lvov
相关产品推荐
相关产品推荐

