[Learn Microservices With Me] Setting Up A Config Server With Spring Cloud

[Learn Microservices With Me] Setting Up A Config Server With Spring Cloud

Hey everyone! Today, we'll be learning about config servers in a microservice architecture using Spring Cloud. As a practical example, we'll be extending the student and course API from our last guide to use a config server.

Prerequisites

To follow along with this tutorial, you should be able to follow along with our last guide on the basics of microservices and implementing them with Spring Cloud.

What is a Config Server

A config server is a microservice that other services use to import their configurations (in the case of Spring Cloud, settings that would go in your application.properties file). This is useful for sharing common configurations for your microservices and creating externalized configurations that can be updated without redeployment! The config server can read configuration files from one location (often a git repository) and then other services can read the configuration files from the config server and import them.

Implementation

Now that you understand the idea of a config server, let's implement it. To begin, we'll be starting from the code we left off from in the last guide which you can find here. From that starting point, we'll need to create a new ConfigServer module:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>io.john.amiscaray</groupId>
        <artifactId>MicroservicesClassroomExample</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>ConfigServer</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-server</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</artifactId>
        </dependency>
    </dependencies>

    <properties>
        <maven.compiler.source>21</maven.compiler.source>
        <maven.compiler.target>21</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

</project>

Notice the spring-cloud-config-server and spring-cloud-starter-consul-discovery dependencies. These will allow this microservice to act as a config server and register itself with Consul. Within this new Maven module, we need to add the following class to start up the Config Server:

@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(ConfigServerApplication.class, args);
    }

}

From there, we need to create a Git repository with the configs we want to share and then have this config server retrieve it. To do this, first, create a new Git repository and host it on GitHub. Within the repository, we'll put a simple application.properties file in the root directory configuring a debug logging level for our testing purposes:

logging.level.root=DEBUG

Once you committed the configuration and pushed it to GitHub, you'll need to create a GitHub personal access token with private repository access. With it, your config service can authenticate with GitHub to fetch configurations from the repository. To generate the token, go to Settings > Developer settings > Personal access tokens > Tokens (classic) > Generate new token > Generate new token (classic). Select the following permissions for the access token:

Now that you have the token, you can configure your config service's application.properties to access the GitHub repo for the configs:

spring.application.name=config-server
server.port=8888
spring.cloud.config.server.git.uri=https://github.com/john-amiscaray/MicroservicesClassroomConfigs
# Set the GitHub username and access token using environment variables
spring.cloud.config.server.git.username=${GITHUB_USER}
spring.cloud.config.server.git.password=${GITHUB_REPO_TOKEN}

Now, we can configure our other microservices' application.properties to import configurations from our config server like so:

spring.config.import=configserver:
# Same as the spring.application.name property of our config service
spring.cloud.config.discovery.service-id=config-service
spring.cloud.config.discovery.enabled=true

Along with that, we also need to add a spring-cloud-starter-config dependency in our root pom.xml for all of our services:

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

Now, we can start up Consul and our microservices and see that our Student Service, API Gateway, and Course Service applications have debug-level logging in the console:

Importing Microservice-Specific Configs

With our config server and our Git repository, we can also import configs for specific microservices. Within the GitHub repository containing our configs, let’s create new course-service and student-service directories with course-service.properties and student-service.properties files for our Course Service and Student Service respectively. We name these property files the exact same as the names of the services (listed in their respective application.properties files) so that the config server will know what to do with them. After adding these new files, the directory structure would look like so:

Within each properties file, let’s configure the data sources for its respective microservice:

# student-service configuration
spring.datasource.url=jdbc:mysql://localhost:3306/student
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=password
spring.jpa.hibernate.ddl-auto=create-drop
# course-service configuration
spring.datasource.url=jdbc:mysql://localhost:3306/course
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=password
spring.jpa.hibernate.ddl-auto=create-drop

After that, we need to update the application.properties file in our config server. These new properties specify subdirectories in our GitHub repository where configs can be:

spring.cloud.config.server.git.search-paths[0]=course-service
spring.cloud.config.server.git.search-paths[1]=student-service

With all that, we can commit to our GitHub repository, remove the configuration from the microservices' resources/application.properties files, re-run the microservices, and see that these data source configurations are being imported from the config server!

Profile Specific Configuration

As you might expect, we can create Spring profile-specific configurations for all our microservices. As you'd normally do for a traditional Spring application, we can define property files with a "-dev" suffix for configurations to use in a dev profile:

# student-service-dev.properties

spring.datasource.url=jdbc:h2:mem:student
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.h2.console.enabled=true
spring.jpa.hibernate.ddl-auto=create-drop
# course-service-dev.properties

spring.datasource.url=jdbc:h2:mem:course
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.h2.console.enabled=true
spring.jpa.hibernate.ddl-auto=create-drop
# application-dev.properties

logging.level.root=DEBUG
# application.properties

logging.level.root=INFO

With these new files, our repository should look like so:

Once we run all our services with the dev profile, you'll see that our microservices have debug-level logging and connect to H2 databases.

Conclusion

In this guide, we learned about what config servers are in a microservice architecture and how we can implement them with Spring Cloud. To review the work we did, you can have a look at the final code on GitHub. Happy coding!