Docker Compose est un outil d’orchestration de conteneurs.

Question:

C’est pas ce que fait déjà Docker, de gérer des conteneurs ?

Pour comprendre pourquoi on utilise un outil supplémentaire, il est utile de revenir à la page précédente, où on a fabriqué et lancé une image Docker. Le conteneur avait un nom, un mapping de ports et un montage. La commande pour le lancer était la suivante :

docker run -d --name quentin -p 80:80 -v quentin:/var/www/html nginx:quentin

C’est déjà long, et encore, il n’y a que quelques options. Imagine qu’à chaque mise à jour, il faille taper la même commande pour relancer le conteneur! C’est long et pénible, il y a des risques d’erreurs, la « configuration » du conteneur n’est jamais stockée quelque part…

Et c’est là qu’intervient Docker Compose. Compose permet de décrire à quoi doit ressembler un conteneur dans un fichier de configuration, et de gérer son cycle de vie avec des commandes simples.

C’est génial, parce que le fichier de configuration peut être versionné sur Git, partagé entre plusieurs machines et modifié collaborativement, contrairement à une grande ligne de commande.

Compose est particulièrement indiqué pour les applications avec plusieurs conteneurs. Par exemple, Mattermost n’est pas un seul conteneur : c’est un serveur web et une base de données. Compose permet de décrire les dépendances entre ces conteneurs, et de les lancer d’un seul coup.

Compose est aussi très utile pour déclarer des volumes ou des réseaux Docker, dont on reparlera avec Traefik.

Enfin, toutes les commandes Compose permettent de vérifier les journaux d’une application, de lister ses processus, de recréer intelligemment les conteneurs quand il y a besoin… Bref, on ne rentre pas dans tous les détails, place à la pratique!

Les fichiers de configuration de Docker Compose sont au format YAML. C’est un format qui exprime la « hiérarchie » par des espaces. Un exemple simple où je veux décrire des groupes de musiques et des salles de concert :

snippet.yaml
artists:
  - title: System of a Down
    year: 1992
    albums:
      - ...
  - title: Mansfield.TYA 
    year: 2002
    
theaters:
  maroquinerie:
    title: La maroquinerie
  trianon:
    title: Le Trianon

On voit qu’il y a deux « blocs » de premier niveau, et qu’à chaque décalage on décrit quelque chose de plus précis. Ce qu’il y avant un : s’appelle une clé et ce qu’il y a après s’appelle une valeur.

Note:

Il y a une différence subtile entre les artistes et les salles. Les artistes sont listés avec des - alors que les salles n’ont pas de tiret. Pourquoi ?

C’est juste une histoire de nommage. Les artistes ne sont pas nommés, c’est simplement une liste. Ainsi, on pourrait dire « le premier artiste de artists », mais on ne peut pas le désigner directement. Les salles sont nommées, on peut s’y référer directement, par exemple dire la salle trianon.

En YAML, quand on a pas besoin de se référer explicitement à des sous-éléments, on utilise des tirets, et sinon on les nomme et on utilise pas de tirets.

La dernière fois, on a vu comment éditer un fichier avec nano. nano est bien pratique pour faire des petites modifications, mais est mauvais quand il s’agit d’éditer des fichiers YAML. Il n’y a pas de coloration syntaxique, pas d’espace automatique en allant à la ligne… c’est un enfer.

Je te propose donc de découvrir vim, un éditeur plus difficile à prendre en main mais très pratique pour éditer des fichiers YAML!

On va faire au plus simple : tu ouvres ton fichier docker-compose.yml avec vim :

vim docker-compose.yml

Tu appuies sur I pour rentrer en mode “insertion”. Tu écris ton texte. Quand tu as fini, tu appuies sur Échap.

Enfin, tu appuies sur : pour rentrer en mode « commande », tu écris « wq » (write and quit), puis Entrée. Et voilà ! Ça peut paraître contre-intuitif parce qu’on ne rentre pas dans le pourquoi du comment, mais c’est tout ce que tu as besoin de savoir. Démonstration :

Note comment la barre du bas change au fil des commandes (I puis :wq).

On est maintenant équipé pour écrire des fichiers Compose sur les machines ! ^_^

On va ré-écrire la première commande de cette page, mais à l’aide d’un fichier Compose.

La première étape, c’est de déclarer la « version » du fichier de configuration. Actuellement, on utilise la 3.7, mais chaque version apporte ses évolutions :

snippet.yaml
version: "3.7"

Note:

Note les guillemets pour indiquer une chaîne de caractère. Des fois, les guillemets sont optionnels, mais sur la version Compose râle s’ils n’y sont pas.

Regardons la suite :

snippet.yaml
version: "3.7"

services:
  quentin:
    image: nginx:quentin
    container_name: quentin
    ports:
      - 8001:80
    volumes:
      - ./website:/var/www/html

Important:

Tout ceci est à adapter avec les noms et ports de vos propres conteneurs!

