Microservices Context-Based Configuration Approach

Deployment Challenges

Microservices have become very popular mainly due to the introduction of Docker containers and cloud resource schedulers such as Mesos. With all the advantages of modularity and distribution that they bring, microservices migrate considerable complexity from development to deployment:

  • An SSO is expected for uniform security access to services and for transferring the security context in service-to-service calls.
  • Services need to be packed into Docker images. Deployment instructions are essential to launch the composite application through a cloud resource scheduler.
  • Persistent state through disk volumes needs to be provisioned and services have to be launched physically close to their volumes and migrated along with the volumes.
  • Client-side or server-side service discovery is needed. Server-side discovery such as a dynamic DNS service (e.g. Mesos-DNS) can be used to map service instances to their symbolic name.
  • Centralized and dynamic configuration is required to avoid hard-coding sensitive data into Docker images and provide a context to the composite application that depends on the deployment profile.

Central & Dynamic Configuration

We will employ Zookeeper and confd to provide context-based and deployment-time configuration to Spring Boot – based microservices.

confd Templates

A typical Spring Boot application is configured through its application.properties located in the working directory or the classpath. E.g.

# HTTP service
# Zookeeper

This can be converted to a confd template where the base path of configuration keys depends on the activated profile. The profile name is pulled from an environment variable which renders the template friendly to Docker image parameterization:

# {{$base:= print "/profiles/" (getenv "PROFILE")}}

# HTTP service
service.instances={{getv (print $base "/http/instances")}}
# Zookeeper
zookeeper.connection.timeout={{getv (print $base "/http/zk.connection.timeout")}}

The configuration template is accompanied by a template resource config:

src = "application.properties.tmpl"
dest = "/opt/service/application.properties"
keys = [

Docker Image

The Dockerfile installs confd and pulls the configuration templates and the Spring Boot jar into the image:

FROM java:8 

ENV APP_HOME /opt/service
ENV APP_DATA = /var/lib/service

RUN apt-get update && apt-get install -y wget && rm -rf /var/lib/apt/lists/*

# Create user & group
RUN /usr/sbin/groupadd -g 1000 srv 
    && /usr/sbin/useradd -M -d /opt/service -g srv -s /sbin/nologin -u 1000 srv

# Add confd
RUN wget "https://github.com/kelseyhightower/confd/releases/download/v0.10.0/confd-0.10.0-linux-amd64" -O /usr/bin/confd 
    && chmod +x /usr/bin/confd && mkdir -p /etc/confd/conf.d 
    && mkdir -p /etc/confd/templates

ADD *.toml /etc/confd/conf.d/
ADD *.tmpl /etc/confd/templates/

ADD start.sh /
RUN chmod +x /start.sh

# Create directories
ADD app.jar $APP_HOME/
RUN chown -R srv:srv $APP_HOME $APP_DATA

USER srv
CMD /start.sh


The start.sh script will accept a Zookeeper URL and pass it to confd which runs once to create the final application.properties before launching the executable JAR:



if [ -z $ZK ]; then
    echo "Zookeeper URI is required."
    exit 1

# Convert ZK node list
IFS=',' read -ra ADDR <<< "$ZK"
for node in "${ADDR[@]}"; do
    nodes=$nodes" -node="$node

confd -onetime -backend zookeeper $nodes
cd $APP_PATH && java -jar app.jar

All that is left is to setup the actual values in Zookeeper for a ‘test’ profile:

[zk: localhost:2181(CONNECTED) 1] create /profiles ""
[zk: localhost:2181(CONNECTED) 2] create /profiles/test ""
[zk: localhost:2181(CONNECTED) 3] create /profiles/test/http ""
[zk: localhost:2181(CONNECTED) 4] create /profiles/test/instances "4"
[zk: localhost:2181(CONNECTED) 5] create /profiles/test/zk.connection.timeout "10000"

When the Docker instance is created, we pass 2 environment variables ZK=zookeeper_ip:2181 and PROFILE=test:

docker create -t -i 
    -p 8080:8080 
    --name service 
    -e "ZK=$1" 
    -e "PROFILE=$2" 

Any of the other backend storage supported by confd, such as etcd and consul, could have been used as well. In addition confd can be deployed as a daemon that reacts to configuration updates, regenerates the configuration file and optionally restarts the Spring Boot process.

The above approach allows decoupling the Docker image from context-specific deployments and it is compatible with multi-container deployment tools such as docker-compose and distributed deployment platforms such as Kubernetes and Mesos.

Leave a Reply

Your email address will not be published. Required fields are marked *