It’s no secret I’m a big fan of Docker, and one of its biggest strengths is the ability to compose a fully functional local development environment that simulates a real system in minutes, helping us achieve Dev/Prod parity without sacrificing simplicity.

For example, you may want to spin up your environment in order load/resilience test it in isolation, say as part of a CI process. I’ve blogged about this before, but I didn’t mention one small annoyance – Docker Compose will build a dependency tree, and properly wait for linked services to become available, but it cannot – and will not – understand if the service within the container is up and running. This is left to the application to handle, and probably rightly so.

Unfortunately, this means a little extra work, implementing hacks like this:

echo ">> Waiting for postgres to start" WAIT=0 while ! nc -z $POSTGRES_HOST 5432; do sleep 1 WAIT=$(($WAIT + 1)) if [ "$WAIT" -gt 15 ]; then echo "Error: Timeout wating for Postgres to start" exit 1 fi done

Fortunately, there is a better way…

The Solution: Dockerizing your test harness

Bruno Rocha has a nice little bash script that you can use to solve the problem, and whilst it gives you some flexibility in how you determine that a service is “up”, you will need to install any prerequisites (like telnet, curl etc.) and script this yourself for each project.

But there is a simple way: as of today, v0.1.0 of Jason Wilder’s Dockerize has the capability to wait for dependent services (on tcp, http or https), and installing it is a cinch. Simply add the following to your Dockerfile:

RUN apt-get update && apt-get install -y wget RUN wget https://github.com/jwilder/dockerize/releases/download/v0.1.0/dockerize-linux-amd64-v0.1.0.tar.gz RUN tar -C /usr/local/bin -xzvf dockerize-linux-amd64-v0.1.0.tar.gz

Once you’ve installed dockerize in the dependent container you can simply prepend your command with “dockerize”, supplying any hosts you need to wait on:

dockerize -wait tcp://web:80 -wait http://web:80

Your Docker Compose file will look something like this:

api: build: . ports: - "8000:80" expose: - "80" test: build: test command: dockerize -wait http://api:80 go test -v ./... links: - api:api

9 times out of 10 you are waiting on a service to start listening on a port, so this should be all you need most of the time.

Dockerize is a neat little project that solves a bunch of Docker pain points around things like run time configuration and log streaming, and now it can make your test process even simpler!

Example Docker Compose Project

To demonstrate how all of this stuff works, I’ve created a simple Docker Compose setup. It is composed of front-end API that deliberately takes 5 seconds to start up, and a test harness that hits the API 100 times, failing if it receives any non-20x response codes. You can see the before and after in branches “fail” and “dockerize” respectively.

Head on over to the GitHub repo to see this black magic in action.

References/Further Reading