Cours B2-23 - Conteneurs en production : Docker, Compose, Podman
Cours · Fiche de cours

B2-23 - Conteneurs en production : Docker, Compose, Podman

B2-23 Conteneurs en production : Docker, Compose, Podman

🎓 SIO2 · semestre 3 ⏱️ 5 h (cours + TP) 🎯 Bloc 2 – SISR Comprendre ce qu'est un conteneur, manipuler images, volumes et réseaux, décrire une application complète avec Compose, la publier derrière Traefik et l'exploiter en sécurité, avec Docker ou Podman.

🎯 Objectifs

  • Expliquer la différence entre un conteneur et une machine virtuelle, et choisir l'un ou l'autre.
  • Décrire une image : couches, tag, registre ; écrire un Dockerfile simple.
  • Lancer, observer et dépanner un conteneur : docker run, ps, logs, exec.
  • Garder les données avec des volumes et isoler les services avec des réseaux.
  • Décrire une application web et sa base de données dans un fichier Compose.
  • Publier l'application derrière Traefik configuré par fichiers, puis l'exploiter en sécurité (Docker ou Podman).

📋 Prérequis

🧭 Référentiel

  • B2.2 Installer, tester et déployer une solution d'infrastructure : services conteneurisés.
  • B2.2 Vérifier les conditions de la continuité d'un service : données persistantes, redémarrage, sauvegarde.
  • B2.3 Exploiter et maintenir : mises à jour, journaux, sécurisation des services.
Test express des prérequis 3 questions · 2 minutes · conseillé avant de commencer

1. Sur Debian 13, quelle commande affiche les dernières lignes du journal du service nginx ?

journalctl -u filtre le journal de systemd par service, -n 20 limite aux 20 dernières lignes. À revoir : B2-14 · Debian 13.

2. Dans Traefik, quel élément indique l'adresse réelle de l'application vers laquelle transmettre la requête ?

Le routeur choisit la requête, les middlewares la modifient, le service sait où est l'application (url: "http://127.0.0.1:8080"). À revoir : B2-12 · Traefik.

3. Dans Proxmox VE, qu'est-ce qui distingue un conteneur LXC d'une machine virtuelle ?

Un conteneur partage le noyau de l'hôte : il est léger, mais ne peut faire tourner que des systèmes Linux. À revoir : B2-21 · Proxmox VE.
poste du développeur serveur de production Le conteneur emporte l'application et tout ce dont elle a besoin « Chez moi ça marche » devient « partout ça marche »

Brocéliande Logistique (entreprise fictive) veut un site d'actualités internes pour ses 60 salariés : notes de la direction, plannings de l'entrepôt, informations de l'agence de Rennes. Le prestataire propose WordPress, avec une base MariaDB. L'an dernier, une application semblable installée à la main sur un serveur avait cassé lors d'une mise à jour de PHP, et personne ne savait plus comment elle avait été configurée.

Le responsable informatique veut cette fois une installation décrite dans un fichier, que l'on peut relancer, mettre à jour ou reconstruire en quelques minutes. Il te confie le déploiement de l'application en conteneurs, sur la VM Debian, publiée en HTTPS derrière le reverse proxy Traefik déjà en place, avec des données qui survivent à tout.

Le coursConteneur et VM, images et registres, premiers conteneurs, volumes et réseaux, Compose, publication derrière Traefik, sécurité en production, puis Podman et le dépannage.

1. Conteneur ou machine virtuelle ?

Une machine virtuelle simule un ordinateur complet : l'hyperviseur lui donne un processeur, de la mémoire et un disque virtuels, et elle démarre son propre système, avec son propre noyau. Un conteneur, lui, n'est qu'un groupe de processus isolés qui tournent directement sur le système hôte et partagent son noyau Linux. L'isolement est assuré par deux mécanismes du noyau : les namespaces, qui cloisonnent ce que le conteneur voit, et les cgroups, qui limitent ce qu'il consomme.

Clique sur chaque technologie pour voir ce qui est empilé sur le serveur.

Machines virtuelles Conteneurs Matériel du serveur : processeur, mémoire, disques, cartes réseau Hyperviseur (Proxmox VE, KVM) VM 1 · DebianVM 2 · DebianVM 3 · Windows Server ApplicationApplicationApplication BibliothèquesBibliothèquesBibliothèques Noyau LinuxNoyau LinuxNoyau Windows Système hôte Debian 13 et son unique noyau Linux Moteur de conteneurs : Docker ou Podman conteneur webconteneur dbconteneur cache WordPressMariaDBRedis BibliothèquesBibliothèquesBibliothèques

Choisis une technologie pour comparer.

La VM virtualise le matériel ; le conteneur isole des processus sur un noyau partagé.
VM = maison conteneurs = appartements Les fondations (le noyau) sont partagées on emménage en quelques secondes

Pour bien comprendre : maison et appartements

Une VM ressemble à une maison individuelle : elle a ses propres fondations, sa chaudière, son compteur. Elle est très indépendante, mais longue à construire et coûteuse en terrain.

