{{indexmenu_n>30}}
## C'est quoi Docker Compose ?
Docker Compose est un outil d'**orchestration** de conteneurs.
### Mais pourquoi diable un énième outil ?
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 [[technique:tech_team:tuto_docker|à 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.
### Cas d'usage de Compose
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 [[technique:tech_team:traefik|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!
### Un détour par le format YAML
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 :
```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.
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.
### vim : un goût amer mais bien utile
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 :
{{ :technique:tech_team:vim.gif |}}
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 ! ^_^
### Ton premier fichier Compose
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](https://docs.docker.com/compose/compose-file/) :
```yaml
version: "3.7"
```
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 :
```yaml
version: "3.7"
services:
quentin:
image: nginx:quentin
container_name: quentin
ports:
- 8001:80
volumes:
- ./website:/var/www/html
```
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`.
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 [[technique:tech_team:tuto_docker|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.
### Gérer les volumes avec Compose
Si tu te rappelles, on avait [[technique:tech_team:tuto_docker#passer_aux_choses_serieuses|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 :
```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 !
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.
On a fait une documentation plus complète sur les volumes [[technique:docker:good_practices:storage|par ici]] !
### Et comment on lance tout ça ?
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
```
{{ :technique:tech_team:compose_volume.gif |}}
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
```
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.
Et comment on fait pour modifier le fichier dans le conteneur ?
Il suffit d'ouvrir un shell dedans :
```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.
{{ :technique:tech_team:compose_volume_cp.gif |}}
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.
### D'autres commandes Compose ?
[[:technique:docker:picasoft:admin|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](https://docs.docker.com/compose/reference/)
### Compléments
Il y toute une [[technique:docker:good_practices:start|section du wiki]] dédiée à Compose, qui explique un peu plus formellement les choses. N'hésite pas à y jeter un œil !
### Et maintenant ?
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.
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 [[technique:tech_team:traefik|la prochaine page pour en savoir plus]] ! ^_^