Docker-compose

De Justine's wiki
Aller à la navigation Aller à la recherche

Référence de la syntaxe en version 3

Installer docker et docker-compose

<source>

  1. Enlever les vieilles versions

sudo apt-get remove docker docker-engine docker.io containerd runc

  1. Préalable

sudo apt-get update sudo apt-get install apt-transport-https ca-certificates curl gnupg lsb-release

    1. Ajouter la clef GPG

curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

  1. Ajouter le repo

echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

  1. Installer Docker

apt update apt install docker-ce docker-ce-cli containerd.io

  1. Installer docker-compose

apt install docker-compose </source>

Explication des versions de docker-compose

Doc sur les versions Il existe à l'heure actuelle (Octobre 2021) trois versions de Docker-compose: Les versions 2 et 3 sont valides, la 1 est dépréciée. Il est recommandé d'utiliser la dernière version, mais nous y reviendrons.

Il faut spécifier la version au début de chaque fichier docker-compose. Pour cela: <source> version :2

  1. Correspond à 2.0

version: 2.1

  1. Ou

version: 3 </source> Si on ne mets pas cette ligne, le fichier est considéré comme étant en version 1.

Les différences notables:

  • Version 1 : Ne prend pas en compte la notion de networking, ni celle de volumes. Le seul moyen de lier des conteneurs est par l'usage de links.

Exemple: <source lang="yaml"> web:

 build: .
 ports:
  - "5000:5000"
 volumes:
  - .:/code
 links:
  - redis

redis:

 image: redis

</source>

  • Version 2 : On peut déclarer des volumes et des réseaux. Par défaut, les conteneurs sont dans le même réseau et leur hostname est leur nom; mais on peut faire ses propres réseaux. Les versions mineures ont apporté de nouveaux paramètres, voir ladoc en lien ci-dessus.

Exemple un peu "chiadé": <source lang="yaml"> version: "2.4" services:

 web:
   build: .
   ports:
    - "5000:5000"
   volumes:
    - .:/code
   networks:
     - front-tier
     - back-tier
 redis:
   image: redis
   volumes:
     - redis-data:/var/lib/redis
   networks:
     - back-tier

volumes:

 redis-data:
   driver: local

networks:

 front-tier:
   driver: bridge
 back-tier:
   driver: bridge

</source>

  • Version 3 : La version 3 a été conçue pour être cross-compatible avec le mode Swarm de docker-compose. De nombreuses options ont disparu :( La fonctionnalité deploy a été ajoutée, j'y reviendrait plus bas.

Un exemple simple : freshrss

Un fichier docker-compose doit **toujours** s'appeller docker-compose.yml. En général, je fais un dossier pour chaque projet dans /opt.

Le docker-compose suivant fait tourner un conteneur pour FreshRSS (un très bon lecteur de flux en mode web). <source lang="yaml"> --- version: "3" services:

 freshrss:
   image: ghcr.io/linuxserver/freshrss
   container_name: freshrss
   environment:
     - PUID=1000
     - PGID=1000
     - TZ=Europe/London
   volumes:
     - ./config:/config
   ports:
     - 3100:80
   restart: unless-stopped

</source> Explications:

  • --- : marque le début d'un fichier yaml.
  • services : on va déclarer nos services.
  • freshrss : nom de mon service
  • image : nom de l'image dans le docker hub
  • container_name : le nom de mon conteneur
  • environment: Sert à déclarer des variables d'environnement dans le conteneur. Celles-ci sont utilisées par mon application.

volumes

  • volumes : on déclare des volumes.

Un volume est un dossier partagé entre le conteneur et la machine hôte. Ils servent surtout à y mettre les données importantes, pour ne pas les perdres entre deux démarrages. L'utilisation de volumes est pratique car elle permet de ranger toute notre application dans un dossier avec son docker-compose, de la déplacer, la lancer ailleurs, etc.

Mon docker-compose.yml est dans /opt/freshrss.

Ici, la mention ./config:/config permet de binder (à gauche) le dossier de ma machine hôte /opt/freshrss/config avec (à droite) le dossier /config dans mon conteneur.

ports

  • ports: on binde les ports.

Ici, il s'agit de binder des ports, sur le même principe que pour le volume. Le port 3100 de mon hôte mènera ainsi au port 80 du conteneur. Par défaut, c'est en tcp, mais on peut préciser (et même binder des ports de protocole différents): 3100/tcp:87/udp

Quand redémarre le conteneur ?

  • restart : sert à définir les conditions de redémarrage du conteneur.

Peut être à no, always-on, unless-stopped, on-failure. Il s'agit ici d'une syntaxe de version 2, qui est compatible comme ça mais pas en mode swarm. La version swamr donnerait plutôt: <source lang="yaml"> version: "3.9" services:

 redis:
   image: redis:alpine
   deploy:
     restart_policy:
       condition: on-failure
       delay: 5s
       max_attempts: 3
       window: 120s

</source>

Je ne rentre pas dans les détails sur la section deploy, je vais le faire juste après.

De façon (un peu) plus poussée

La section deploy, mode de compatibilité

Cette section, apparue en version 3, contient toutes les directives utiles à un déploiement sur swarm. Cependant, elle peut aussi contenir des choses utiles sans swarm, comme une limite de ram ou une restart-policy. Les deux choses qui m'intéressent sont surtout:

  • La limite de mémoire
  • La restart policy

...car ce sont des choses que l'on peut utiliser en version 3, sans swarm. En effet, par défaut, un lancement sans swarm ignore les directives dans deploy !

Pour pouvoir lancer un fichier en version 3, sans swarm, avec une section deploy et en récupérant ce qui est récupérable, il faut lancer son fichier avec l'option (non documentée) --compatibility. On va voir un exemple un peu plus parlant.

Un exemple avec des réseaux, des limites mémoire, 2 conteneurs

<source lang="yaml"> version: "3"

networks:

 gitea:
   external: false
 db:
   external: false
   ipam:
     config:
       - subnet: 172.19.0.0/24

services:

 database:
   image: mariadb:latest
   container_name: mariadb_gitea
   volumes:
     - ./gitea_db/:/var/lib/mysql
   environment:
     - MYSQL_ROOT_PASSWORD=ithaibai0C
     - MYSQL_DATABASE=gitea
     - MYSQL_USER=gitea
     - MYSQL_PASSWORD=ithaibai0C
   networks:
     db:
       ipv4_address: 172.19.0.10
   deploy:
     resources:
       limits:
         memory: 200M
       reservations:
         memory: 100M
 server:
   image: gitea/gitea:latest
   container_name: gitea
   environment:
     - USER_UID=1000
     - USER_GID=1000
   restart: always
   networks:
     gitea:
     db:
       ipv4_address: 172.19.0.20
   volumes:
     - ./gitea:/data
     - /etc/timezone:/etc/timezone:ro
     - /etc/localtime:/etc/localtime:ro
   ports:
     - "3000:3000"
   deploy:
     resources:
       limits:
         memory: 200M
       reservations:
         memory: 100M

</source>

section network

<source lang="yaml"> networks:

 gitea:
   external: false
 db:
   external: false
   ipam:
     config:
       - subnet: 172.19.0.0/24

</source> Il n'est pas obligatoire de déclarer des IPs pour s'assurer de la connectivité des conteneurs; voir Docker-compose#En_utilisant_les_hostnames Ici, je déclare mes réseaux. J'en ai 2 ; gitea et db. L'option external si elle est à True sert à rejoindre un réseau déjà existant (ce qui n'est pas mon cas ici). Si elle est activée, docker-compose va chercher un réseau du nom de mon réseau et tenter de s'y connecter.

Par défaut, un réseau utilise une adresse privée aléatoire. Je peux définir le sous-réseau que je veux donner à mon réseau avec les options "ipam" et suivantes.

Ensuite, pour chacun de mes conteneurs, je peux leur dire quelle adresse ils prendront si j'ai définit un subnet dans la partie réseau (je ne peux pas leur définir d'adresse sans avoir déclaré de subnet dans réseau bien sûr, et par défaut les conteneurs ont une adresse aléatoire): <source lang="yaml">

   networks:
     db:
       ipv4_address: 172.19.0.10

