< Docker

La commande docker compose est un utilitaire généralement fourni avec Docker, permettant d'orchestrer plusieurs images et conteneurs avec la même commande[1]. Pour ce faire, les paramétrages de l’ensemble des conteneurs doivent être définis dans le fichier docker-compose.yml à la racine du projet. Toutefois il est possible de surcharger des parties de ce fichier au lancement des conteneurs, pour chaque environnement[2].

Par convention, les paires clés / valeurs de ces fichiers YAML ne sont pas entre apostrophes ou guillemets, mais cela fonctionne aussi avec. Toutefois il existe deux exceptions : les versions, et les associations de ports (contenant des ":"), où les guillemets sont par contre recommandés pour éviter les conflits (avec le "." ou avec le ":" interprété avec des nombres sexagésimaux[3]).

Configuration YAML

version

Version de Docker Compose[4]. Exemple en 2023 :

 version: "3.8"

networks

Définition du réseau des VM Docker.

Ex :

         networks:
            default:
                ipv4_address: 172.170.0.2

services

Liste des conteneurs à construire. Pour chacun on peut trouver :

image

Nom de l'image à télécharger (sur https://hub.docker.com/ ou un dépôt privé). Elle peut être suivie d'un tag pour en indiquer la version.

Exemples :

    image: mariadb

    image: mariadb:latest

    image: mariadb:10.4

extends

"image" permet donc de lancer un groupe d'applications, qui sont par ailleurs lançables individuellement. Mais pour partager des configurations on peut aussi utiliser "extends"[5] :

  extends:
    file: webapp/docker-compose.yml
    service: webapp

build

Alternativement à l'image, on peut indiquer le chemin d'un dockerfile pour construire son propre conteneur.

Si le conteneur ne partage aucun fichier avec d'autres, indiquer simplement le nom du dossier contenant le dockerfile :

        build: ./php8.2-fpm

Sinon, préciser le contexte où le conteneur devra récupérer les fichiers partagés nécessaires à son build :

        build:
            context: .
            dockerfile: ./php8.2-fpm/Dockerfile

volumes

Mapping des répertoires partagés entre la machine hôte et le conteneur :

        volumes:
            - $HOME/www:/var/www

