One thing that quickly adds up when building a microservice-based solution are all the properties that must be managed. It's one thing to manage a single application's application.yml file, and make tweaks and adjustments. But working with all these services, and having to jump to the correct file underneath each application's src/main/resources folder quickly becomes daunting. On top of that, when trying to make changes or adjustments, it is easy to overlook the settings of one microservice.
A key piece of the twelve-factor app (https://12factor.net/) is externalizing configuration. We already took a big step using Spring Boot's powerful property support. But Spring Cloud brings another key technology to the table that takes property support to the next level--Spring Cloud Config Server.
The Config Server let's us put all the properties into a centralized location, and feed them via an application to our existing microservices.
To see how, let's dive into creating one. First, go to http://start.spring.io and select Config Server (along with our other favorite settings).
When we do that, we get a familiar Gradle build file containing the following dependencies:
buildscript { ext { springBootVersion = '2.0.0.M5' springCloudVersion = 'Finchley.M3' } ... } ... dependencies { compile('org.springframework.cloud:spring-cloud-config-server') } dependencyManagement { imports { mavenBom "org.springframework.cloud:spring-cloud-
dependencies:${springCloudVersion}" } }
We can explain this preceding build file as follows:
- spring-cloud-starter-config-server is only needed to run a config server, not a config server client
- The dependencyManagement shows us the release train of Spring Cloud we are using
In a way very analogous to the Hystrix Dashboard, we will create a Config Server:
@SpringBootApplication @EnableConfigServer public class LearningSpringBootConfigServer { public static void main(String[] args) { SpringApplication.run( LearningSpringBootConfigServer.class, args); } }
This preceding app isn't hard to unravel:
- @SpringBootApplication marks this as a Spring Boot application. Since this is the cornerstone of the rest of our microservices (including Eureka), it doesn't use Eureka.
- @EnableConfigServer launches an embedded Spring Cloud Config Server, full of options. We'll use the defaults as much as possible.
- It has a public static void main to launch itself.
With that, we just need a couple of property settings in application.yml:
server: port: 8888 spring: cloud: config: server: git: uri: https://github.com/gregturn/learning-spring-boot-
config-repo
- Let's set its port to 8888, since that is the default port for Spring Cloud Config clients
- By setting spring.cloud.config.server.git.uri to https://github.com/gregturn/learning-spring-boot-config-repo, we tell the Config Server where to get its property settings for all the other services
That's it! That's all we need to build a Config Server. We can launch it right now, but there is one thing missing--all the other properties of the application!
To configure properties for our Eureka Server, we need to add a eureka.yml that looks like this:
server: port: 8761 eureka: instance: hostname: localhost client: registerWithEureka: false fetchRegistry: false serviceUrl: defaultZone:
http://${eureka.instance.hostname}:${server.port}/eureka/
If you'll notice, this is the exact same setting we put into the Eureka Server's application.yml earlier in this chapter. We are simply moving it into our config repo.
To make our Eureka Server talk to a Config Server, we need to add this to its build file:
compile('org.springframework.cloud:spring-cloud-starter-config')
What does this single dependency do?
- spring-cloud-starter-config empowers the Eureka Server to talk to the Config Server for property settings
There is a certain order by which Spring Boot launches things. Suffice it to say, property sources must be read early in the Spring lifecycle in order to work properly. For this reason, Spring Cloud Config clients must have a bootstrap.yml file. The one for the Eureka Server must look like this:
spring: application: name: eureka
Not a whole lot needs to be in here, but at a minimum, spring.application.name needs to be set so that the Config Server knows which property file to fetch from its config repo. By default, Spring Cloud Config clients will seek {spring.application.name}.yml, so in this case, eureka.yml.
Assuming we have committed eureka.yml to our GitHub-based config repo and launched the config server, we can actually see what is served up:
Let's tear apart the details of this preceding screenshot:
- http://localhost:8888/eureka/default looks up spring.application.name=eureka, and finds the default state of things
- The name eureka is at the top along with information like its label and SHA version
- The config server entry lists the available Spring property sources (eureka.yml) along with each property found in that property source
In essence, the Spring Cloud Config Server is Yet Another Way™ to craft a property source that the Spring Framework can intrinsically consume.
Next, let's move all the properties for images from its application.yml file into the config repo's images.yml like this:
eureka: client: serviceUrl: defaultZone: http://localhost:8761/eureka/ spring: cloud: stream: bindings: output: destination: learning-spring-boot-comments group: comments-service content-type: application/json
With all these settings moved to the Config Server's images.yml file, we can replace the application.yml with the following src/main/resources/bootstrap.yml file:
spring: application: name: images
Earlier in this chapter, spring.application.name=images, along with all the other settings, were combined in application.yml. To work with Spring Cloud Config Server, we split out spring.application.name, and put it inside bootstrap.yml.
We can do the same for comments by moving all of its property settings into comments.yml. You can see it at https://github.com/gregturn/learning-spring-boot-config-repo/blob/master/comments.yml, if you wish, along with hystrix-dashboard.yml.
Instead, we'll give comments the following src/main/resources/bootstrap.yml file:
spring: application: name: comments
And do the same for our Hystrix Dashboard app:
spring: application: name: hystrix-dashboard
You know what's truly amazing about all this? We don't have to touch the services. At all.
Notice the little 10 second delay in the bottom-right corner of the preceding screenshot? The Config Server needs to be up and operational before any other services start, or they'll fall on default settings.
Using the Multirun plugin, if we launch everything, we should have a nice little system up:
Each service, when it launches, should show something like this:
Without touching a line of code, and simply moving most of what we've already written into another location (or into bootstrap.yml), we have extracted the entire configuration of our social media site to a remote location, making configuration a snap to maintain.
So, is our little snap-a-picture social media platform ready for IPO? Heh, maybe not yet. But we've made a major enhancement that will make us more stable and ready for growth by breaking things up into microservices without breaking the bank.
Spring Cloud Config Server currently supports GitHub, GitLab, and Bitbucket out of the box. This means that you can quickly put your configuration on a publicly hosted GitHub repository, but you can also install GitLab inside your data center, and point there, instead, to reduce the risk of public repository outages.