07 October 2020

How to make a container wait for other container in docker compose?

 Dear readers

 Another day, another research is done. This time, it is related to docker, specificly docker compose

 For those who don't know, docker compose is a way to start one or more container with certain attributes or parameters, so that you don't need to execute:

docker run .....

everytime. Instead, you simply run:

docker-compose up

or similar command after you complete writing docker-compose.yml

 The problem arise when you need to run something like this:

version: "2"
services:
  database:
    image: mysql

  app:
    image: custom_app

Let's put aside what the app is doing and how app connect to mysql. The problem is how make sure mysql run first and fully ready before app tries to connect?

The first solution that comes up to mind is to use depends_on like below:


version: "2"
services:
  database:
    image: mysql

  app:
    image: custom_app
    depends_on:
      - database

 
Sounds solid? Yes, on the surface. Try to run that and you will realize that what depends_on really means is that "wait until container A run then run B". The meaning of "run" doesn't necessarily means "ready", especially if you are dealing with database engine that does whole lot stuffs beside just "start".

I face similar situation and I come up with really simple solution (inspired by discussion in Stackoverflow here). So, here is my solution


version: "2"
services:
  database:
    image: mysql

  app:
    image: custom_app
    depends_on:
      - database

    entrypoint:
      - "/bin/sh"
      - -c
      - |
        sleep 30 && \
        /usr/local/bin/the_app

What I did are:
- I declare that I want to override entrypoint in the image. Think entrypoint as init script in Linux boot sequence, so it is execute right after container is up
- Execute sh as the shell of the sub sequence command. Ok why sh? why not bash? it is simply due to sh is more common to found in docker hub images compared to bash
- Run sleep for 30 seconds. I am not using more sophisticated ways, say using nc or mysql CLI, since I can predict how long it takes for mysql to be ready. Of course, your mileage may vary and this solution might be inappropriate for you
- After sleep succeed, then execute the app binary inside the container image. Of course, you need to make sure that said binary is already inside the image

And.... what is that the | (pipe symbol) use for? This is to declate that subsequence commands are written in multi lines. So without this, if you insist to use multi lines command like above (ended by \ after every line, of course), you will get failed.

This is a simple yet elegant solution for me, hope it also works for you.

Cheers and regards,

Mulyadi

How to execute multiple commands directly as ssh argument?

 Perhaps sometimes you need to do this: ssh user@10.1.2.3 ls It is easy understand the above: run ls after getting into 10.1.2.3 via ssh. Pi...