A nice feature of Compose is the possibility to define dependencies between Docker containers. Compose starts containers in the defined order and evaluates the dependencies by the depends_on, links, volumes_from, and network_mode: “service:…” options. But, Compose only waits until a container is running, not if it’s ready because it does not know if and when a certain service in a container is in a ready state.
Normaly it is a good idea to implement such a readiness check in the service itself. But sometimes, this is not possible. A different solution is to use a small wrapper script in the Docker container itself, to synchronize the start-up of the services’s interdependencies.
The wrapper script takes a hostname and a port and checks periodically the availability via netcat. If the service becames available, the script will return success and the Spring Boot service will start. The wrapper script also has a timeout of 90 seconds. If the given hostname und port is not available until the timeout hits the wrapper script exits with an error. In this case the Spring Boot service will not be started and the Docker container stops.
I created a small Dockerfile to build the Docker image containing the Spring Boot service. The file contains instructions to copy the service’s .jar file and the wrapper script to the image and to install netcat, because netcat is not available in the debian-slim openjdk-10 base image:
As mentionend above, a Compose file defines the containers and their dependencies. I have created an example Compose file. The file defines a web container, which is the Spring Boot service, and a database container, which is the Postgres database. The web container defines a dependency to the database container via depends_on. The entrypoint of the web container is set to bin/sh with additional parameters via the entrypoint property. What happens here is that first, the wrapper script is called, which checks for the database to be ready and if successful starts the Spring Boot service. One can, of course, add multiple hostnames and ports to wait for.
When executing docker-compose up the wrapper script checks periodically for the database to become ready (Retrying…) and then starts the Spring Boot Application when the connection becomes available after 4 seconds.
Find the full, working project including the Spring Boot service, Dockerfile, docker-compose.yml and wait-for.sh on Github.
Sebastian Glahn is a Senior Software Engineer living in Cologne. He writes about Software Development, 3D-Printing, Robots and other stuff. He is also a maintainer of several open source projects.