On commence par déclarer un ensemble de services. Dans la terminologie Compose, un service = un conteneur. Ici, il n’y en a qu’un, c’est notre serveur web. On le nomme quentin juste en dessous de la directive services.

Attention:

C’est très utile de nommer le service, car on pourra ensuite s’y référer avec les commandes Compose (redémarre tel service, montre moi les journaux de tel service, etc). Mais ce n’est pas nécessairement le même nom que celui du conteneur! Ici, oui, mais ce sont deux entités différentes - le nom du service n’a de sens que pour les commandes Compose.

Ensuite, les autres directives devraient te parler d’elles-mêmes si tu as suivi la partie sur la fabrication d'une image Docker. On choisit l’image, on nomme le conteneur, on indique les mapping entre port hôte et port conteneur, puis les montages.

Si tu te rappelles, on avait utilisé les volumes Docker plutôt que les points de montage pour les conteneurs. C’était plus pratique, notamment pour des raisons de portabilité.

Voici comment on ferait avec Compose :

snippet.yaml
volumes:
  quentin_data:
    name: quentin_data
  
services:
  quentin:
    [...]
    volumes:
      - quentin_data:/var/www/html

Ici, pas besoin de faire de docker volume create, Compose s’occupera de tout ! Créer un volume Docker qui s’appelle quentin_data, et le monter sur /var/www/html dans le conteneur !

Note:

Il suffira ensuite de faire un docker cp pour copier des fichiers dans le volume, et les garder au fil des recréations du conteneur.

A Savoir:

On a fait une documentation plus complète sur les volumes par ici !

Une fois que le fichier est édité, une commande ~~pour les gouverner tous~~ pour tout lancer :

# -d pour détacher, lancer en arrière plan
docker-compose up -d

Pour vérifier que tout s’est bien passé, on peut consulter les journaux. S’il n’y a aucun message, c’est plutôt bon signe.

docker-compose logs

On peut ensuite vérifier que tout s’est bien lancé :

curl pica01-test.picasoft.net:8001

Question:

Heu, on a pas monté un volume vide dans /var/www/html ? Pourquoi ça affiche un truc ?

Compose a créé le volume quentin_data et l’a monté sur /var/www/html. Mais ce volume est vide alors que le dossier de l’image n’est pas vide ! Il contient la page d’accueil par défaut de nginx. Alors Docker copie le contenu du dossier dans le volume ; c’est bien pratique pour ne pas écraser des choses par erreur.

Maintenant, on voudrait bien mettre notre page d’accueil. C’est l’occasion de se rappeler comment on copie un fichier dans un volume Docker :

vim index.html
docker cp index.html quentin:/var/www/html

Important:

Cette opération est différente d’un montage, car à présent le fichier est dans le volume et y reste ! Même si on le supprime de l’hôte, il reste dans le volume. Il faudrait le modifier depuis l’intérieur du conteneur pour qu’il soit modifier dans le volume, ou copier un nouveau fichier.

Question:

Et comment on fait pour modifier le fichier dans le conteneur ?

Il suffit d’ouvrir un shell dedans :

snippet.bash
# Exécute la commande bash dans le conteneur quentin
docker-compose exec quentin bash

Et de faire sa vie !

Voyons que ce ça donne en action : copier un fichier dans le volume, le supprimer, voir que ça ne change rien, puis modifier le fichier dans le conteneur.

On constate en même temps que dans le conteneur il n’y a aucun éditeur. C’est parce que dans l’image debian sur laquelle on s’est basée, il n’y en a pas ; et pour cause, un service n’a pas besoin d’éditeur de texte.

A Savoir:

Cette page du wiki répertorie quelques commandes utiles que fournit Compose!

Pour le reste, on ne liste pas tout sur le wiki, mais on peut retrouver l’ensemble des commandes sur la documentation de Compose

A Savoir:

Il y toute une section du wiki dédiée à Compose, qui explique un peu plus formellement les choses. N’hésite pas à y jeter un œil !

On est déjà pas mal, on a un moyen de créer des conteneurs de façon stable, à partir d’un fichier de configuration. Mais il manque encore quelque chose… vous ne trouvez pas que pica01-test.picasoft.net:8081, c’est un peu bizarre comme URL ?

Est-ce-qu’on a envie de cliquer sur une URL comme ça ? Typiquement, team.picasoft.net, c’est un peu plus joli.

Note:

Rappel : quand on ne précise pas de port dans une URL, c’est le port 80, le port standard du web, qui est sélectionné automatiquement.

Mais on a vu que le port 80 ne pouvait être écouté que par un seul service. Alors, si on a plusieurs URLs team.picasoft.net, pad.picasoft.net qui tournent sur la même machine, comment on fait ?

Et bien c’est là qu’entre en scène Traefik, l’une des pièces les plus importantes de l’infrastructure ! Direction la prochaine page pour en savoir plus ! ^_^

  • technique/tech_team/pres_compose.txt
  • de qduchemi