Virtualisation / Tutoriel

Docker Compose : décrire ses services dans un fichier

Passer de longues commandes docker run à un fichier compose.yaml lisible et versionnable : structure du fichier, exemple complet d'une application avec sa base PostgreSQL, secrets dans un fichier .env, contrôle de santé, commandes du quotidien, mises à jour et sauvegardes.

Virtualisation Tutoriel Intermédiaire Publié le 20 octobre 2026 25 min de lecture
Vue aérienne d'un port de commerce et de la ville qui l'entoure
Photo : Thilina Alagiyawanna sur Unsplash

Avant de commencer

En clair

Avec docker run, chaque conteneur se lance avec une longue ligne d'options qu'il faut retenir ou noter quelque part. Docker Compose remplace ces lignes par un fichier, compose.yaml, qui décrit toute l'application : les conteneurs, leurs ports, leurs volumes, leurs variables, et comment ils se parlent. C'est la recette écrite plutôt que de mémoire : on la relit, on la modifie, on la sauvegarde avec Git, et on relance tout en une commande.

1. Pourquoi Compose

Avec docker run Avec Compose
Une commande par conteneur, à retenir Un fichier qui décrit tous les conteneurs
Réseau et noms à créer à la main Un réseau privé créé automatiquement ; les services se joignent par leur nom
Ordre de démarrage à gérer soi-même Dépendances déclarées (depends_on)
Configuration difficile à partager Fichier texte, versionnable avec Git, relisible
Mise à jour conteneur par conteneur docker compose pull puis docker compose up -d

2. La structure du fichier

services:            # les conteneurs de l'application
  nom-du-service:
    image: …         # l'image et sa version
    restart: …       # la politique de redémarrage
    ports: […]       # les ports publiés sur l'hôte
    environment: …   # les variables de configuration
    volumes: […]     # les données persistantes
    depends_on: …    # les services à démarrer avant

volumes:             # les volumes nommés utilisés plus haut
  nom-du-volume:

networks:            # facultatif : réseaux supplémentaires

Le fichier s'appelle compose.yaml (les anciens noms docker-compose.yml restent reconnus). L'indentation se fait avec des espaces, jamais des tabulations, et elle a un sens : deux espaces par niveau.

Rangez chaque application dans son propre dossier, par exemple /opt/forgejo/. Le nom du dossier devient le nom du projet, qui préfixe les conteneurs, volumes et réseaux créés.

3. Un exemple complet : Forgejo et PostgreSQL

Forgejo est une forge Git libre, auto-hébergeable, qui stocke ses données dans une base PostgreSQL. C'est un bon exemple d'application à deux services.

Le fichier des secrets : .env

sudo mkdir -p /opt/forgejo
cd /opt/forgejo

Créez /opt/forgejo/.env :

POSTGRES_PASSWORD=remplacez-par-un-mot-de-passe-long
FORGEJO_VERSION=16

Générez un mot de passe solide avec openssl rand -base64 32, puis protégez le fichier :

sudo chmod 600 /opt/forgejo/.env

Compose lit automatiquement le fichier .env placé à côté de compose.yaml et remplace les ${VARIABLE} du fichier par leur valeur.

Le fichier compose.yaml

services:
  forgejo:
    image: codeberg.org/forgejo/forgejo:${FORGEJO_VERSION}
    container_name: forgejo
    restart: unless-stopped
    environment:
      USER_UID: "1000"
      USER_GID: "1000"
      FORGEJO__database__DB_TYPE: postgres
      FORGEJO__database__HOST: db:5432
      FORGEJO__database__NAME: forgejo
      FORGEJO__database__USER: forgejo
      FORGEJO__database__PASSWD: ${POSTGRES_PASSWORD}
    volumes:
      - forgejo-data:/data
      - /etc/localtime:/etc/localtime:ro
    ports:
      - "192.168.1.10:3000:3000"
      - "192.168.1.10:2222:22"
    depends_on:
      db:
        condition: service_healthy

  db:
    image: postgres:17-alpine
    container_name: forgejo-db
    restart: unless-stopped
    environment:
      POSTGRES_DB: forgejo
      POSTGRES_USER: forgejo
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    volumes:
      - forgejo-db:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U forgejo -d forgejo"]
      interval: 10s
      timeout: 5s
      retries: 5

volumes:
  forgejo-data:
  forgejo-db:
Élément Explication
${FORGEJO_VERSION} La version vient du fichier .env : on la change à un seul endroit. Vérifiez la dernière version stable sur le site de Forgejo
FORGEJO__database__HOST: db:5432 Forgejo joint la base par le nom du service db, dans le réseau privé créé par Compose
Pas de ports: pour db La base n'est joignable que par les conteneurs du projet, jamais depuis le réseau
ports: "192.168.1.10:3000:3000" L'interface web n'est publiée que sur l'adresse du réseau local (les ports publiés contournent ufw)
2222:22 L'accès Git en SSH, sur le port 2222 pour ne pas entrer en conflit avec le SSH du serveur
healthcheck et condition: service_healthy Forgejo attend que PostgreSQL soit réellement prêt, pas seulement démarré
/etc/localtime:ro Le conteneur prend le fuseau horaire de l'hôte, en lecture seule
volumes: en bas Déclare les deux volumes nommés : données Git et base de données

Démarrer et vérifier

