We had a similar issue when constrained to Spring Boot 2.7 and JDK 8. The solution was to use the fabric8 kubernetes-client directly, it has an easy-to-use LeaderElector
Version pkg:maven/io.fabric8/[email protected]
is the last one that supports JDK 8:
<dependency>
<groupId>io.fabric8</groupId>
<artifactId>kubernetes-client</artifactId>
<version>6.13.5</version>
</dependency>
Then in your @Service start the leader election:
public static final String serviceLeaderLeaseName = "my-service-leader-lease-name";
private final String leaseHolder = System.getenv("HOSTNAME");
private boolean serviceLeader = false;
@PostConstruct
public void initService() {
KubernetesClient client = new KubernetesClientBuilder().build();
LeaderCallbacks leaderCallbacks = new LeaderCallbacks(() -> {
serviceLeader = true;
logger.info("I am now the leader: {}", leaseHolder);
}, () -> {
serviceLeader = false;
logger.info("I am no longer the leader: {}", leaseHolder);
}, newLeader -> {
logger.info("The new leader is: {}", newLeader);
});
LeaderElectionConfig leaderElectionConfig = new LeaderElectionConfigBuilder()
.withName(serviceLeaderLeaseName)
.withLock(new LeaseLock(kubeNamespace, serviceLeaderLeaseName, leaseHolder))
.withLeaseDuration(Duration.ofSeconds(30))
.withRenewDeadline(Duration.ofSeconds(20))
.withRetryPeriod(Duration.ofSeconds(2))
.withReleaseOnCancel()
.withLeaderCallbacks(leaderCallbacks)
.build();
Executor executor = Executors.newSingleThreadExecutor();
LeaderElector leaderElector = new LeaderElectorBuilder(client, executor).withConfig(
leaderElectionConfig).build();
leaderElector.start();
}
public boolean isLeader() {
return serviceLeader;
}
This example uses a LeaseLock but there is also a ConfigMapLock if you prefer that.
Each replica will compete to lock the named lease. You'll be able to see which replica was elected as leader. If the leader goes away for any reason the lease will time out and a new replica becomes leader.
In your code check myService.isLeader()
to see if the current instance is the leader.