Skip to content

Commit f22175c

Browse files
Gytis TriklerisRyan Baxter
Gytis Trikleris
authored and
Ryan Baxter
committed
1.0.x update local leader before notifications (spring-cloud#410)
* Fix leader election example * Update local leader before sending events
1 parent aef102d commit f22175c

File tree

9 files changed

+73
-49
lines changed

9 files changed

+73
-49
lines changed

spring-cloud-kubernetes-examples/kubernetes-leader-election-example/README.md

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,17 @@ And finally, if the leadership is yielded or revoked for some reason, the old le
2727

2828
## Example application usage
2929

30-
To begin with, build and deploy the application:
30+
Leader election mechanism uses Kubernetes ConfigMap feature to coordinate leadership information.
31+
To access ConfigMap user needs correct role and role binding.
32+
Create them using the following commands:
33+
```
34+
kubectl apply -f leader-role.yml
35+
kubectl apply -f leader-rolebinding.yml
36+
```
37+
38+
Now build and deploy the application:
3139
```
32-
mvn clean package fabric8:deploy -Pkubernetes
40+
mvn clean fabric8:deploy -Pkubernetes
3341
```
3442

3543
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
7684

7785
> Note: instances periodically try to acquire leadership and Spring Cloud Kubernetes doesn't decide which one of them is more worth to become one.
7886
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.
79-
80-
## Access control notice
81-
82-
Leader election mechanism uses Kubernetes ConfigMap feature to coordinate leadership information.
83-
In order to access it, [Role](./src/main/fabric8/role.yaml) and [RoleBinding](./src/main/fabric8/rb.yaml) objects are defined.
87+
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
apiVersion: rbac.authorization.k8s.io/v1
2+
kind: Role
3+
metadata:
4+
name: leader
5+
labels:
6+
app: kubernetes-leader-election-example
7+
group: org.springframework.cloud
8+
rules:
9+
- apiGroups:
10+
- ""
11+
resources:
12+
- pods
13+
- configmaps
14+
verbs:
15+
- '*'
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
apiVersion: rbac.authorization.k8s.io/v1
2+
kind: RoleBinding
3+
metadata:
4+
labels:
5+
app: kubernetes-leader-election-example
6+
group: org.springframework.cloud
7+
name: leader
8+
roleRef:
9+
apiGroup: ""
10+
kind: Role
11+
name: leader
12+
subjects:
13+
- kind: ServiceAccount
14+
name: default
15+
apiGroup: ""

spring-cloud-kubernetes-examples/kubernetes-leader-election-example/pom.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@
3636
<groupId>org.springframework.boot</groupId>
3737
<artifactId>spring-boot-starter-web</artifactId>
3838
</dependency>
39+
<dependency>
40+
<groupId>org.springframework.boot</groupId>
41+
<artifactId>spring-boot-starter-actuator</artifactId>
42+
</dependency>
3943
<dependency>
4044
<groupId>org.springframework.cloud</groupId>
4145
<artifactId>spring-cloud-kubernetes-leader</artifactId>

spring-cloud-kubernetes-examples/kubernetes-leader-election-example/src/main/fabric8/rb.yaml

Lines changed: 0 additions & 13 deletions
This file was deleted.

spring-cloud-kubernetes-examples/kubernetes-leader-election-example/src/main/fabric8/role.yaml

Lines changed: 0 additions & 12 deletions
This file was deleted.

spring-cloud-kubernetes-leader/src/main/java/org/springframework/cloud/kubernetes/leader/LeaderAutoConfiguration.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@
4141
@Configuration
4242
@EnableConfigurationProperties(LeaderProperties.class)
4343
@ConditionalOnBean(KubernetesClient.class)
44-
@ConditionalOnProperty(value = "spring.cloud.kubernetes.leader.enabled", matchIfMissing = true)
44+
@ConditionalOnProperty(value = "spring.cloud.kubernetes.leader.enabled",
45+
matchIfMissing = true)
4546
public class LeaderAutoConfiguration {
4647

4748
@Bean

spring-cloud-kubernetes-leader/src/main/java/org/springframework/cloud/kubernetes/leader/LeadershipController.java

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -149,24 +149,18 @@ private void handleLeaderChange(Leader newLeader) {
149149
LOGGER.debug("Leader is still '{}'", this.localLeader);
150150
return;
151151
}
152-
else if (this.localLeader != null
153-
&& this.localLeader.isCandidate(this.candidate)) {
152+
153+
Leader oldLeader = this.localLeader;
154+
this.localLeader = newLeader;
155+
156+
if (oldLeader != null && oldLeader.isCandidate(this.candidate)) {
154157
notifyOnRevoked();
155158
}
156159
else if (newLeader != null && newLeader.isCandidate(this.candidate)) {
157160
notifyOnGranted();
158161
}
159162

160-
this.localLeader = newLeader;
161-
if (this.leaderReadinessWatcher != null) {
162-
this.leaderReadinessWatcher.stop();
163-
this.leaderReadinessWatcher = null;
164-
}
165-
if (this.localLeader != null && !this.localLeader.isCandidate(this.candidate)) {
166-
this.leaderReadinessWatcher = new PodReadinessWatcher(
167-
this.localLeader.getId(), this.kubernetesClient, this);
168-
this.leaderReadinessWatcher.start();
169-
}
163+
restartLeaderReadinessWatcher();
170164

171165
LOGGER.debug("New leader is '{}'", this.localLeader);
172166
}
@@ -203,6 +197,19 @@ private void notifyOnFailedToAcquire() {
203197
}
204198
}
205199

200+
private void restartLeaderReadinessWatcher() {
201+
if (this.leaderReadinessWatcher != null) {
202+
this.leaderReadinessWatcher.stop();
203+
this.leaderReadinessWatcher = null;
204+
}
205+
206+
if (this.localLeader != null && !this.localLeader.isCandidate(this.candidate)) {
207+
this.leaderReadinessWatcher = new PodReadinessWatcher(
208+
this.localLeader.getId(), this.kubernetesClient, this);
209+
this.leaderReadinessWatcher.start();
210+
}
211+
}
212+
206213
private String getLeaderKey() {
207214
return this.leaderProperties.getLeaderIdPrefix() + this.candidate.getRole();
208215
}

spring-cloud-kubernetes-leader/src/test/java/org/springframework/cloud/kubernetes/leader/LeaderAutoConfigurationTests.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,13 @@
3131
import static org.hamcrest.Matchers.containsString;
3232

3333
@RunWith(SpringRunner.class)
34-
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = {
35-
"spring.cloud.kubernetes.leader.autoStartup=false" // Make sure test passes
36-
// without Kubernetes cluster
37-
})
34+
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
35+
properties = { "spring.cloud.kubernetes.leader.autoStartup=false" // Make sure
36+
// test passes
37+
// without
38+
// Kubernetes
39+
// cluster
40+
})
3841
public class LeaderAutoConfigurationTests {
3942

4043
@Value("${local.server.port}")

0 commit comments

Comments
 (0)