Externalizing configuration

It’s a best practice that the Configuration details of Microservices should be kept outside of the code.
Build once - deploy many is a best practice that helps the development team to have repeatable builds and easier to debug code.

What does “Build Once, Deploy Many” Mean?

  • Build application binary once and deploy it on dev=>test=>prod environments.
  • When things work in dev environment and fail in test/prod, It’s easier to understand if the same binary is deployed on both environment.
  • When you follow the deployment pipeline consider answering following questions
    1.How often you build ?
    2.How many deploy time variables are introduced ?

If answers to above questions are not straight forward - Remember that there is a nightmare ahead waiting for you !!

How to externalize configuration ?

Microservice has various kinds of configuration - secrets, tokens, details of external components to connect to, business logic configs.

Categorized based on the frequency of changes to the configuration

  • Environment variables
  • Configuration files.
  • Database
  • Vault/Secrets store

At startup, microservices load the configuration from the external store. During runtime, microservices provide an option to - reload the configuration without having to restart the service. - restart to fetch new configuration.

Sometime it’s not always possible/required to provide reload the configuration without having to restart the service. Doing so might be over-engineering.

Spring cloud config Server

Spring Cloud Config project provides server and client-side support for externalized configuration in a distributed system.
Spring cloud config server also provides endpoint which can give config for consumption with non spring applications.

Spring Cloud Config Server features:

  • HTTP, resource-based API for external configuration (name-value pairs, or equivalent YAML/JSON content)
  • Encrypt and decrypt property values (symmetric or asymmetric)
  • Embeddable easily in a Spring Boot application using @EnableConfigServer
  • Config Client features (for Spring applications):
    1.Bind to the Config Server and initialize Spring Environment with remote property sources
    2.Encrypt and decrypt property values (symmetric or asymmetric)

How to use config-server and config-client

1. Config server

Config server holds all configuration properties for microservices deployed in distributed service. Every microservice when starts in the environment:
- Knows where config server is / Finds out where config server is.
- Ask for configuration from server using config-client/HTTP api and initializes itself.

Config server usually is a separate spring boot project. Enable config server by adding following dependency to your spring boot project

  <!-- config server -->
  <!-- https://spring.io/projects/spring-cloud -->
  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-config-server</artifactId>
    <version>2.0.2.RELEASE</version>
  </dependency>

Enable Config server:

@SpringBootApplication
@EnableConfigServer
@EnableDiscoveryClient //if service discovery is available
public class ConfigServerApplication {
   ...
}

Enable application.yml to get git based configuration:

spring:
 cloud.config.server.git.uri: https://github.com/xyz.git

Complete git config attributes : https://cloud.spring.io/spring-cloud-config/multi/multi__spring_cloud_config_server.html#_git_backend

With minimal configuration you will have config server serving configuration backed by git.
When you decide to release new configuration make a git commit/tag/branch appropriately. The config server periodically fetches configuration from git based backend.

There are various strategies available to release configuration w.r.t your application release.

  1. Branch based release
  2. Tag based release

2. Config client

Enable spring boot applications to read configuration from config client:

  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-config-client</artifactId>
    <version>2.0.2.RELEASE</version>
  </dependency>

bootstrap.yaml/properties or application.yaml/properties with basic details of config server.

 # client name with which config is stored with config server
 spring.application.name=a-bootiful-client
 spring.cloud.config.uri=http://localhost:8888

Git backend

Configuration separate from code is usually tracked in a version control system. Storing configuration in a separate repository where you track your source code is recommended. Spring cloud config also provided git as a backend option and it’s easy to configure.

Remember here git is storage as deployment unit for your production services configuration.

One approach for storing config is as following :

Directory structure

  • application.properties # Applicable for all environments.
    • application-dev.properties # Environment level commons across all services.
      • service1-dev.properties # Overrides specific to the service for one environment.
      • service2-dev.properties
    • application-qa.properties

S3 as backend for configuration

I am not sure why people chose git as backend for configuration, but my motivation behind moving deployment config to S3 has been because of following

  • Separate source code from deployment
  • Storage/Retrieval is not git’s primary use case.

Why S3 ?

Following are specific reasons to not use git and Use S3 for config storage

  • Not exposing git/source control to production deployments environment.
  • Avoiding copying/cloning or maintaing a git server in prod environments.
  • Using storage for storage and version control for version control (Single Responsibility principle)
  • Deployment pipeline defines when to push config / Not your source or code review system

How to use ?

I created a config server implementation using S3 as backend for configuration. This includes complete implementation to USE s3 as backend for config service.

I am putting this project to gumroad with price $5 for any support that you would need https://gum.co/FDMDmr

If you need code for this project and no support, please email me on salunkenagesh14@gmail.com

You need following to use S3 as config backend.

  1. Maintain config as you want to in your code/version control.
  2. Add extra S3 repository configuration in your code.
  3. Write a deployment script that copies config to the S3 bucket.
  4. Update release config.meta file that defines release version for the config - using deployment script.

Config directory structure can be same as discussed above for git or you can define your own.
For now, I have not specifically created a dependency. [ This is in plan ]
You can follow similar approach to maintain your own implementation of the S3 repository till this is available as dependency.

Thanks for Reading

-

Nagesh