</source>

En utilisant les hostnames

Par défaut, deux conteneurs situés dans le même réseau peuvent résoudre les noms de conteneurs comme des noms dns. Dans l'exemple ci-dessous, le conteneur 'alice' peut parler à 'bob' directement via une requête sur http://bob/stufftograb et ça se passera bien. Donc, configurer les réseaux est facultatif. <source lang="yaml"> version: '3.3'

networks:

 monreseau:

services:

 alice:
   restart: always
   environment:
     - MASTER_URL=http://bob/stufftograb
   networks:
     - monreseau
 bob:
   restart: always
   networks:
     - monreseau

</source>

section deploy : limites mémoire

En version 3 sans swarm, avec le mode de compatibilité, je peux limiter la ram allouée aux conteneurs (mais pas le CPU). Autrement, ils se servent allègrement jusqu'à ce qu'il n'y en ai plus (et ils redémarrent).

Cela se fait par la section suivante: <source lang="yaml">

   deploy:
     resources:
       limits:
         memory: 200M
       reservations:
         memory: 100M

</source> Ici, je limite à 200 Mo et je réserve 100Mo.

Choisir quel utilisateur lance les conteneurs

C'est utile notamment pour savoir à quel utiisateur doivent appartenir les dossiers qui me servent de volumes. Cela se fait par la directive user: "UID:GID": <source lang="yaml"> service:

 database:
   container_name: mydb
   user: "1001:1001"

</source>

Choisir les serveurs DNS de mon conteneur

Cela se fait simplement via une directive appellée DNS: <source lang="yaml">

   blackbox-exporter:
       dns:
         - 9.9.9.9
         - 8.8.8.8
         - 1.1.1.1

</source>

Ici, mon conteneur blackbox ira résoudre ses adresses auprès de quad9 (puis de Google, puis de Cloudflare).


Voir les stats de mes conteneurs (mémoire, cpu, etc)

Cela se fait via la commande "docker stats": <source> docker stats CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS 29448d6f6660 freshrss 0.01% 19.97MiB / 200MiB 9.98% 7.36kB / 6.41kB 221kB / 10.3MB 14 5700f28b120e mariadb_gitea 0.03% 91.88MiB / 200MiB 45.94% 113kB / 269kB 17.8MB / 8.19kB 8 90751ba098af gitea 0.00% 126.3MiB / 200MiB 63.13% 346kB / 1.44MB 745kB / 36.9kB 12 </source>

Lancement, arrêt

À effectuer en se trouvant dans le dossier de mon docker-compose.

<source>

  1. Lancement normal

docker-compose up

  1. Lancement avec mise en arrière plan

docker-compose up -d

  1. Lancement avec mode de compatibilité

docker-compose --compatibility up -d

  1. Arrêt

docker-compose down </source>

Mise à jour d'un conteneur en latest

docker compose pull
docker compose up -d