La variable $HOME vaut "~" par défaut (dossier de l'utilisateur courant), mais peut être remplacée dans le fichier .env.

ports

Mapping du partage des ports. Ex :

        ports:
            - "3306:3306"

environment

Injecte des variables d'environnement dans le conteneur. Très utile pour que les conteneurs soient à l'heure de la machine hôte :

        environment:
            TZ: Europe/Paris

Logo

environment: n'accepte pas les sous-tableaux : il faut les convertir en JSON.

env_file

Définit le nom d'un fichier contenant des variables d'environnement récupérables dans docker-compose.yml, avec la syntaxe "${ma_variable}". On peut aussi rajouter une valeur par défaut ensuite. Exemple :

    env_file: .env
    environment:
        HOST_UID: ${UID:-valeur-par-défaut}

Logo

Sur Windows le changement de l'UID entraine une modification des droits de tous les fichiers.

depends_on

Permet de spécifier qu'un conteneur doit en attendre un autre pour être lancé.

restart

Indique si le conteneur doit se lancer au démarrage du daemon Docker (donc de la machine hôte). Vaut "no" par défaut. Ex :

        restart: always

Autre valeur possible :

unless-stopped

container_name

Permet de forcer un nom de conteneur.

hostname

Permet de forcer un nom de machine dans le conteneur. Utile si on a une application qui doit pointer dessus dans son .env (car "localhost" fonctionne quand le serveur était installé directement sur la machine hôte mais pas dans un conteneur).

network

Permet de forcer une adresse IP pour le conteneur.

Logo

Dans docker-compose.yml, il faut toujours remplir le paramètre "default" de "networks" pour ne pas qu’il prenne une plage utilisée.

extra_hosts

Remplit le /etc/hosts du conteneur. Ex :

extra_hosts:
    - mon_serveur_local.localhost:172.20.0.2

command

Pour exécuter un script à chaque lancement du conteneur.

    command: ls -alh

ou en multiligne :

   command: |
       ls -alh

</syntaxhighlight> ou :

    command: ['ls', '-alh']

ou si la commande est dans un fichier :

    command: /bin/ls.sh

entrypoint

Pour définir le dernier script exécuté à chaque lancement du conteneur.

tty

Équivalent à docker -t : ajoute un pseudo-terminal pour interagir avec le conteneur.

Exemples

Minimal

Exemple de docker-compose.yml contenant un seul conteneur CentOS, qui a le droit d'accéder au dossier ~/www :

version: "3.8"
services:
  centos:
    image: centos/systemd
    volumes:
        - $HOME/www:/var/www

Avancé

version: "3.8"

networks:
    default:
        driver: bridge
        ipam:
            driver: default
            config:
                - subnet: 172.170.0.0/16

services:
    mariadb:
        hostname: mariadb
        image: mariadb:10.4
        ports:
            - "3306:3306"
        environment:
            MYSQL_ROOT_PASSWORD: wikibooks
        # Partage pour les commandes SQL "into outfile" et "load data infile"
        volumes:
            - $HOME/www:/var/www
        restart: unless-stopped
        networks:
            default:
                ipv4_address: 172.170.0.3

    adminer:
        hostname: adminer
        image: adminer
        ports:
            - 8080:8080
        restart: unless-stopped
        networks:
            default:
                ipv4_address: 172.170.0.4


 Une alternative aux IP fixes (permettant des noms de domaines personnalisés dans le fichier hosts) et de passer par des ports, comme pour Adminer ci-dessus, qui est accessible sur http://localhost:8080 (puis fonctionne en se loguant vers le serveur "mariadb", login "root" et mot de passe "wikibooks".

Avec Traefik

Pour éviter de maintenir les noms de domaines des conteneurs dans le fichier hosts de la machine hôte, il existe le conteneur du proxy inverse Traefik pour mettre en l’œuvre l'association entre les conteneurs et leurs URLs.

Par ailleurs, sachant que les docker-compose.yml peuvent être utilisés dans des environnements de tests, donc sans besoin d'y accéder par des noms de domaine, il est préférable de séparer le docker-compose.yml en deux : l'un qui sera tout le temps utilisé pour l'application, et l'autre uniquement quand on veut l'utiliser manuellement en complément du premier : il faudra alors monter les conteneurs en précisant leurs deux noms.

docker-compose.yml

Plus besoin de fixer l'IP ici :

version: "3.8"

services:
    mariadb:
        hostname: mariadb
        image: mariadb:10.4
        ports:
            - "3306:3306"
        environment:
            MYSQL_ROOT_PASSWORD: wikibooks
        volumes:
            - $HOME/www:/var/www
        restart: unless-stopped

docker-compose.override.yml

Par convention, le nom du second docker-compose.yml est docker-compose.override.yml[6]. Mais on peut en créer un par environnement (ex : docker-compose.test.yml, docker-compose.dev.yml, docker-compose.prod.yml).

Ex :

version: "3.8"
services:
  traefik:
    image: traefik
    command:
      - --providers.docker
      - --entryPoints.web.address=:80
      - --entryPoints.websecure.address=:443
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock

  adminer:
    image: adminer
    labels:
      - traefik.enable=true
      - traefik.http.routers.adminer.rule=Host(`adminer.localhost`)
      - traefik.http.routers.adminer.entryPoints=web
    depends_on:
      - mariadb

Ainsi, la base décrite dans le premier fichier sera accessible par l'Adminer du second sur http://adminer.localhost.


Plusieurs domaines vers le même conteneur

On peut avoir par exemple un serveur Apache avec plusieurs vhosts pointant vers des applications différentes :

  apache:
    labels:
      - traefik.enable=true
      - traefik.http.routers.app.rule=Host(`www.example1.com`) || Host(`www.example2.com`)
      - traefik.http.routers.app.entryPoints=web
      - traefik.http.routers.whoami.entrypoints=web-secure
      - traefik.http.routers.whoami.tls=true
      - traefik.http.routers.whoami.tls.certresolver=certificato
      - traefik.http.routers.whoami.tls.domains[0].main=*.example1.com
      - traefik.http.routers.whoami.tls.domains[1].main=*.example2.com
    hostname: apache
    build: './devops/apache'
    environment:
      TZ: Europe/Paris
      APACHE_LOG_DIR: /var/log/apache2
    volumes:
      - ./apps:/var/www/

Gestion

Pour relancer le conteneur (sur Windows ou Linux) :

docker compose stop; docker compose build; docker compose start
 Au premier lancement, on peut regrouper le "build" et le "run" dans une seule commande "up -d". Par contre pour reconstruire les images existantes, il faudra préciser le "build".

Pour lancer les conteneurs avec plusieurs docker-compose.yml :

docker compose -f docker-compose.yml -f docker-compose.override.yml up -d

Pour rentrer dedans :

docker compose exec centos bash

Pour rentrer dedans en root :

docker compose exec --user root centos bash

Pour le lancer et rentrer dedans en même temps :

docker compose run centos bash

Pour exécuter une seule commande shell dedans sans y rentrer (en restant depuis la machine hôte) :

docker compose exec centos sh -c 'ls -alh'

Logs

Pour voir les logs de tous les conteneurs en live :

 docker compose logs -f

Pour voir les logs d'un seul conteneur :

 docker compose logs nom_du_conteneur


Supprimer les logs

L'emplacement des logs d'un conteneur est visible avec :

 docker inspect --format='{{.LogPath}}' nom_du_conteneur

Sur Linux

Tous les conteneurs

Pour supprimer les logs de tous les conteneurs sur Linux :

docker compose stop
 find /var/lib/docker/containers/ -type f -name "*.log" -delete
docker compose up -d
Un seul conteneur

Pour ne supprimer les logs que d'un seul conteneur :

docker compose stop mon_conteneur
sudo rm $(sudo docker inspect --format='{{.LogPath}}' mon_conteneur)
docker compose up -d mon_conteneur

Sur Windows

Sur Windows, comme les logs sont dans le fichier C:\ProgramData\DockerDesktop\vm-data\DockerDesktop.vhdx, il faut d'abord se connecter à la VM Docker pour exécuter cette commande[7]. Exemple en DOS :

docker run --privileged -it -v /var/run/docker.sock:/var/run/docker.sock jongallant/ubuntu-docker-client 
docker run --net=host --ipc=host --uts=host --pid=host -it --security-opt=seccomp=unconfined --privileged --rm -v /:/host alpine /bin/sh
chroot /host

Références

Cet article est issu de Wikibooks. Le texte est sous licence Creative Commons – Attribution – Partage à l’identique. Des conditions supplémentaires peuvent s’appliquer aux fichiers multimédias.