Configuration as Code With Docker and Spring Boot
Learn how this DevOps practice makes life easier for operations, as well as delivering increased velocity to the software lifecycle.
Join the DZone community and get the full member experience.
Join For FreeWhat Is Configuration as Code?
Configuration as code is a DevOps practice that promotes storing of application configuration as code within source code repository. Few key benefits that this brings is that
Versioning of application configuration
Storing the application configuration in a source code repository such as Git allows us to see what configuration changes were made over a period of time and who made those changes.
By using branches, you can isolate changes that are under development without affecting the production application.
Traceability
Versioned and managed properly, it can provide tracking of what version of configuration is deployed in various environments.
Make configuration changes without requiring to re-deploy application
Operators would love you for this. Operators can throttle the logging level up in the configuration settings file to troubleshoot a production issue without having to redeploy the application.
Implementation
Now that we understand what configuration as code is and what benefits it brings, let's take a look at how we would implement this with Docker and Spring Boot. Spring Boot provides support for keeping configuration settings in "yml" files instead of using a properties files, by default spring boot looks for these "yml" files under classpath, but you can specify an explicit location by setting "spring.config.location" property via command line during application startup.
For the purpose of this article, we have stored all default configurations for this demo application in application.yml and environment specific settings are stored in application-{environment label}.yml, as shown in the screen capture below.
Since we are running the Spring Boot app in Docker, we can use an "entrypoint.sh" bash script to pull default configuration and environment specific configuration files from a Git repository onto directory named "configs" as shown below using the wget command.
echo "Downloading configuration files from git repository"
wget $GIT_REPO/$LABEL/$REL_PATH/$APP_NAME.yml
wget $GIT_REPO/$LABEL/$REL_PATH/$APP_NAME-$PROFILE.yml
echo "copying yml files to configs directory"
cp $APP_NAME.yml ./configs/$APP_NAME.yml
cp $APP_NAME-$PROFILE.yml ./configs/$APP_NAME-$PROFILE.yml
As you can see from the above snippet,
The "GIT_REPO" environment variable is used to pass the Git repository URL where the configuration files are stored.
The "LABEL" environment variable maps to the branch. In development/test/staging phases you might use "MASTER," when you release it to production you'll want to create a branch and use that branch label. This allows us to isolate changes that are under development from impacting the production application.
The "REL_PATH" environment variable is used to point to the location of configuration files in the repo relative to the repository path.
The "APP_NAME" environment variable maps to the file name; in the demo app I'm keeping the default name "application."
The "PROFILE" environment variable maps to the name of the environment in which the application is running. Spring Boot will merge the default settings and environment-specific settings and provide it to your application.
(Note: If your Git repository requires authentication, you can use ssh or HTTPS protocol with a username and password to authenticate with the Git repository. The Docker container can obtain the credentials required to connect to the Git repository during startup.)
Once the configuration files are downloaded from the repository onto the "configs" directory in the container, we specify this location via application startup using the "spring.config.location" property, as shown in the snippet below.
exec java $JAVA_OPTS -jar /app.jar --spring.config.location="./configs/$APP_NAME.yml, ./configs/$APP_NAME-$PROFILE.yml"
Running the Demo Application
Let's run this demo application with staging settings. as shown in the command below.
docker run -d -p 80:8080 -e PROFILE=staging -e GIT_REPO="https://raw.githubusercontent.com/rprakashg/blog-demos" \
-e LABEL=master -e REL_PATH="externalize-config-demo/src/main/resources" \
-e APP_NAME="application" rprakashg/externalize-config-demo
The demo application simply displays the configuration information, and you can see from the screen capture below that the application has picked up default settings as well as staging environment-specific settings.
Let's run the same demo application, now with production settings, as shown in the snippet below.
docker run -d -p 80:8080 -e PROFILE=production -e GIT_REPO="https://raw.githubusercontent.com/rprakashg/blog-demos" \
-e LABEL=master -e REL_PATH="externalize-config-demo/src/main/resources" \
-e APP_NAME="application" rprakashg/externalize-config-demo
As you can see from the screen capture below, the application now picks up default as well as production-specific settings.
Source Code
All the code for the demo application is available in this GitHub repository.
Conclusion
Configuration as code is a good practice that all development teams practicing DevOps should follow. Many of the benefits gained from implementing configuration as code can help increase velocity and deliver new features to your customers in production faster and help operators run and manage application in production efficiently.
Opinions expressed by DZone contributors are their own.
Comments