1.0.x update local leader before notifications (#410)
* Fix leader election example * Update local leader before sending events
This commit is contained in:
committed by
Ryan Baxter
parent
aef102dc72
commit
f22175ca2d
@@ -27,9 +27,17 @@ And finally, if the leadership is yielded or revoked for some reason, the old le
|
||||
|
||||
## Example application usage
|
||||
|
||||
To begin with, build and deploy the application:
|
||||
Leader election mechanism uses Kubernetes ConfigMap feature to coordinate leadership information.
|
||||
To access ConfigMap user needs correct role and role binding.
|
||||
Create them using the following commands:
|
||||
```
|
||||
mvn clean package fabric8:deploy -Pkubernetes
|
||||
kubectl apply -f leader-role.yml
|
||||
kubectl apply -f leader-rolebinding.yml
|
||||
```
|
||||
|
||||
Now build and deploy the application:
|
||||
```
|
||||
mvn clean fabric8:deploy -Pkubernetes
|
||||
```
|
||||
|
||||
This will deploy a single application instance to the cluster and that instance will automatically become a leader.
|
||||
@@ -76,8 +84,4 @@ Thus, when trying to yield the leadership, request might go to a non-leader node
|
||||
|
||||
> Note: instances periodically try to acquire leadership and Spring Cloud Kubernetes doesn't decide which one of them is more worth to become one.
|
||||
Thus, it is possible that the instance which just yielded the leadership, made another leadership take over request faster than another instances and became a leader again.
|
||||
|
||||
## Access control notice
|
||||
|
||||
Leader election mechanism uses Kubernetes ConfigMap feature to coordinate leadership information.
|
||||
In order to access it, [Role](./src/main/fabric8/role.yaml) and [RoleBinding](./src/main/fabric8/rb.yaml) objects are defined.
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: leader
|
||||
labels:
|
||||
app: kubernetes-leader-election-example
|
||||
group: org.springframework.cloud
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- pods
|
||||
- configmaps
|
||||
verbs:
|
||||
- '*'
|
||||
@@ -0,0 +1,15 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
labels:
|
||||
app: kubernetes-leader-election-example
|
||||
group: org.springframework.cloud
|
||||
name: leader
|
||||
roleRef:
|
||||
apiGroup: ""
|
||||
kind: Role
|
||||
name: leader
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: default
|
||||
apiGroup: ""
|
||||
@@ -36,6 +36,10 @@
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-kubernetes-leader</artifactId>
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: leader
|
||||
namespace: default
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: leader
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: default
|
||||
namespace: default
|
||||
@@ -1,12 +0,0 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: leader
|
||||
namespace: default
|
||||
rules:
|
||||
- apiGroups:
|
||||
resources:
|
||||
- pods
|
||||
- configmaps
|
||||
verbs:
|
||||
- "*"
|
||||
@@ -41,7 +41,8 @@ import org.springframework.integration.leader.event.LeaderEventPublisher;
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(LeaderProperties.class)
|
||||
@ConditionalOnBean(KubernetesClient.class)
|
||||
@ConditionalOnProperty(value = "spring.cloud.kubernetes.leader.enabled", matchIfMissing = true)
|
||||
@ConditionalOnProperty(value = "spring.cloud.kubernetes.leader.enabled",
|
||||
matchIfMissing = true)
|
||||
public class LeaderAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -149,24 +149,18 @@ public class LeadershipController {
|
||||
LOGGER.debug("Leader is still '{}'", this.localLeader);
|
||||
return;
|
||||
}
|
||||
else if (this.localLeader != null
|
||||
&& this.localLeader.isCandidate(this.candidate)) {
|
||||
|
||||
Leader oldLeader = this.localLeader;
|
||||
this.localLeader = newLeader;
|
||||
|
||||
if (oldLeader != null && oldLeader.isCandidate(this.candidate)) {
|
||||
notifyOnRevoked();
|
||||
}
|
||||
else if (newLeader != null && newLeader.isCandidate(this.candidate)) {
|
||||
notifyOnGranted();
|
||||
}
|
||||
|
||||
this.localLeader = newLeader;
|
||||
if (this.leaderReadinessWatcher != null) {
|
||||
this.leaderReadinessWatcher.stop();
|
||||
this.leaderReadinessWatcher = null;
|
||||
}
|
||||
if (this.localLeader != null && !this.localLeader.isCandidate(this.candidate)) {
|
||||
this.leaderReadinessWatcher = new PodReadinessWatcher(
|
||||
this.localLeader.getId(), this.kubernetesClient, this);
|
||||
this.leaderReadinessWatcher.start();
|
||||
}
|
||||
restartLeaderReadinessWatcher();
|
||||
|
||||
LOGGER.debug("New leader is '{}'", this.localLeader);
|
||||
}
|
||||
@@ -203,6 +197,19 @@ public class LeadershipController {
|
||||
}
|
||||
}
|
||||
|
||||
private void restartLeaderReadinessWatcher() {
|
||||
if (this.leaderReadinessWatcher != null) {
|
||||
this.leaderReadinessWatcher.stop();
|
||||
this.leaderReadinessWatcher = null;
|
||||
}
|
||||
|
||||
if (this.localLeader != null && !this.localLeader.isCandidate(this.candidate)) {
|
||||
this.leaderReadinessWatcher = new PodReadinessWatcher(
|
||||
this.localLeader.getId(), this.kubernetesClient, this);
|
||||
this.leaderReadinessWatcher.start();
|
||||
}
|
||||
}
|
||||
|
||||
private String getLeaderKey() {
|
||||
return this.leaderProperties.getLeaderIdPrefix() + this.candidate.getRole();
|
||||
}
|
||||
|
||||
@@ -31,10 +31,13 @@ import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = {
|
||||
"spring.cloud.kubernetes.leader.autoStartup=false" // Make sure test passes
|
||||
// without Kubernetes cluster
|
||||
})
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
|
||||
properties = { "spring.cloud.kubernetes.leader.autoStartup=false" // Make sure
|
||||
// test passes
|
||||
// without
|
||||
// Kubernetes
|
||||
// cluster
|
||||
})
|
||||
public class LeaderAutoConfigurationTests {
|
||||
|
||||
@Value("${local.server.port}")
|
||||
|
||||
Reference in New Issue
Block a user