Attendre l’initialisation d’un conteneur MySQL

Lorsqu’un conteneur MySQL est lancé pour la première fois (plus précisément, quand son dossier mysql n'existe pas), ce dernier va, entre autres :

  1. initialiser son dossier de données ;
  2. démarrer un serveur temporaire inaccessible de l’extérieur ;
  3. créer l’utilisateur root ;
  4. le cas échéant, créer la base MYSQL_DATABASE et l’utilisateur MYSQL_USER ;
  5. exécuter tous les scripts (sh ou sql) du dossier /docker-entrypoint-initdb.d ;
  6. stopper le serveur temporaire.

C’est seulement une fois ces étapes terminées qu’un serveur écoutant le port 3306 est lancé, toute tentative de connexion antérieure échouerait donc. Pour s’assurer de la disponibilité de MySQL, le plus simple est de tester le port jusqu’à ce qu’il soit disponible (ainsi on n’a pas besoin des identifiants de connexion).

Idéalement, on voudrait tester le port 3306 de l’intérieur du conteneur puisque cela n’imposerait ni de le publier, ni aux développeurs d’installer un outil pour réaliser ce test. Si vous pensez à Netcat, cet utilitaire n’est malheureusement pas disponible dans le conteneur. Par contre ce dernier étant basé sur Debian, il est garanti d’y trouver Bash qui nous offre une solution basée sur les redirections : si le chemin spécial /dev/tcp/host/port est utilisé, Bash va tenter d’ouvrir le socket TCP correspondant.

De l’intérieur du conteneur, echo >/dev/tcp/127.0.0.1/3306 ne renverra un code de succès que si le port 3306 est ouvert. Sinon, il échouera en indiquant

bash: connect: Connection refused
bash: /dev/tcp/127.0.0.1/3306: Connection refused

Puisque ce message d’erreur est expecté, on peut le cacher grâce à 2> /dev/null qui redirige la sortie d’erreur standard vers /dev/null. On se retrouve avec

echo 2> /dev/null >/dev/tcp/127.0.0.1/3306

qu’on veut exécuter jusqu’au succès. Pour cela nous allons utiliser la boucle until de Bash, et attendre deux secondes entre chaque tentative grâce à la commande sleep :

until echo 2> /dev/null >/dev/tcp/127.0.0.1/3306; do sleep 2; done

Reste à exécuter ce script dans le conteneur démarré. Comme il s’agit d’un script Bash, on va utiliser la commande bash avec son option -c à qui on va passer notre script sous forme de chaîne :

docker exec CONTAINER bash -c 'until echo 2> /dev/null >/dev/tcp/127.0.0.1/3306; do sleep 2; done'

Une fois terminée, vous êtes certain de pouvoir accéder à votre conteneur MySQL !