Skip to content

Instantly share code, notes, and snippets.

@syrm
Created November 25, 2021 13:22
Show Gist options
  • Save syrm/c5926c0af43b813d8b2ab4da22e61d69 to your computer and use it in GitHub Desktop.
Save syrm/c5926c0af43b813d8b2ab4da22e61d69 to your computer and use it in GitHub Desktop.
Docker Compose service depends

Alors par avance désolé si c’est connu de tous, je débarque sans doute mais bon. Pour ceux qui utilisent docker-compose vous devez avoir souvent rencontré un soucis de dépendance de démarrage des différents services. Par exemple vous avez un programme qui a besoin que la base de données soit disponible pour se connecter, il faut donc que le service de votre programme se lance après celui de la base de données.

La solution simple que l’on trouve partout est de mettre dans votre docker-compose l’instruction depends_on, ansi vous pouvez avoir quelque chose du genre :

services:
   program:
      build: .
      depends_on:
         - db

   db:
      image: postgres:12-alpine

Mais souvent ça n’est pas suffisant, parce que quand le service db est démarré, la base de données n’est pas immédiatement disponible, ça peut prendre plusieurs dizaines de secondes pour que la base de donnée ai correctement terminée de démarrer et accepte des connexions.

Du coup on entends souvent de parler des solutions du type wait-for-it (et ce même sur la doc officielle : https://docs.docker.com/compose/startup-order/) L’idée du wait-for-it c’est de modifier la command de démarrage de notre service programme pour qu’au lieu de se lancer directement, c’est un petit utilitaire qui va le lancer après avoir fait des vérifications. Exemple :

services:
   program:
      build: .
      command: ["./wait-for-it.sh", "db:5432", "--", "./program"]
      depends_on:
         - db

   db:
      image: postgres:12-alpine

Ici on voit donc que le script wait-for-it va vérifier si il peut faire une connexion sur le service db sur le port 5432, si c’est le cas il va lancer la commande ./program

Sauf que... là encore ça n’est pas parfait, en effet il y a des cas ou on peut se connecter à la base de données mais que son initialisation n’est pas terminée et Postgres à même dans son image docker un système de double reboot après la première initialisation.

Du coup tout ceci nous amène à la solution que j’ai trouvé, qui hélas n’est même pas documenté sur https://docs.docker.com/compose/startup-order/ alors que selon moi c’est LA bonne solution.

Tout le principe se repose sur le fait d’utiliser la feature healthcheck (https://docs.docker.com/engine/reference/builder/#healthcheck) Et je cite la documentation pour bien comprendre à quoi ça sert :

The HEALTHCHECK instruction tells Docker how to test a container to check that it is still working. This can detect cases such as a web server that is stuck in an infinite loop and unable to handle new connections, even though the server process is still running.

Du coup on modifie notre docker-compose comme suivant :

services:
   program:
      build: .
      depends_on:
         db:
           condition: service_healthy

   db:
      image: postgres:12-alpine
      healthcheck:
         test: ["CMD", "pg_isready"]
         timeout: 5s
         retries: 3

On configure le healthcheck sur le service db (c’est le healthcheck officiel inclus dans l’image Postgres) et ensuite on configure le service program pour qu’il soit dépendant du service db AVEC la condition service_healthy

Et voilà, on a un système clean de dépendance :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment