What is docker-gen
docker-gen is tool which monitors Docker for events via Dockers remote API and then writes to a file according to a template.
For example; we are interested in the events generated by Docker for when a container is created, deleted, started or stopped. Each event contains information relevant to the container which generated it.
This information can be used to generate configuration files for reverse proxies, centralized logging, service discovery, log rotation and so forth. You no longer need to worry about which IP address a container has, or about its port number assignments and mappings. This makes it ideal for configuring a service to provide access to other container services.
The rest of this article will be talking in terms of configuring a reverse proxy server for web content.
Using docker-gen inside a container
docker-gen could already be used inside a container before version 0.3.4; but it required everything to be running together inside that one container (work arounds were available but they were clunky and messy).
For those of us with the one-process-per-container philosophy, this isn’t very tidy or appealing. It could also potentially cause future issues when trying to scale a fleet of contaners up.
Previously docker-gen could only notify an already running process (or rather execute a new process to request a reload, eg:
nginx reload); hence why everything needed to be running inside one container.
--notify-sighup flag allows docker-gen to send a HUP signal to a specified container (equivalent to running:
docker kill -s HUP container-ID), which should cause the process to reload its configuration.
Combining this with putting our generated configuration files on a Docker volume, it is a very powerful tool for providing and managing access to containers delivering web services.
Setting up the container
We need a docker-gen binary; you can either get one from the docker-gen github page, or build your own. Here we build our own so the build flags can be customised to create a binary file which is smaller in size (
$ go get -d github.com/jwilder/docker-gen $ cd /path/to/src/github.com/jwilder/docker-gen $ DGTAG=$(git describe --tags --abbrev=0 | sed 's/^v//' | sed 's/\+.*$$//') $ go build -ldflags "-s -X main.Version $DGTAG" -o docker-gen-bin $ cd /path/to/port-eighty/docker-gen $ mv /path/to/src/github.com/jwilder/docker-gen/docker-gen-bin docker-gen
FROM ubuntu:14.04 MAINTAINER JustAdam <email@example.com> RUN apt-get update && \ apt-get upgrade -y ADD docker-gen /usr/bin/docker-gen ENV DOCKER_HOST unix:///docker.sock VOLUME ["/etc/docker-gen/", "/share/"] WORKDIR /etc/docker-gen/ CMD ["/usr/bin/docker-gen", "-watch", "-only-exposed", "-notify-sighup=REVERSE_PROXY_CONTAINER_ID", "reverse-proxy.tmpl", "/share/reverse-proxy"]
DOCKER_HOST environment variable tells docker-gen how to connect to Docker. This will be shared from the host via a volume.
Two addditional volumes are created; one for docker-gen’s files and another for our reverse proxy service.
docker-gen will then run in watch mode and will monitor Docker events for only containers that have exposed ports. Now whenever a container is started, stopped etc., docker-gen will write to the file
/share/reverse-proxy using the template
Command run down
After you have built the docker-gen binary and created the Dockerfile in the same directory, you can run these commands to get a working docker-gen container. The locations for the template and output files is assumed to be in the same directory as the build file (but they could of course be anywhere).
Create a template file for docker-gen
$ mkdir templates $ vim templates/reverse-proxy.tmpl
Create an output file for docker-gen
$ mkdir share $ touch share/reverse-proxy
Build the image
$ docker build -t justadam/docker-gen .
Create and start the container
$ docker run -d --name docker-gen -v /var/run/docker.sock:/docker.sock -v $(pwd)/templates/:/etc/docker-gen/ -v $(pwd)/share/:/share:rw justadam/docker-gen
And now your container
REVERSE_PROXY_CONTAINER_ID will be sent a HUP signal every time a relevant container is started or stopped (don’t forget that that container needs to also have /share/ specified as a volume, and be configured to read its configuration files from there).
Next time we’ll use this container and build a more real world example.