Vérifiez d'abord la syntaxe et le remplacement des variables :

sudo docker compose config

La commande affiche le fichier final, variables remplacées, ou une erreur précise. Puis démarrez :

sudo docker compose up -d
sudo docker compose ps
NAME         IMAGE                            SERVICE   STATUS                    PORTS
forgejo      codeberg.org/forgejo/forgejo:16  forgejo   Up 20 seconds             192.168.1.10:3000->3000/tcp, 192.168.1.10:2222->22/tcp
forgejo-db   postgres:17-alpine               db        Up 31 seconds (healthy)

Ouvrez http://192.168.1.10:3000 et terminez l'assistant d'installation de Forgejo : les paramètres de base de données sont déjà remplis. Créez le compte administrateur (par exemple spo).

Le fichier .env ne va pas dans Git

Si vous versionnez le dossier, ajoutez .env au fichier .gitignore, et fournissez à la place un .env.exemple sans les vraies valeurs. Un mot de passe publié sur une forge, même privée, doit être considéré comme compromis.

4. Les commandes du quotidien

Toutes se lancent dans le dossier qui contient compose.yaml (ou avec -f /opt/forgejo/compose.yaml).

Commande Effet
docker compose up -d Crée et démarre tous les services ; recrée ceux dont la configuration a changé
docker compose ps État des services du projet
docker compose logs -f Journaux de tous les services en direct
docker compose logs -f --tail 100 forgejo Journaux d'un seul service
docker compose restart forgejo Redémarre un service
docker compose stop Arrête les services sans les supprimer
docker compose down Arrête et supprime les conteneurs et le réseau ; les volumes sont conservés
docker compose exec db psql -U forgejo Lance une commande dans un service en cours
docker compose pull Télécharge les nouvelles versions des images
docker compose config Valide le fichier et affiche le résultat final
docker compose top Processus de chaque service

docker compose down -v

L'option -v supprime aussi les volumes du projet : la base de données et les dépôts Git disparaissent. Ne l'utilisez que pour effacer volontairement un projet de test.

5. Mettre à jour

  1. Lisez les notes de version de l'application : une version majeure peut demander une migration.
  2. Sauvegardez (partie 6).
  3. Changez la version dans .env si vous suivez une version précise, puis :
sudo docker compose pull
sudo docker compose up -d
sudo docker image prune

Compose recrée uniquement les conteneurs dont l'image a changé. Suivez les journaux (docker compose logs -f) pendant le redémarrage.

Les mises à jour automatiques

Des outils peuvent mettre à jour les conteneurs tout seuls. C'est pratique pour un service sans enjeu, mais risqué pour une base de données ou une application qui demande des migrations : une mise à jour ratée à 3 h du matin passe inaperçue jusqu'au lendemain. Préférez des mises à jour planifiées et surveillées, et fixez les versions majeures.

6. Sauvegarder

Une sauvegarde d'application Compose comprend trois éléments :

Élément Comment
La configuration : compose.yaml et .env Copie du dossier /opt/forgejo/ (le .env dans un emplacement protégé)
La base de données Export cohérent avec l'outil de la base
Les fichiers de l'application Archive du volume, application arrêtée ou figée

Export de la base PostgreSQL, sans arrêter le service :

sudo docker compose exec -T db pg_dump -U forgejo -d forgejo | gzip > forgejo-db-$(date +%F).sql.gz

Archive du volume de données, service arrêté pour garantir la cohérence :

sudo docker compose stop forgejo
sudo docker run --rm -v forgejo_forgejo-data:/data:ro -v "$PWD":/sauvegarde debian:13 tar czf /sauvegarde/forgejo-data-$(date +%F).tar.gz -C /data .
sudo docker compose start forgejo

Le nom réel du volume est préfixé par le nom du projet (forgejo_forgejo-data) : vérifiez-le avec docker volume ls. Copiez ensuite ces archives hors du serveur (voir la règle 3-2-1), et testez une restauration.

7. Les bonnes pratiques

Pratique Pourquoi
Un dossier par application (/opt/nom/) avec son compose.yaml et son .env Organisation claire, sauvegarde simple
Versions fixées (postgres:17-alpine, pas latest) Pas de changement majeur surprise
Secrets dans .env, droits 600, hors de Git Les mots de passe ne traînent pas dans le fichier principal
Bases de données sans ports: Elles ne sont joignables que par l'application
Ports publiés sur une adresse précise ou derrière un reverse proxy Les ports publiés contournent le pare-feu de l'hôte
restart: unless-stopped Redémarrage automatique après un plantage ou un redémarrage du serveur
healthcheck sur les services critiques Démarrage dans le bon ordre, état visible dans docker compose ps
docker compose config avant chaque up Les erreurs de syntaxe ou de variables apparaissent avant de casser le service
Fichier versionné avec Git (sans .env) Historique des changements, retour arrière facile

À retenir

  • compose.yaml décrit toute l'application ; les services se joignent par leur nom dans un réseau privé.
  • Secrets dans .env (droits 600, jamais dans Git), versions d'images fixées.
  • docker compose up -d, ps, logs -f, pull, down : les cinq commandes du quotidien.
  • down -v supprime les données : à manier avec précaution.
  • Sauvegarde = configuration + export de la base + volumes, copiée hors du serveur et testée.

À lire aussi