Spring Cloud Config Server — Auto Refresh using Apache Kafka in Kubernetes

Athul RAVINDRAN
4 min readMar 12, 2020

--

In the previous articles we saw how to set up Config server, Config first client and discovery first client. Here are the links to previous articles.

  1. Bootstrapping Spring Cloud Config server
  2. Spring Cloud Config server — Discovery First Vs Config First

We will now look at how to configure an auto refreshable configuration using Spring Cloud Bus, Kafka and run the software on Google Kubernetes Engine.

Config Server:

Maven dependency

Add the following dependency to your config server pom.

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-monitor</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-kafka</artifactId>
</dependency>

spring-cloud-config-monitor opens up the /monitor endpoint on config server which listens to any change of events (git webhook) and in turn refresh call to spring cloud bus which post the message to kafka broker. Any clients listening to the kafka broker’s topic will get event to refresh.

changes to application.yml, application-git.yml

Add properties related to bus and kafka to ymls.

server:
port: 8762

management:
endpoints:
web:
exposure:
include: '*'

spring:
profiles:
active: git
application:
name: config-server
cloud:
config:
override-system-properties: false
server
:
git:
uri: https://github.com/athulravindran87/spring-cloud-config.git
clone-on-start: true
search-paths
:
config-server/src/main/resources/config/,
config-server/src/main/resources/config/client-config-first,
config-server/src/main/resources/config/client-discovery-first
username: prasanna29387
bus:
enabled: true
kafka
:
bootstrap-servers: ${KAFKA_ADDR:http://localhost:9092}
eureka:
client:
register-with-eureka: true
fetch-registry
: true
serviceUrl
:
defaultZone: ${EUREKA_URI:http://localhost:8761/eureka}
instance:
hostname: ${spring.application.name}
preferIpAddress: true

Note: pay attention to the variables, KAFKA_ADDR, EUREKA_URI. These will be used later in the story.

Config Client:

Maven dependency

Add the following dependency to your config server pom.

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-kafka</artifactId>
</dependency>

Changes to bootstrap.yml

Add properties related to bus and kafka to ymls.

spring:
application:
name: client-config-first
profiles:
active: local
cloud:
config:
uri: ${CONFIG_URI:http://localhost:8888}
fail-fast: true
retry
:
max-attempts: 20
max-interval: 15000
initial-interval: 10000
bus:
refresh:
enabled: true
env
:
enabled: true
kafka
:
bootstrap-servers: ${KAFKA_ADDR:http://localhost:9092}

server:
port: 8763

Note: pay attention to the variables, KAFKA_ADDR, CONFIG_URI. These will be used later in the story.

Now that we have made changes to server and client, lets try to add Kafka.

Download kafka from Go to this URL and download Apache Kafka: https://www.apache.org/dyn/closer.cgi?path=/kafka/2.2.0/kafka_2.12-2.2.0.tgz and follow instructions to bring kafka up at 9092.

How to test ??

  1. Bring up Kafka, Config server (-Dspring.profiles.active = git) and config client.
  2. Both services should connect to kafka on start up and apps are healthy.
  3. Modify “test.name” in client-config-first.yml and push it to git.
  4. Use postman or any other client and make a POST call to http://localhost:8762/actuator/bus-refresh
  5. In the logs you will see that config server pulled the latest from git, published the change event on kafka topic and config client pulled the information and refreshed itself.
  6. Now hit the url (http://localhost:8763/test) on your browser to view the updated property value.

Let’s go further and achieve auto refresh …

Let’s go one step further and automate it completely by deploying to Kubernetes on Google Cloud.

I am assuming you have an active project on Google Cloud and have a Kubernetes cluster configured, published your docker images to GCR or docker and ready to deploy. If not please google and set up your cluster ready. I have written a story on publishing docker images to GCR using Jenkins and maven plugin.

Let’s start deploying one service at a time. Refer to the source code here in github.

  1. deploy zookeeper.yml from Kafka-server/deploy folder.
  2. deploy kafka.yml from Kafka-server/deploy folder.
  3. deploy kube-discovery-server.yml from discovery-server/deploy folder.
  4. deploy kube-config-server.yml from config-server/deploy folder

note the values supplied to EUREKA_URI and KAFKA_ADDR under env section. We use service names of discovery server and kafka deployment and kube resolves their location from kube’s native service registry.

apiVersion: apps/v1
kind: Deployment
metadata:
name: config-deployment
labels:
app: config-server
spec:
selector:
matchLabels:
app: config-server
replicas: 1
template:
metadata:
labels:
app: config-server
spec:
containers:
- name: config-server
image: gcr.io/spring-cloud-config-server/config-server:latest
imagePullPolicy: Always
ports:
- containerPort: 8762
env:
- name: EUREKA_URI
value: http://eureka:admin@eureka-service:8761/eureka
- name: KAFKA_ADDR
value: http://kafka-service:9092
- name: spring.profiles.active
value: git
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP

5. deploy kube-client-config-first.yml from “client-config-first/deploy” folder.

6. deploy kube-client-discovery-first.yml from “client-discovery-first/deploy” folder.

Now all of our services are up and running in Kubernetes.

run the command “kubectl get all -o wide” to get list of all the resources deployed and the result will look something like below. Pick up the external-ip of config server. Go to your github project and from settings add a new webhook. Add the url http://<IP-of-kube>:port/monitor.

Github will make a POST api call to /monitor endpoint for any changes to source code. This will trigger an internal bus refresh within config server. Config server will push changes to kafka broker and clients will pick it up and thus we achieve an end to end auto refreshable configuration.

No Auto refresh ?? Sure alternatives are always there in next article.

--

--