Reusable containers with confd

I recently had the need to populate a file in a docker container based upon whether or not the container is in production or development. I eventually came across confd which let me populate data in files based upon particular environment variables. While confd excels with distributed key value stores, my needs (and infrastructure) is at a much simpler level.

Confd requires a few folders to store a toml (/etc/confd/conf.d/) and a template file (/etc/confd/templates/). When confd runs, it will look at the contents of each toml file in the conf.d directory and process them according to their instructions.

In my repository example, I am wanting a container to say hello to me when it senses a NAME environment variable and print out the current datetime. If no environment variable is set, only the datetime is printed out. To do this, I must create the toml file to look like this:

src = "echo.tmpl"
dest = "/echo"

This file is instructing confd to generate the echo file, place it in the root (/) and use /etc/confd/templates/echo.tmpl as the contents.

When we are building the container, we must include these configuration files and ensure confd is ran to generate the destination file. My example Dockerfile is doing just that by including all of the files in the container and running the docker-entrypoint script which is basically running confd and the newly generated file.

 andrew@wipplerxps > ~/git_repos/confd $  docker build -t blog-confd .
Sending build context to Docker daemon 57.34 kB
Step 1/9 : FROM centos:7.4.1708
 ---> 5076a7d1a386
Step 2/9 : LABEL maintainer ""
 ---> Using cache
 ---> d712b31f7449
Step 3/9 : RUN mkdir -p /etc/confd/{conf.d,templates}
 ---> Running in f340bdcdf973
 ---> 1f0faa9b962f
Removing intermediate container f340bdcdf973
Step 4/9 : COPY docker/confd/ /etc/confd/
 ---> fb16dffc63ac
Removing intermediate container 133128cb7fc1
Step 5/9 : ADD /usr/local/bin/confd
Downloading 17.61 MB/17.61 MB
 ---> a62b388274e6
Removing intermediate container 3f9ec343a5ab
Step 6/9 : RUN chmod +x /usr/local/bin/confd
 ---> Running in 1489dd02ea45
 ---> ab99a5fc5f95
Removing intermediate container 1489dd02ea45
Step 7/9 : COPY docker/ /var/local/
 ---> 16906971c8ef
Removing intermediate container 7a17a8e17e22
Step 8/9 : RUN chmod a+x /var/local/
 ---> Running in 1562a6d06432
 ---> f963372159b1
Removing intermediate container 1562a6d06432
Step 9/9 : ENTRYPOINT /var/local/
 ---> Running in 1b7e12c38b4c
 ---> f7d260597e0a
Removing intermediate container 1b7e12c38b4c
Successfully built f7d260597e0a
 andrew@wipplerxps > ~/git_repos/confd $  docker run blog-confd
2017-11-28T20:05:24Z 0931113b25f4 /usr/local/bin/confd[7]: INFO Backend set to env
2017-11-28T20:05:24Z 0931113b25f4 /usr/local/bin/confd[7]: INFO Starting confd
2017-11-28T20:05:24Z 0931113b25f4 /usr/local/bin/confd[7]: INFO Backend source(s) set to 
2017-11-28T20:05:24Z 0931113b25f4 /usr/local/bin/confd[7]: INFO Target config /echo out of sync
2017-11-28T20:05:24Z 0931113b25f4 /usr/local/bin/confd[7]: INFO Target config /echo has been updated
The current time is: Tue Nov 28 20:05:24 UTC 2017
 andrew@wipplerxps > ~/git_repos/confd $  docker run -e NAME="Andrew Wippler" blog-confd
2017-11-28T20:05:52Z 223f28e8d18f /usr/local/bin/confd[7]: INFO Backend set to env
2017-11-28T20:05:52Z 223f28e8d18f /usr/local/bin/confd[7]: INFO Starting confd
2017-11-28T20:05:52Z 223f28e8d18f /usr/local/bin/confd[7]: INFO Backend source(s) set to 
2017-11-28T20:05:52Z 223f28e8d18f /usr/local/bin/confd[7]: INFO Target config /echo out of sync
2017-11-28T20:05:52Z 223f28e8d18f /usr/local/bin/confd[7]: INFO Target config /echo has been updated
Hello Andrew Wippler
The current time is: Tue Nov 28 20:05:34 UTC 2017
 andrew@wipplerxps > ~/git_repos/confd $

While it is fun to say hello to yourself once in a while, I am using confd to modify an nginx.conf. When I pass in the SSL environment variable, nginx will listen on port 443 with a self signed cert and forward all HTTP traffic to HTTPS. Obviously in production, I want to use a real SSL cert. Using confd allows me to have the same docker container in development and production – the only difference being a configuration change.