At EA we’re using Docker extensively. We’re deploying containers to production and we’re also running those containers locally for development and testing purposes. Our services are running in multiple containers and spinning up one service, usually involves spinning up multiple other containers. The most common scenario is running a service that depends on mysql
and/or redis
.
To orchestrate the containers that we run locally, we’re using docker compose. While docker-compose
does a great job at running multiple containers and connecting them, it has a big flaw: it cannot wait for a service to be ready before starting the next one.
The problem is not impossible or, in most cases, it’s not even hard to solve but it requires a bit of infrastructure to make one service wait for another.
A frequently used solution is the wait-for-it script which checks if a TCP port is available. Another solution is to use curl
or wget
to poll an endpoint on the dependency container. A third solution that might not be available for every container, is to use some sort of SDK to do the check; in the case of mysql
, you can use the mysql
command line.
If a container runs more than one service, or it’s ready state is not a determined by a single state, then the burden of checking everything falls on the dependent. It also ties the two containers - if the dependency changes, the dependent might have to update the checks.
I wrote ruready
to help me solve the readiness orchestration problem. ruready
is a tool that exposes a single, stable HTTP endpoint to check the status of a dependency container.
The advantage of having a single endpoint, hosted on the dependency machine is that you only have to update the dependency container when this changes. Any dependent container will be unaffected.
To run ruready
in a container you have to make it available to the container by downloading it when the container starts, by copying it at build time, or by mounting a folder with it, and then specify a command that checks the status of the container.
In my case, since I need to wait for mysql
to become available, I can run: ruready -c mysql -- --host=localhost --port=3306 --user=u --password=p --execute=quit
. While the program is running, the HTTP endpoint <host>:8099/ready
tells me if the machine is ready. If it returns 200 (OK)
then the machine is ready. If it returns anything else, the machine is not ready.
Then, from a dependent container, I can poll the /ready
endpoint until the machine becomes available.
To learn more about ruready
and see full, working examples, check out the Github project: https://github.com/victorhurdugaci/ruready.