Les conteneurs sont des appartements dans un immeuble : chacun a sa porte fermée à clé et son aménagement, mais tous reposent sur les mêmes fondations (le noyau de l'hôte). On emménage en quelques secondes et on loge beaucoup plus de monde sur le même terrain.

Revers de la médaille : si les fondations ont un défaut, tout l'immeuble est concerné. Une faille du noyau touche tous les conteneurs de l'hôte.

Machine virtuelleConteneur
Ce qui est virtualiséLe matériel : la VM démarre son propre noyauLe système : processus isolés sur le noyau de l'hôte
Taille, démarrageQuelques Go, dizaines de secondesQuelques dizaines de Mo, environ une seconde
Systèmes possiblesTous (Linux, Windows, BSD…)Applications Linux sur un hôte Linux
IsolementTrès fort (frontière matérielle)Bon, mais noyau partagé
Usage typiqueContrôleur de domaine, pare-feu, serveur completApplications web, API, bases de données, outils

En entreprise, on ne choisit pas l'un contre l'autre : les conteneurs tournent presque toujours dans des VM. La VM apporte l'isolement fort et la sauvegarde par l'hyperviseur, les conteneurs apportent la légèreté et la reproductibilité des applications. C'est exactement l'architecture du TP : une VM Debian dans Proxmox, et des conteneurs dedans.

Docker a popularisé les conteneurs d'application (un service par conteneur) et le format d'image, aujourd'hui normalisé par l'OCI. Podman, porté par Red Hat, lance les mêmes images sans démon (partie 9). Les conteneurs LXC de Proxmox sont des conteneurs système : ils ressemblent à une petite VM Linux complète, avec ses services.

2. Images, couches et registres

Un conteneur est toujours lancé à partir d'une image : un modèle en lecture seule qui contient l'application, ses bibliothèques et la commande à exécuter au démarrage. Une image n'est pas un gros fichier unique, mais un empilement de couches : chaque couche ne contient que les fichiers ajoutés ou modifiés par rapport à la précédente.

registre (Docker Hub) docker pull debian:13-slim · 28 Mo RUN apt install nginx · +60 Mo COPY site/ · +2 Mo image suivi:1.0 sha256:4f2a9c… lecture seule écritureconteneur web1 écritureconteneur web2
Les couches en lecture seule sont partagées ; seule la couche d'écriture appartient au conteneur.

2.1 Lire le nom complet d'une image

Le nom docker.io/library/mariadb:11.4 se décompose en quatre morceaux, souvent abrégés : mariadb:11.4 suffit, car Docker Hub et l'organisation library (images officielles) sont pris par défaut.

  • docker.ioLe registre, serveur qui stocke et distribue les images : Docker Hub (docker.io), GitHub (ghcr.io), Red Hat (quay.io) ou un registre privé de l'entreprise (Harbor, GitLab).
  • library/mariadbLe dépôt : organisation puis nom. library regroupe les images officielles, maintenues et analysées régulièrement.
  • :11.4Le tag, une étiquette de version choisie par l'éditeur. Il peut être déplacé : 11.4 pointe toujours vers la dernière correction de la 11.4.
  • @sha256:…Le digest, empreinte du contenu exact. Contrairement au tag, il ne change jamais : on l'utilise pour figer une version de façon certaine.

latest n'est pas « la dernière version stable » : c'est seulement le tag utilisé quand on n'en précise aucun. Un docker pull peut donc faire passer une base de données à une version majeure sans prévenir. En production, on précise toujours un tag de version (mariadb:11.4), et on décide quand on change.

2.2 Construire sa propre image : le Dockerfile

Un Dockerfile décrit la construction d'une image. Le plus souvent, on utilise des images toutes faites ; on écrit un Dockerfile pour empaqueter une application maison.

Fichier Dockerfile · image du site de suivi
FROM debian:13-slim
RUN apt-get update && apt-get install -y --no-install-recommends nginx \
    && rm -rf /var/lib/apt/lists/*
COPY site/ /var/www/html/
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
  • FROML'image de départ. On choisit une image officielle et légère (-slim, -alpine) : moins de fichiers, moins de failles.
  • RUNUne commande exécutée pendant la construction ; elle crée une couche. On enchaîne avec && et on nettoie dans la même ligne pour garder la couche petite.
  • COPYCopie des fichiers du projet dans l'image.
  • EXPOSEDocumente le port écouté par l'application. N'ouvre rien : la publication se fait au lancement (-p).
  • CMDLa commande lancée au démarrage du conteneur. Elle doit rester au premier plan : quand elle s'arrête, le conteneur s'arrête.
Debian 13 construire et inspecter l'image
$ sudo docker build -t broceliande/suivi:1.0 . # le point = dossier qui contient le Dockerfile
$ sudo docker image ls # REPOSITORY broceliande/suivi TAG 1.0 SIZE 125MB
$ sudo docker image history broceliande/suivi:1.0 # une ligne par couche

3. Installer Docker et lancer un premier conteneur

3.1 Installation sur Debian 13

Debian fournit un paquet docker.io, mais en production on installe le plus souvent Docker Engine depuis le dépôt officiel de Docker, plus à jour, avec le greffon Compose. On ajoute la clé de signature du dépôt, puis le dépôt lui-même :

Debian 13 installer Docker Engine et Compose
$ sudo apt install -y ca-certificates curl
$ sudo install -m 0755 -d /etc/apt/keyrings
$ sudo curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
$ echo "deb [signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian trixie stable" | sudo tee /etc/apt/sources.list.d/docker.list
$ sudo apt update && sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
$ sudo systemctl status docker # active (running), activé au démarrage
$ sudo docker run --rm hello-world # « Hello from Docker! » : tout fonctionne

Le démon dockerd tourne en root et reçoit les ordres de la commande docker par un socket, /var/run/docker.sock. Sans droits sur ce socket, la commande répond permission denied while trying to connect to the Docker daemon socket : on la lance avec sudo. On verra en partie 8 pourquoi ajouter un utilisateur au groupe docker n'est pas anodin.

3.2 Les commandes de base

Debian 13 un serveur web en une ligne
$ sudo docker run -d --name web -p 127.0.0.1:8080:80 --restart unless-stopped nginx:1.28-alpine
$ sudo docker ps # NAMES web · STATUS Up 5 seconds · PORTS 127.0.0.1:8080->80/tcp
$ curl -s http://127.0.0.1:8080 | grep title # <title>Welcome to nginx!</title>
$ sudo docker logs -f web # journal du conteneur (sortie de nginx), Ctrl+C pour quitter
$ sudo docker exec -it web sh # un shell DANS le conteneur ; exit pour sortir
$ sudo docker stop web && sudo docker rm web # arrêter puis supprimer
  • -dDétaché : le conteneur tourne en arrière-plan et la commande rend la main.
  • --name webUn nom choisi, plus pratique que l'identifiant aléatoire pour logs, exec, stop.
  • -p 127.0.0.1:8080:80Publication de port : adresse de l'hôte : port de l'hôte : port du conteneur. Sans adresse, le port est ouvert sur toutes les interfaces de l'hôte.
  • --restart unless-stoppedRedémarre le conteneur après un plantage ou un redémarrage de la machine, sauf si on l'a arrêté volontairement.
  • nginx:1.28-alpineL'image et son tag, toujours en dernier ; ce qui suit l'image remplace la commande CMD. Vérifie sur le registre la version stable du moment.

3.3 La vie d'un conteneur

Imagelecture seule En marcheUp ArrêtéExited (code) Supprimécouche effacée run stop start rm rm -f (force, même en marche)
Un conteneur arrêté existe encore (on peut lire ses journaux) ; supprimé, sa couche d'écriture est perdue.

Un conteneur ne vit que tant que son processus principal tourne. S'il s'arrête aussitôt démarré, docker ps -a le montre en Exited avec un code de sortie, et docker logs donne presque toujours la raison : variable obligatoire manquante, port déjà pris, fichier de configuration invalide.

4. Garder les données : volumes et montages

Un conteneur est jetable : pour le mettre à jour, on ne le modifie pas, on le supprime et on en recrée un depuis la nouvelle image. Tout ce qu'il a écrit dans sa couche d'écriture disparaît alors. Les données qui doivent durer (base de données, fichiers envoyés par les utilisateurs, configuration) sont donc rangées en dehors du conteneur, dans un volume monté à l'intérieur.

Sans volume Avec un volume nommé db (11.4) couche : 2 Go de données SUPPRIMÉ db (11.8) base vide ! données perdues db (11.4) volume db_data /var/lib/mysql SUPPRIMÉ db (11.8) données retrouvées
Règle d'or : rien d'important dans la couche d'écriture d'un conteneur.
Volume nomméMontage d'un dossier (bind mount)
Syntaxe-v db_data:/var/lib/mysql-v /srv/site:/usr/share/nginx/html:ro
Où sont les fichiers ?Gérés par le moteur : /var/lib/docker/volumes/db_data/_dataDans le dossier de l'hôte que tu choisis
UsageDonnées d'une application : bases, fichiers envoyésFichiers que l'administrateur écrit : configuration, site statique, certificats
Bon réflexeUn volume par donnée à conserver, avec un nom parlant:ro (lecture seule) dès que le conteneur n'a pas à écrire
Debian 13 manipuler les volumes
$ sudo docker volume create db_data
$ sudo docker run -d --name db -e MARIADB_ROOT_PASSWORD=Ch4ng3-m0i -v db_data:/var/lib/mysql mariadb:11.4
$ sudo docker volume ls # DRIVER local · VOLUME NAME db_data
$ sudo docker volume inspect db_data # "Mountpoint": "/var/lib/docker/volumes/db_data/_data"
$ sudo docker rm -f db && sudo docker run -d --name db -e MARIADB_ROOT_PASSWORD=Ch4ng3-m0i -v db_data:/var/lib/mysql mariadb:11.4 # les bases sont toujours là

Copier le dossier d'un volume pendant que la base tourne donne une sauvegarde incohérente. Pour une base, on fait un export logique depuis le conteneur : docker exec db mariadb-dump … (TP, étape 7). Les volumes de fichiers se copient quand l'application est arrêtée, ou se sauvegardent avec la VM entière par Proxmox Backup Server.

5. Les réseaux des conteneurs

Chaque conteneur reçoit une interface réseau et une adresse privée (par défaut dans 172.17.0.0/16), reliée à un bridge sur l'hôte. Deux règles organisent les échanges :

  • Entre conteneurs : sur un réseau créé par l'administrateur (ou par Compose), un DNS interne résout le nom de chaque conteneur. WordPress joint la base par le nom db, jamais par une adresse qui change à chaque recréation. Sur le réseau bridge par défaut, ce DNS n'existe pas.
  • Depuis l'extérieur : un conteneur n'est joignable que par les ports publiés (-p). Une base de données ne se publie jamais : seuls les conteneurs de son réseau y accèdent.
Hôte Debian 13 (SRV-LINUX) poste client Traefik:80 · :443 127.0.0.1:8081 webport 80 dbport 3306 réseau back · internal HTTPS 443 db:3306 nom résolu par le DNS interne port publié 3306 jamais publié · la base ne sort pas de son réseau
Un seul chemin d'entrée : Traefik, puis le port web publié sur la boucle locale. La base n'est joignable que par web.
Debian 13 réseaux
$ sudo docker network ls # bridge, host, none + les réseaux créés
$ sudo docker network create back
$ sudo docker run -d --name db --network back -e MARIADB_ROOT_PASSWORD=Ch4ng3-m0i mariadb:11.4
$ sudo docker run --rm --network back debian:13-slim getent hosts db # 172.18.0.2 db : le DNS interne répond
$ sudo docker network inspect back # sous-réseau, passerelle et conteneurs reliés

Pour publier un port, Docker écrit ses propres règles de NAT dans le noyau, avant celles de ton pare-feu (nftables, ufw). Un -p 3306:3306 rend donc la base joignable depuis tout le réseau, même si ton pare-feu « bloque » le 3306. Publie le strict nécessaire, et sur 127.0.0.1 quand un reverse proxy local est devant.

6. Docker Compose : décrire une application complète

Avec docker run, une application à deux conteneurs demande deux longues commandes, deux volumes et un réseau à créer dans le bon ordre. Compose décrit tout cela dans un seul fichier YAML, compose.yaml, que l'on range dans un dossier par application (par exemple /opt/actus) et que l'on versionne dans Git. Une seule commande crée ou met à jour l'ensemble.

Fichier /opt/actus/compose.yaml
name: actus
services:
  db:
    image: mariadb:11.4
    restart: unless-stopped
    environment:
      MARIADB_DATABASE: wordpress
      MARIADB_USER: wp
      MARIADB_PASSWORD: ${DB_PASSWORD}          # lu dans le fichier .env
      MARIADB_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
    volumes:
      - db_data:/var/lib/mysql
    networks: [back]
    healthcheck:
      test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
      interval: 10s
      retries: 5

  web:
    image: wordpress:7-apache
    restart: unless-stopped
    depends_on:
      db:
        condition: service_healthy              # attend que la base soit prête
    environment:
      WORDPRESS_DB_HOST: db                     # le nom du service, pas localhost
      WORDPRESS_DB_USER: wp
      WORDPRESS_DB_PASSWORD: ${DB_PASSWORD}
      WORDPRESS_DB_NAME: wordpress
    volumes:
      - wp_data:/var/www/html
    ports:
      - "127.0.0.1:8081:80"                     # visible seulement depuis l'hôte (Traefik)
    networks: [front, back]

volumes:
  db_data:
  wp_data:

networks:
  front:
  back:
    internal: true                              # aucun accès vers ou depuis l'extérieur
  • servicesUn bloc par conteneur. Le nom du service (db, web) sert aussi de nom DNS sur les réseaux du projet.
  • image · restartL'image avec un tag de version précis, et la politique de redémarrage (après un plantage ou un redémarrage de la VM).
  • environment · ${…}Variables passées à l'application. Les secrets sont lus dans un fichier .env placé à côté, protégé (chmod 600) et jamais versionné.
  • volumesMontages du service, et en bas du fichier la déclaration des volumes nommés. Compose les préfixe avec le nom du projet : actus_db_data.
  • depends_on · healthcheckOrdre de démarrage. Avec condition: service_healthy, web ne démarre que lorsque le test de santé de db réussit, et pas seulement quand son conteneur existe.
  • ports · networksPublication du seul port utile, sur la boucle locale ; deux réseaux : front pour sortir, back interne pour la base.
Fichier /opt/actus/.envchmod 600 · hors Git
DB_PASSWORD=mot-de-passe-long-et-aleatoire
DB_ROOT_PASSWORD=autre-mot-de-passe-long-et-aleatoire
compose.yaml .env compose up -d réseau actus_front réseau actus_back actus_db_data actus_wp_data db healthy web db:3306 127.0.0.1:8081
Le fichier décrit l'état voulu ; Compose crée ou corrige ce qui manque, dans le bon ordre.
Commande (dans le dossier du projet)Effet
docker compose configVérifie le fichier et affiche la configuration finale, variables remplacées
docker compose up -dCrée ou met à jour tout le projet, en arrière-plan
docker compose psÉtat des services : running, healthy, ports publiés
docker compose logs -f webJournaux d'un service en continu
docker compose exec db bashShell dans un service en marche
docker compose pull puis up -dMise à jour : télécharge les nouvelles images et recrée les conteneurs concernés
docker compose downArrête et supprime conteneurs et réseaux ; garde les volumes

docker compose down supprime les conteneurs et les réseaux, mais garde les volumes : on relance avec up -d et tout revient. Avec down -v, les volumes du projet sont supprimés aussi : base et fichiers perdus, sans confirmation. À réserver au labo, après une sauvegarde.

7. Publier l'application derrière Traefik

Les utilisateurs ne doivent pas taper http://172.16.50.11:8081 : ils ouvrent https://actus.broceliande.lan. C'est le rôle du reverse proxy Traefik vu en B2-12 : il reçoit les connexions HTTPS, présente le certificat, ajoute les en-têtes de sécurité et transmet à l'application. Comme pour tous les services de Brocéliande, on le configure uniquement par des fichiers dynamiques (file provider) : un fichier par service publié.

navigateur Traefik (hôte) /etc/traefik/dynamic/intranet.yml · actus.yml 127.0.0.1:8081 web db HTTPS · certificat HTTP Aucun accès au socket Docker, aucune étiquette dans les conteneurs : toute la publication est décrite dans les fichiers de Traefik.
Traefik ne sait rien des conteneurs : il connaît une adresse et un port, comme pour n'importe quelle application.
YAML /etc/traefik/dynamic/actus.ymlappliqué à chaud
http:
  routers:
    actus:
      rule: "Host(`actus.broceliande.lan`)"
      entryPoints: [websecure]
      service: actus
      middlewares: [securite]            # défini dans intranet.yml (B2-12)
      tls: {}

  services:
    actus:
      loadBalancer:
        servers:
          - url: "http://127.0.0.1:8081"   # le port publié par Compose

tls:
  certificates:
    - certFile: /etc/traefik/certs/actus.crt
      keyFile: /etc/traefik/certs/actus.key

Tous les fichiers du dossier forment une seule configuration : un middleware déclaré dans intranet.yml est utilisable dans actus.yml. WordPress sait qu'il est servi en HTTPS grâce à l'en-tête X-Forwarded-Proto: https que Traefik ajoute.

7.1 Variante : Traefik lui-même en conteneur

Si Traefik n'est pas installé sur l'hôte, on peut l'ajouter comme service du projet, toujours avec le file provider. Il rejoint le réseau front et joint l'application par son nom de service : le port de web n'a alors plus besoin d'être publié.

Fichier extrait de compose.yaml · service traefik
  traefik:
    image: traefik:v3
    restart: unless-stopped
    ports: ["80:80", "443:443"]
    volumes:
      - ./traefik/traefik.yml:/etc/traefik/traefik.yml:ro   # providers.file.directory: /etc/traefik/dynamic
      - ./traefik/dynamic:/etc/traefik/dynamic:ro
      - ./traefik/certs:/etc/traefik/certs:ro
    networks: [front]
# dans ./traefik/dynamic/actus.yml : url: "http://web:80"

Traefik sait aussi découvrir les conteneurs tout seul (provider Docker) : on décrit alors la publication dans des labels de chaque conteneur. Pour cela, il faut lui donner le socket /var/run/docker.sock, c'est-à-dire le contrôle total du moteur, donc de l'hôte : une faille de Traefik deviendrait une prise de contrôle du serveur. Les fichiers dynamiques évitent ce risque, regroupent toute la publication au même endroit, se relisent et se versionnent. C'est la règle au labo et dans cette fiche.

8. Sécuriser des conteneurs en production

Un conteneur isole une application, mais il ne la rend pas sûre : il partage le noyau de l'hôte, il tourne souvent en root à l'intérieur, et son image peut contenir des failles connues. La sécurité se joue à quatre niveaux : qui pilote le moteur, d'où viennent les images, comment chaque service est lancé, et comment on l'entretient.

8.1 Qui pilote le moteur ?

Le démon Docker tourne en root. Toute personne qui peut lui parler (membre du groupe docker, ou programme qui a accès à /var/run/docker.sock) peut lancer un conteneur qui monte la racine de l'hôte, et devenir root sur la machine en une ligne :

Debian 13 démonstration au labo · compte stagiaire membre du groupe docker
stagiaire$ id # uid=1001(stagiaire) groups=1001(stagiaire),989(docker)
stagiaire$ docker run --rm -it -v /:/hote debian:13-slim chroot /hote bash
root# cat /etc/shadow # lisible : c'est le fichier de l'hôte, et on est root

Ajouter un compte au groupe docker, c'est lui donner les droits de root, sans mot de passe et sans trace dans les journaux de sudo. On réserve le moteur aux administrateurs, on passe par sudo docker (tracé dans le journal), et on ne monte jamais docker.sock dans un conteneur. Pour aller plus loin : le mode rootless de Docker, ou Podman (partie 9), où le moteur tourne avec les droits d'un simple utilisateur.

8.2 Des images de confiance et à jour

  • Origine : images officielles (library/) ou d'éditeurs vérifiés ; pour une image maison, un Dockerfile relu, construit à partir d'une image officielle.
  • Version : un tag de version précis, jamais latest en production ; on lit les notes de version avant de changer de version majeure.
  • Failles connues : on analyse les images avec un scanner, par exemple trivy image wordpress:7-apache ou docker scout cves wordpress:7-apache, qui liste les CVE par gravité.
  • Mises à jour : un conteneur ne se met pas à jour avec apt upgrade à l'intérieur (perdu à la recréation). On télécharge la nouvelle image et on recrée : docker compose pull && docker compose up -d, puis docker image prune pour supprimer les anciennes.

8.3 Lancer chaque service avec le minimum de droits

Dans compose.yamlEffet
security_opt: ["no-new-privileges:true"]Aucun processus du conteneur ne peut gagner de droits (programmes setuid, sudo)
cap_drop: [ALL] puis cap_addRetire toutes les capacités de root, puis rend seulement celles que l'image exige (à tester service par service)
user: "1000:1000"Lance le processus avec un compte non privilégié, quand l'image le permet
read_only: true + tmpfs: [/tmp]Système de fichiers du conteneur en lecture seule : un attaquant ne peut pas y déposer d'outil
mem_limit: 512m · cpus: 1.0Plafonne la mémoire et le processeur : un service emballé ne bloque pas les autres
À proscrire : privileged: true, network_mode: host, /var/run/docker.sock montéChacun supprime une grande partie de l'isolement

8.4 Secrets et journaux

Les mots de passe ne s'écrivent pas dans compose.yaml : ils vont dans .env (droits 600, listé dans .gitignore), ou mieux dans des secrets Compose, des fichiers montés dans /run/secrets/ que lisent les images officielles grâce aux variables …_FILE (MARIADB_PASSWORD_FILE, WORDPRESS_DB_PASSWORD_FILE). Côté journaux, Docker garde par défaut toute la sortie de chaque conteneur dans un fichier qui grossit sans limite : on fixe une rotation pour tout l'hôte.

Fichier /etc/docker/daemon.jsonpuis systemctl restart docker
{
  "log-driver": "json-file",
  "log-opts": { "max-size": "10m", "max-file": "3" }
}

9. Podman, l'alternative sans démon

Podman lance les mêmes images OCI avec presque les mêmes commandes, mais sans démon central : chaque conteneur est un processus lancé directement par l'utilisateur qui tape la commande, et supervisé par systemd. Par défaut, il fonctionne en rootless : le root d'un conteneur n'est qu'un utilisateur ordinaire sur l'hôte. C'est l'outil par défaut de Red Hat, AlmaLinux et Rocky Linux, et il est disponible dans Debian 13.

Docker Podman (rootless) commande docker démon dockerd · root docker.sock conteneurs enfants du démon Si le démon s'arrête, tous les conteneurs s'arrêtent. podman (utilisateur) systemd --user processus de l'utilisateur, aucun démon Le root du conteneur n'est pas root sur l'hôte.
Même format d'image, même registre ; ce qui change, c'est qui exécute les conteneurs et avec quels droits.
Debian 13 Podman en simple utilisateur
$ sudo apt install -y podman podman-compose
$ podman run -d --name test -p 127.0.0.1:8082:80 docker.io/library/nginx:1.28-alpine # sans sudo
$ podman ps && podman logs test # mêmes verbes que docker
$ podman exec -it test sh
$ podman top test user huser # root dans le conteneur = ton UID sur l'hôte
$ podman compose up -d # lit le même compose.yaml (via podman-compose)

Pour qu'un conteneur Podman démarre avec la machine, on le confie à systemd avec un fichier Quadlet : une unité .container que systemd transforme en service.

Fichier ~/.config/containers/systemd/test.container
[Container]
Image=docker.io/library/nginx:1.28-alpine
PublishPort=127.0.0.1:8082:80
Volume=site:/usr/share/nginx/html:ro

[Service]
Restart=always

[Install]
WantedBy=default.target
Debian 13 activer le service utilisateur
$ systemctl --user daemon-reload && systemctl --user start test
$ sudo loginctl enable-linger $USER # les services de l'utilisateur tournent même sans session ouverte
DockerPodman
ArchitectureUn démon root, piloté par un socketPas de démon : chaque conteneur est un processus supervisé
Droits par défautRoot (mode rootless possible)Rootless ; ports inférieurs à 1024 interdits sans réglage
Multi-conteneursDocker ComposePods, podman compose, Quadlet
Démarrage avec la machinerestart: géré par le démonsystemd (Quadlet)
Noms d'imagesnginx = Docker Hub par défautNom complet conseillé : docker.io/library/nginx

Les images et les fichiers Compose sont les mêmes. Docker reste le plus répandu et le mieux documenté ; Podman apporte un meilleur cloisonnement (rootless, pas de socket root) et une intégration native à systemd. Au labo, on travaille avec Docker ; sache transposer en Podman, souvent en changeant seulement le nom de la commande.

10. Dépanner une application conteneurisée

10.1 La boîte à outils

QuestionCommande
Les services tournent-ils ? Sont-ils sains ?docker compose ps -a · docker inspect --format '{{.State.Health.Status}}' actus-db-1
Pourquoi s'est-il arrêté ?docker compose logs --tail 50 db (et le code de sortie dans ps -a)
Quelle configuration a-t-il reçue ?docker compose config · docker compose exec web env
Quel port est publié, et où ?docker compose port web 80 · ss -tlnp sur l'hôte
Les conteneurs se voient-ils ?docker network inspect actus_back · docker compose exec web getent hosts db
Reste-t-il de la place ?docker system df · df -h /var/lib/docker

10.2 Le chemin de diagnostic

https://actus.broceliande.lan ne s'affiche pas Réponds en partant de l'application, puis remonte vers le client

« docker compose ps » montre-t-il web en marche et db « healthy » ?Lance la commande dans /opt/actus.

Sur la VM, « curl -I http://127.0.0.1:8081 » répond-il (200 ou 302) ?On teste l'application sans passer par Traefik.

Sur la VM, « curl -kI --resolve actus.broceliande.lan:443:127.0.0.1 https://actus.broceliande.lan » répond-il ?On teste Traefik sans dépendre du DNS du poste.

Lis docker compose logs db puis web. Causes fréquentes : fichier .env absent (variables vides), mot de passe différent de celui de la première initialisation du volume, port déjà utilisé, test de santé en échec. Corrige, puis docker compose up -d.

Le conteneur tourne mais ne répond pas sur ce port : vérifie la ligne ports et docker compose port web 80, le port réellement écouté par l'application (80 pour l'image WordPress Apache), puis docker compose logs web.

Le problème est dans Traefik : sudo journalctl -u traefik -n 30. Vérifie le nom et l'extension du fichier dans /etc/traefik/dynamic/, la règle Host(`…`) avec ses accents graves, l'url du service (127.0.0.1:8081) et les chemins du certificat.

Le serveur fonctionne : le problème est côté client. Vérifie la résolution du nom (nslookup actus.broceliande.lan, enregistrement DNS ou fichier hosts), le pare-feu de la VM sur le port 443, puis le cache du navigateur.

10.3 Entraîne-toi : les tickets du support

L'application d'actualités est en service depuis un mois. Six tickets arrivent : lis le message, observe le relevé et choisis la cause.

File d'attente du support6 tickets · un à la fois · l'explication s'affiche après ta réponse
Ticket n° 1De : directionPriorité haute
« Depuis la mise à jour de la base faite par le stagiaire, le site affiche la page d'installation de WordPress. Tous nos articles ont disparu ! »
Debian 13 history (extrait) · serveur de test
docker run -d --name db --network back -e MARIADB_ROOT_PASSWORD=… mariadb:11.4
docker rm -f db
docker run -d --name db --network back -e MARIADB_ROOT_PASSWORD=… mariadb:11.8

Quelle est la cause ?

Cause : sans -v, /var/lib/mysql était dans la couche d'écriture ; docker rm l'a effacée. Correction : restaurer la dernière sauvegarde dans un conteneur qui monte un volume nommé (-v db_data:/var/lib/mysql), et décrire le service dans un fichier Compose pour que l'erreur ne se reproduise pas.

Ticket n° 2De : technicienPriorité haute
« J'ai écrit mon compose.yaml pour une deuxième instance de test. Le site affiche "Error establishing a database connection", alors que db est healthy. »
Fichier compose.yaml (extrait du service web)
    environment:
      WORDPRESS_DB_HOST: localhost
      WORDPRESS_DB_USER: wp

Quelle est la cause ?

Cause : chaque conteneur a sa propre pile réseau ; localhost dans web, c'est web. Correction : WORDPRESS_DB_HOST: db, le nom du service, résolu par le DNS interne du réseau du projet. Publier 3306 est inutile et dangereux.

Ticket n° 3De : technicienPriorité moyenne
« Mon conteneur web refuse de démarrer sur SRV-LINUX, alors qu'il marchait sur mon poste. »
Debian 13 docker compose up -d
Error response from daemon: driver failed programming external
connectivity on endpoint actus-web-1: failed to bind host port
0.0.0.0:80/tcp: address already in use

Quelle est la cause ?

Cause : ports: "80:80" demande le port 80 de toutes les interfaces, où Traefik écoute déjà. Correction : publier sur un port libre de la boucle locale ("127.0.0.1:8081:80") et laisser Traefik recevoir le trafic. sudo ss -tlnp | grep :80 montre qui occupe un port.

Ticket n° 4De : responsable sécuritéPriorité haute
« Le scan de vulnérabilités trouve le port 3306 de SRV-LINUX ouvert depuis le VLAN invités. Pourtant, nftables bloque ce port en entrée. »
Debian 13 docker ps (extrait)
NAMES        IMAGE          PORTS
actus-db-1   mariadb:11.4   0.0.0.0:3306->3306/tcp
actus-web-1  wordpress:7…   127.0.0.1:8081->80/tcp

Quelle est la cause ?

Cause : quelqu'un a ajouté ports: "3306:3306" à db pour « tester ». Docker a ouvert le port sur toutes les interfaces, en contournant les règles d'entrée de l'hôte. Correction : supprimer cette ligne (web joint db par le réseau interne) et recréer avec docker compose up -d ; pour administrer la base, utiliser docker compose exec db mariadb.

Ticket n° 5De : utilisateur (compta)Priorité moyenne
« https://actus.broceliande.lan affiche "Bad Gateway". Le technicien dit que les conteneurs tournent. »
Debian 13 journalctl -u traefik (extrait)
level=error msg="502 Bad Gateway" error="dial tcp: lookup web on
172.16.50.10:53: no such host" routerName=actus@file

Quelle est la cause ?

Cause : l'URL http://web:80 ne convient qu'à un Traefik placé dans le même réseau Docker (variante 7.1). Un Traefik installé sur l'hôte interroge le DNS de l'entreprise, qui ignore ce nom. Correction : url: "http://127.0.0.1:8081" dans actus.yml ; Traefik l'applique à chaud.

Ticket n° 6De : chargée de communicationPriorité basse
« Quand je me connecte à l'administration du site, je suis renvoyée vers http://127.0.0.1:8081/wp-admin, qui ne s'ouvre pas. »
Debian 13 docker compose exec db mariadb -u wp -p wordpress
MariaDB [wordpress]> SELECT option_name, option_value FROM wp_options
    -> WHERE option_name IN ('siteurl','home');
siteurl   http://127.0.0.1:8081
home      http://127.0.0.1:8081

Quelle est la cause ?

Cause : WordPress mémorise l'adresse utilisée lors de l'installation. Correction : UPDATE wp_options SET option_value='https://actus.broceliande.lan' WHERE option_name IN ('siteurl','home');. Bonne pratique : faire l'installation directement par l'adresse publique, derrière Traefik.

11. À l'examen et en entreprise

  • Documentation attendue : le schéma de l'application (conteneurs, réseaux, volumes, port publié, reverse proxy), le compose.yaml commenté, le fichier dynamique Traefik et la procédure de mise à jour et de sauvegarde. Les mots de passe n'apparaissent jamais dans le dossier.
  • Démonstration : docker compose down puis up -d devant le jury, et montrer que les articles sont toujours là, est très parlant. Montrer aussi que http://IP-VM:8081 ne répond pas depuis le poste.
  • Justifier ses choix : conteneur ou VM, volume plutôt que couche du conteneur, port sur la boucle locale, Traefik en fichiers plutôt qu'en étiquettes, Docker ou Podman. Le jury demande souvent comment on met à jour l'application sans perte.
  • En entreprise : un dossier par application dans /opt, versionné dans Git (sans .env), des images à version fixée, une mise à jour planifiée et testée, et une sauvegarde de la base exportée chaque nuit.

12. L'essentiel

  1. Un conteneur est un groupe de processus isolés (namespaces, cgroups) qui partage le noyau de l'hôte ; une VM a son propre noyau.
  2. Une image est un empilement de couches en lecture seule ; le conteneur ajoute une couche d'écriture, perdue à sa suppression.
  3. Nom d'image : registre/dépôt:tag ; en production, un tag de version précis, jamais latest.
  4. docker run -d --name … -p … -v … image:tag, puis ps, logs, exec, stop, rm.
  5. Les données à garder vont dans un volume nommé ; la configuration de l'administrateur dans un montage en :ro.
  6. Sur un réseau créé par Compose, les services se joignent par leur nom ; localhost désigne le conteneur lui-même.
  7. Publier le minimum, sur 127.0.0.1 derrière un reverse proxy : un port publié contourne le pare-feu de l'hôte.
  8. Compose décrit l'application dans compose.yaml + .env ; up -d crée ou met à jour, down -v efface les volumes.
  9. Publication par Traefik en fichiers dynamiques : jamais d'étiquettes ni de docker.sock monté.
  10. Sécurité : groupe docker = root, images officielles analysées, no-new-privileges, mises à jour par pull + up -d ; Podman offre le mode rootless.
Conteneursen production Principenoyau partagé, pas de VMnamespaces · cgroups Imagescouches · tag · registreDockerfile · jamais latest Donnéesvolume nommé · bind :roexport de la base RéseauxDNS interne : nom du service-p 127.0.0.1:8081:80 Composecompose.yaml + .envup -d · ps · logs · down ProductionTraefik en fichiersgroupe docker = root · Podman
La fiche en une image : à refaire de mémoire, sur une feuille, avant de passer aux exercices.

Les commandes clés

Pour…Commandes
Imagesdocker pull mariadb:11.4 · docker image ls · docker build -t nom:1.0 .
Lancerdocker run -d --name web -p 127.0.0.1:8080:80 -v data:/chemin nginx:1.28-alpine
Observerdocker ps -a · docker logs -f web · docker exec -it web sh
Volumes, réseauxdocker volume ls · docker network create back · docker network inspect back
Composedocker compose config · up -d · ps · logs -f · down
Mettre à jourdocker compose pull && docker compose up -d · docker image prune
Podmanpodman run … · podman ps · podman compose up -d · Quadlet .container

Tout cela tient sur une page : utilise le bouton Mémo à imprimer en haut de la fiche.

La pratiqueLe quiz noté pour vérifier tes acquis, les exercices à rendre à ton professeur, puis le TP au labo pour publier une application web et sa base de données avec Compose.

13. Quiz noté

8 questions · 10 minutesRéponds à toutes les questions, puis valide. Seule ta première tentative est enregistrée : elle compte dans ton suivi. Ensuite, tu peux t'entraîner autant que tu veux.

1. Qu'est-ce qu'un conteneur partage avec le système hôte ?

2. Un conteneur a écrit des fichiers sans volume. Que deviennent-ils après docker rm ?

3. Que fait l'option -p 127.0.0.1:8081:80 ?

4. Dans un même projet Compose, comment le service web doit-il joindre la base du service db ?

5. Pourquoi faut-il éviter le tag latest en production ?

6. Quel est l'effet de docker compose down -v ?

7. Pourquoi publie-t-on les conteneurs avec Traefik configuré en fichiers dynamiques plutôt qu'avec des étiquettes Docker ?

8. Quelle différence principale distingue Podman de Docker ?

14. Exercices : à toi de répondre

Écris ta réponse sous chaque énoncé et envoie-la à ton professeur. Quand il l'a validée, le corrigé s'affiche à la place du cadenas ; s'il te la renvoie « à revoir », lis son commentaire et corrige.

Exercice 1 – Comprendre (SIO2)

Pour chacun de ces besoins de Brocéliande Logistique, choisis entre VM et conteneur et justifie en une phrase : a) un second contrôleur de domaine Windows Server ; b) trois instances de test de l'application d'actualités ; c) le pare-feu IPFire de l'agence de Rennes ; d) un outil de supervision web (Uptime Kuma). Explique ensuite pourquoi dix conteneurs lancés depuis la même image n'occupent pas dix fois la taille de l'image.

Le corrigé s'affichera ici dès que ton professeur aura validé ta réponse. Cherche d'abord par toi-même : c'est en se trompant qu'on retient.

Exercice 2 – Configurer (SIO2)

Écris le fichier /opt/supervision/compose.yaml qui déploie Uptime Kuma (image louislam/uptime-kuma:2, port interne 3001, données dans /app/data) : redémarrage automatique, données dans un volume nommé, port publié seulement pour un Traefik installé sur l'hôte, sur le port 8082. Écris ensuite le fichier dynamique Traefik qui publie l'outil sous https://supervision.broceliande.lan.

Le corrigé s'affichera ici dès que ton professeur aura validé ta réponse. Cherche d'abord par toi-même : c'est en se trompant qu'on retient.

Exercice 3 – Dépanner (SIO2)

Un technicien propose ce fichier pour un wiki interne. Relève au moins cinq problèmes (fonctionnement ou sécurité) et propose la correction de chacun.

services:
  wiki:
    image: requarks/wiki:latest
    ports: ["80:3000"]
    environment:
      DB_HOST: localhost
      DB_PASS: Wiki2026!
  db:
    image: postgres
    ports: ["5432:5432"]
    environment:
      POSTGRES_PASSWORD: Wiki2026!
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock

Le corrigé s'affichera ici dès que ton professeur aura validé ta réponse. Cherche d'abord par toi-même : c'est en se trompant qu'on retient.

Exercice 4 – Concevoir (SIO2)

Brocéliande Logistique veut héberger en conteneurs quatre applications internes (actualités, wiki, supervision, gestion des clés). Propose une organisation de production complète : nombre et rôle des VM, Docker ou Podman, rangement des fichiers, publication, sauvegardes, mises à jour, sécurité et documentation. Justifie en une quinzaine de lignes.

Le corrigé s'affichera ici dès que ton professeur aura validé ta réponse. Cherche d'abord par toi-même : c'est en se trompant qu'on retient.

15. Au labo : publier une application web et sa base avec Compose

Objectif

Sur la VM Debian 13 de ton pool Proxmox (page Mes serveurs et VM), tu déploies le site d'actualités de Brocéliande Logistique : WordPress et MariaDB décrits dans un fichier Compose, publiés en HTTPS par Traefik sous https://actus.broceliande.lan. À la fin, le site survit à la recréation des conteneurs et au redémarrage de la VM, la base est sauvegardée, et ni le port de l'application ni celui de la base ne sont joignables depuis le réseau. Note l'adresse de ta VM Debian : on l'appelle IP-VM ci-dessous.

MachineSystèmeRôle dans le TP
SRV-LINUXDebian 13 (B2-14), Traefik installé en B2-12Hôte des conteneurs : Docker Engine, Compose, projet /opt/actus, adresse IP-VM
PC-COMPTAWindows 11 ProPoste client : navigateur, tests de ports
SRV-01Windows Server 2025, DNSFacultatif : enregistrement actus.broceliande.lan (sinon, fichier hosts du poste)
SRV-LINUX · Debian 13 · IP-VM PC-COMPTA Traefikactus.yml 127.0.0.1:8081 projet actus · réseaux front et back (internal) web · WordPress db · MariaDB actus_wp_data actus_db_data HTTPS db:3306
Seul Traefik est exposé ; l'application n'écoute que sur la boucle locale et la base reste dans son réseau interne.

Ce que tu ajoutes à cette étape

  • Le moteur de conteneurs : Docker Engine et Compose depuis le dépôt officiel, journaux limités en taille.
  • Le projet actus : compose.yaml durci et .env protégé, dans /opt/actus.
  • La publication : un fichier dynamique Traefik et un certificat pour actus.broceliande.lan.
  • L'exploitation : persistance vérifiée, sauvegarde de la base, procédure de mise à jour.

1 Installer Docker Engine

Sur SRV-LINUX, ajoute le dépôt officiel et installe les paquets comme en partie 3.1, puis limite la taille des journaux des conteneurs (partie 8.4) :

Debian 13 SRV-LINUX
$ sudo docker run --rm hello-world # Hello from Docker!
$ sudo docker compose version # Docker Compose version v2.x
$ echo '{ "log-driver": "json-file", "log-opts": { "max-size": "10m", "max-file": "3" } }' | sudo tee /etc/docker/daemon.json
$ sudo systemctl restart docker && sudo docker info | grep -i 'logging driver'

N'ajoute pas ton compte au groupe docker : toutes les commandes du TP se lancent avec sudo.

2 Préparer le dossier et les secrets

Debian 13 SRV-LINUX
$ sudo mkdir -p /opt/actus && cd /opt/actus
$ printf 'DB_PASSWORD=%s\nDB_ROOT_PASSWORD=%s\n' "$(openssl rand -hex 20)" "$(openssl rand -hex 20)" | sudo tee .env > /dev/null
$ sudo chmod 600 .env && sudo ls -l .env # -rw------- 1 root root

Les mots de passe sont tirés au hasard et ne s'affichent nulle part. Si tu changes un jour DB_PASSWORD, la base déjà initialisée garde l'ancien : il faudra aussi le changer dans MariaDB.

3 Écrire et valider compose.yaml

Crée /opt/actus/compose.yaml avec sudo nano en reprenant le fichier de la partie 6, puis ajoute à chacun des deux services ces deux lignes de durcissement (même niveau d'indentation que image), avec 1g de mémoire pour db et 512m pour web :

Fichier ajout dans chaque service de compose.yaml
    security_opt: ["no-new-privileges:true"]
    mem_limit: 512m
Debian 13 /opt/actus
$ sudo docker compose config --quiet && echo "fichier valide" # sinon : numéro de ligne de l'erreur YAML
$ sudo docker compose config --services # db et web

4 Démarrer et observer

Complète les commandes, à lancer dans /opt/actus avec sudo. Vérifie chaque ligne avec ✓.

démarrer en arrière-plan $
état des services $
journal du service web $
résolution de db depuis web $
tester sans Traefik $

Attends que db passe à healthy (quelques secondes) : web ne démarre qu'à ce moment. Le test local doit répondre 302 Found vers /wp-admin/install.php. N'ouvre pas l'installation par cette adresse : WordPress l'enregistrerait comme adresse du site (ticket n° 6). Repère aussi les objets créés : sudo docker network ls et sudo docker volume ls montrent les préfixes actus_.

5 Publier derrière Traefik

Debian 13 SRV-LINUX
$ sudo openssl req -x509 -newkey rsa:2048 -nodes -days 365 -keyout /etc/traefik/certs/actus.key -out /etc/traefik/certs/actus.crt -subj "/CN=actus.broceliande.lan" -addext "subjectAltName=DNS:actus.broceliande.lan"
$ sudo chown traefik: /etc/traefik/certs/actus.*
$ sudo nano /etc/traefik/dynamic/actus.yml # contenu de la partie 7
$ sudo journalctl -u traefik -n 20 # aucune ligne level=error
$ curl -kI --resolve actus.broceliande.lan:443:127.0.0.1 https://actus.broceliande.lan # 302, en-tête strict-transport-security

Si Traefik n'est pas installé sur ta VM (B2-12 non fait), ajoute-le au projet comme dans la variante 7.1, avec url: "http://web:80" dans son fichier dynamique ; tu peux alors retirer la ligne ports de web.

6 Résoudre le nom et installer le site

  1. Le nom : sur SRV-01, ajoute l'enregistrement Add-DnsServerResourceRecordA -ZoneName broceliande.lan -Name actus -IPv4Address IP-VM. Sans DNS du domaine, ajoute sur PC-COMPTA la ligne IP-VM actus.broceliande.lan au fichier C:\Windows\System32\drivers\etc\hosts (Bloc-notes en administrateur).
  2. L'installation : depuis PC-COMPTA, ouvre https://actus.broceliande.lan, accepte une fois l'alerte du certificat autosigné, puis installe WordPress en français : titre « Actualités Brocéliande », un compte administrateur nominatif et un mot de passe robuste.
  3. Un premier contenu : publie un article « Planning de l'entrepôt ». Il servira à prouver la persistance.

7 Exploiter : persistance, sauvegarde, mise à jour

Debian 13 /opt/actus
$ sudo docker compose down && sudo docker compose up -d # l'article est toujours là (volumes conservés)
$ sudo docker compose exec -T db sh -c 'mariadb-dump -uroot -p"$MARIADB_ROOT_PASSWORD" wordpress' | gzip | sudo tee /root/actus-$(date +%F).sql.gz > /dev/null
$ sudo zcat /root/actus-$(date +%F).sql.gz | grep -c 'CREATE TABLE' # une douzaine de tables WordPress (pas de * : ton shell ne peut pas lire /root)
$ sudo docker compose pull && sudo docker compose up -d && sudo docker image prune -f # procédure de mise à jour
$ sudo reboot # après redémarrage, le site revient seul (restart: unless-stopped)

Enfin, depuis PC-COMPTA, vérifie l'isolement dans PowerShell : Test-NetConnection IP-VM -Port 8081 et Test-NetConnection IP-VM -Port 3306 doivent répondre TcpTestSucceeded : False, alors que le port 443 répond True.

8 Valider : le cahier de recette

N°TestCommandeRésultat attenduOK
1Le moteur fonctionnesudo docker run --rm hello-worldHello from Docker!
2Les secrets sont protégéssudo ls -l /opt/actus/.env-rw-------, propriétaire root
3Les services sont sainssudo docker compose psweb Up, db Up (healthy)
4Le site répond en HTTPS par Traefikhttps://actus.broceliande.lan sur PC-COMPTASite WordPress, certificat actus.broceliande.lan
5Application et base non exposéesTest-NetConnection IP-VM -Port 8081 puis 3306Échec attendu : False pour les deux
6Les données survivent aux conteneursdocker compose down puis up -dL'article « Planning de l'entrepôt » est présent
7Le site revient après redémarragesudo reboot de la VMSite accessible sans intervention
8La base est sauvegardéesudo sh -c "zcat /root/actus-*.sql.gz | grep -c 'CREATE TABLE'"Nombre de tables non nul
Suis ta progressionConnecte-toi pour marquer les ressources comme terminées et retrouver ton avancement.
Se connecter