🛠 Outils IT
🛠 78 outils 📚 32 docs
🤖 Assistant

Docker

1. Installation

1.1 Installation sur Debian / Ubuntu

Supprimez d'abord les anciennes versions si elles existent :

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

Installez les prérequis et ajoutez le dépôt officiel Docker :

# Installer les dépendances
sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg lsb-release

# Ajouter la clé GPG officielle Docker
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg

# Ajouter le dépôt Docker
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# Installer Docker Engine
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Astuce : Pour Debian, remplacez ubuntu par debian dans l'URL du dépôt et utilisez $(. /etc/os-release && echo "$VERSION_CODENAME") au lieu de $(lsb_release -cs).

1.2 Installation sur CentOS / RHEL / Rocky Linux

# Supprimer les anciennes versions
sudo yum remove docker docker-client docker-client-latest docker-common \
    docker-latest docker-latest-logrotate docker-logrotate docker-engine

# Installer le dépôt Docker
sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

# Installer Docker Engine
sudo yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

# Démarrer et activer Docker
sudo systemctl start docker
sudo systemctl enable docker

1.3 Post-installation (toutes distributions)

Ajoutez votre utilisateur au groupe docker pour éviter d'utiliser sudo en permanence :

# Ajouter l'utilisateur courant au groupe docker
sudo usermod -aG docker $USER

# Appliquer les changements (ou se déconnecter/reconnecter)
newgrp docker

# Vérifier que Docker fonctionne
docker run hello-world
Attention : Ajouter un utilisateur au groupe docker lui donne un accès équivalent à root sur la machine. Ne le faites que pour les utilisateurs de confiance.

1.4 Configurer le démon Docker

Le fichier de configuration principal est /etc/docker/daemon.json :

{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  },
  "storage-driver": "overlay2",
  "default-address-pools": [
    { "base": "172.20.0.0/16", "size": 24 }
  ],
  "dns": ["8.8.8.8", "8.8.4.4"]
}

Après modification, redémarrez le démon :

sudo systemctl restart docker
Astuce : Configurez toujours la rotation des logs via daemon.json. Sans limite, les fichiers de logs peuvent remplir le disque rapidement sur un serveur en production.

2. Commandes essentielles

2.1 Gestion des images

# Télécharger une image depuis Docker Hub
docker pull nginx:latest
docker pull php:8.2-fpm-alpine

# Lister les images locales
docker images
docker image ls

# Lister les images avec filtre
docker images --filter "dangling=true"
docker images | grep nginx

# Supprimer une image
docker rmi nginx:latest
docker image rm nginx:latest

# Supprimer toutes les images non utilisées
docker image prune -a

# Inspecter une image (couches, variables, ports)
docker image inspect nginx:latest

# Voir l'historique de construction d'une image
docker image history nginx:latest

# Sauvegarder / Charger une image (transfert hors-ligne)
docker save -o mon_image.tar nginx:latest
docker load -i mon_image.tar

2.2 Gestion des conteneurs

# Lancer un conteneur en arrière-plan
docker run -d --name mon-nginx -p 8080:80 nginx:latest

# Lancer un conteneur interactif (shell)
docker run -it --rm ubuntu:22.04 /bin/bash

# Lister les conteneurs en cours d'exécution
docker ps

# Lister tous les conteneurs (y compris arrêtés)
docker ps -a

# Lister avec format personnalisé
docker ps --format "table {{.ID}}\t{{.Names}}\t{{.Status}}\t{{.Ports}}"

# Arrêter / Démarrer / Redémarrer un conteneur
docker stop mon-nginx
docker start mon-nginx
docker restart mon-nginx

# Arrêter tous les conteneurs en cours
docker stop $(docker ps -q)

# Supprimer un conteneur
docker rm mon-nginx

# Supprimer un conteneur en cours d'exécution (forcé)
docker rm -f mon-nginx

# Supprimer tous les conteneurs arrêtés
docker container prune

# Exécuter une commande dans un conteneur actif
docker exec -it mon-nginx /bin/bash
docker exec mon-nginx nginx -t

# Copier des fichiers entre hôte et conteneur
docker cp fichier.conf mon-nginx:/etc/nginx/conf.d/
docker cp mon-nginx:/var/log/nginx/access.log ./access.log

# Voir les stats en temps réel (CPU, RAM, réseau)
docker stats
docker stats mon-nginx

# Inspecter un conteneur (config, réseau, volumes)
docker inspect mon-nginx

# Voir les processus dans un conteneur
docker top mon-nginx

2.3 Logs

# Voir les logs d'un conteneur
docker logs mon-nginx

# Suivre les logs en temps réel
docker logs -f mon-nginx

# Logs avec horodatage
docker logs -t mon-nginx

# Derniers N logs
docker logs --tail 100 mon-nginx

# Logs depuis une date
docker logs --since 2024-01-15T10:00:00 mon-nginx
docker logs --since 30m mon-nginx

# Combiner les options
docker logs -f --tail 50 -t mon-nginx
Astuce : Utilisez docker logs --since 1h mon-conteneur 2>&1 | grep -i error pour rechercher rapidement les erreurs de la dernière heure.

3. Dockerfile

3.1 Syntaxe de base

Un Dockerfile définit les instructions pour construire une image Docker :

# Image de base
FROM php:8.2-apache

# Métadonnées
LABEL maintainer="admin@example.com"
LABEL version="1.0"
LABEL description="Application PHP avec Apache"

# Variables d'environnement
ENV APP_ENV=production
ENV APP_DEBUG=false

# Installer des paquets système
RUN apt-get update && apt-get install -y \
    libpng-dev \
    libjpeg-dev \
    libfreetype6-dev \
    zip unzip \
    && docker-php-ext-configure gd --with-freetype --with-jpeg \
    && docker-php-ext-install gd pdo pdo_mysql opcache \
    && apt-get clean && rm -rf /var/lib/apt/lists/*

# Répertoire de travail
WORKDIR /var/www/html

# Copier les fichiers de l'application
COPY --chown=www-data:www-data . /var/www/html/

# Exposer le port
EXPOSE 80

# Commande de démarrage
CMD ["apache2-foreground"]

3.2 Instructions principales

Instruction Description Exemple
FROM Image de base FROM ubuntu:22.04
RUN Exécute une commande lors du build RUN apt-get update && apt-get install -y curl
COPY Copie des fichiers depuis le contexte de build COPY ./app /var/www/html
ADD Comme COPY + décompression automatique des archives ADD archive.tar.gz /opt/
WORKDIR Définit le répertoire de travail WORKDIR /app
ENV Définit une variable d'environnement ENV NODE_ENV=production
ARG Variable de build uniquement ARG PHP_VERSION=8.2
EXPOSE Documente le port exposé EXPOSE 80 443
VOLUME Déclare un point de montage VOLUME /data
CMD Commande par défaut (remplacable au run) CMD ["nginx", "-g", "daemon off;"]
ENTRYPOINT Point d'entrée fixe du conteneur ENTRYPOINT ["docker-entrypoint.sh"]
HEALTHCHECK Vérification de santé du conteneur HEALTHCHECK CMD curl -f http://localhost/ || exit 1
USER Définit l'utilisateur d'exécution USER www-data

3.3 Bonnes pratiques

  • Minimiser les couches : Regroupez les commandes RUN avec && pour réduire le nombre de couches.
  • Utiliser des images Alpine : Préférez php:8.2-fpm-alpine à php:8.2-fpm (image 5x plus petite).
  • Nettoyer le cache : Ajoutez && apt-get clean && rm -rf /var/lib/apt/lists/* après chaque apt-get install.
  • Utiliser un .dockerignore : Excluez les fichiers inutiles du contexte de build.
  • Ordonner les instructions : Placez les instructions qui changent rarement en haut (FROM, RUN apt install) et les fichiers applicatifs en bas pour optimiser le cache.
  • Ne pas exécuter en root : Utilisez USER pour définir un utilisateur non-root.
  • Utiliser COPY plutôt que ADD : Sauf si vous avez besoin de la décompression automatique.
  • Ajouter un HEALTHCHECK : Pour permettre à Docker de surveiller la santé du service.

Exemple de fichier .dockerignore :

.git
.gitignore
node_modules
*.md
docker-compose*.yml
Dockerfile
.env
.env.*
logs/
tmp/

3.4 Build multi-stage

Le multi-stage build permet de séparer les étapes de compilation et d'exécution, pour produire une image finale légère :

# ---- Étape 1 : Build ----
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build

# ---- Étape 2 : Image finale ----
FROM nginx:alpine AS production
COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
    CMD curl -f http://localhost/ || exit 1
CMD ["nginx", "-g", "daemon off;"]
Astuce : Le multi-stage est particulièrement utile pour les applications compilées (Go, Rust, Java, Node.js). L'image finale ne contient que le binaire/les fichiers nécessaires, pas les outils de build.

Construire l'image :

# Build standard
docker build -t mon-app:1.0 .

# Build avec arguments
docker build --build-arg PHP_VERSION=8.2 -t mon-app:1.0 .

# Build avec un fichier Dockerfile alternatif
docker build -f Dockerfile.prod -t mon-app:prod .

# Build sans cache
docker build --no-cache -t mon-app:1.0 .

# Build ciblant une étape spécifique du multi-stage
docker build --target builder -t mon-app:build .

4. Docker Compose

4.1 Structure de base

Docker Compose permet de définir et gérer des applications multi-conteneurs via un fichier docker-compose.yml :

services:
  web:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./html:/usr/share/nginx/html:ro
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
    depends_on:
      - php
    restart: unless-stopped
    networks:
      - frontend

  php:
    build:
      context: ./php
      dockerfile: Dockerfile
    volumes:
      - ./html:/var/www/html
    environment:
      - DB_HOST=db
      - DB_NAME=myapp
    depends_on:
      db:
        condition: service_healthy
    restart: unless-stopped
    networks:
      - frontend
      - backend

  db:
    image: mariadb:10.11
    volumes:
      - db_data:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD_FILE: /run/secrets/db_root_password
      MYSQL_DATABASE: myapp
      MYSQL_USER: myapp_user
      MYSQL_PASSWORD_FILE: /run/secrets/db_password
    secrets:
      - db_root_password
      - db_password
    healthcheck:
      test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
      interval: 10s
      timeout: 5s
      retries: 5
    restart: unless-stopped
    networks:
      - backend

volumes:
  db_data:
    driver: local

networks:
  frontend:
  backend:

secrets:
  db_root_password:
    file: ./secrets/db_root_password.txt
  db_password:
    file: ./secrets/db_password.txt

4.2 Commandes Docker Compose

# Démarrer tous les services en arrière-plan
docker compose up -d

# Démarrer et forcer le rebuild des images
docker compose up -d --build

# Démarrer un service spécifique
docker compose up -d web

# Arrêter tous les services
docker compose down

# Arrêter et supprimer les volumes associés
docker compose down -v

# Voir le statut des services
docker compose ps

# Voir les logs de tous les services
docker compose logs

# Suivre les logs d'un service spécifique
docker compose logs -f php

# Exécuter une commande dans un service
docker compose exec php bash
docker compose exec db mysql -u root -p

# Redémarrer un service
docker compose restart php

# Mettre à jour un service sans arrêter les autres
docker compose up -d --no-deps --build php

# Valider la syntaxe du fichier compose
docker compose config

# Voir la configuration résolue (avec variables substituées)
docker compose config --resolve-image-digests

4.3 Variables d'environnement

Plusieurs méthodes pour passer des variables d'environnement :

Méthode 1 : Directement dans le compose

services:
  web:
    environment:
      - APP_ENV=production
      - APP_DEBUG=false

Méthode 2 : Fichier .env

Créez un fichier .env à côté du docker-compose.yml :

# .env
MYSQL_ROOT_PASSWORD=motdepasse_securise
MYSQL_DATABASE=myapp
PHP_VERSION=8.2
NGINX_PORT=80

Puis référencez-les dans le compose :

services:
  db:
    image: mariadb:10.11
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_DATABASE: ${MYSQL_DATABASE}
  web:
    ports:
      - "${NGINX_PORT}:80"

Méthode 3 : Fichier env_file dédié

services:
  web:
    env_file:
      - ./config/app.env
      - ./config/db.env
Attention : Ne versionnez jamais les fichiers .env contenant des mots de passe. Ajoutez .env dans votre .gitignore et fournissez un fichier .env.example comme modèle.

4.4 Profiles et déploiement conditionnel

Les profiles permettent de définir des services optionnels (debug, monitoring, etc.) :

services:
  web:
    image: nginx:alpine
    # Pas de profile = démarre toujours

  phpmyadmin:
    image: phpmyadmin:latest
    ports:
      - "8080:80"
    profiles:
      - debug

  mailhog:
    image: mailhog/mailhog
    ports:
      - "8025:8025"
    profiles:
      - debug
# Démarrer uniquement les services sans profile
docker compose up -d

# Démarrer avec les services debug
docker compose --profile debug up -d

5. Volumes et persistance des données

5.1 Types de montage

Docker propose trois types de montage pour la persistance des données :

Type Description Usage recommandé
volume Géré par Docker dans /var/lib/docker/volumes/ Bases de données, données persistantes
bind mount Montage d'un répertoire de l'hôte Développement, fichiers de configuration
tmpfs Stocké en mémoire RAM uniquement Données temporaires, secrets

5.2 Volumes nommés (recommandé)

# Créer un volume
docker volume create mon_volume

# Lister les volumes
docker volume ls

# Inspecter un volume (voir le chemin sur l'hôte)
docker volume inspect mon_volume

# Utiliser un volume avec docker run
docker run -d --name db \
    -v db_data:/var/lib/mysql \
    mariadb:10.11

# Supprimer un volume
docker volume rm mon_volume

# Supprimer tous les volumes non utilisés
docker volume prune

5.3 Bind mounts

# Monter un répertoire de l'hôte
docker run -d --name web \
    -v /srv/www:/usr/share/nginx/html:ro \
    -v /srv/nginx/nginx.conf:/etc/nginx/nginx.conf:ro \
    nginx:alpine

# Syntaxe longue (--mount), plus explicite
docker run -d --name web \
    --mount type=bind,source=/srv/www,target=/usr/share/nginx/html,readonly \
    nginx:alpine

5.4 Volumes dans Docker Compose

services:
  db:
    image: mariadb:10.11
    volumes:
      # Volume nommé (persistance gérée par Docker)
      - db_data:/var/lib/mysql
      # Bind mount en lecture seule pour la config
      - ./config/my.cnf:/etc/mysql/conf.d/custom.cnf:ro
      # Bind mount pour les scripts d'init
      - ./init-db:/docker-entrypoint-initdb.d

volumes:
  db_data:
    driver: local
    # Optionnel : stocker le volume à un emplacement spécifique
    driver_opts:
      type: none
      device: /mnt/data/mysql
      o: bind

5.5 Sauvegarder et restaurer un volume

# Sauvegarder un volume dans une archive tar
docker run --rm \
    -v db_data:/source:ro \
    -v $(pwd):/backup \
    alpine tar czf /backup/db_data_backup.tar.gz -C /source .

# Restaurer un volume depuis une archive
docker run --rm \
    -v db_data:/target \
    -v $(pwd):/backup \
    alpine sh -c "cd /target && tar xzf /backup/db_data_backup.tar.gz"
Astuce : Pour les bases de données, préférez un dump logique (mysqldump, pg_dump) plutôt qu'une copie des fichiers bruts du volume. C'est plus fiable et portable.

6. Réseaux Docker

6.1 Types de réseaux

Driver Description Usage
bridge Réseau isolé par défaut. Les conteneurs communiquent entre eux via DNS interne. Cas général, applications sur un seul hôte
host Le conteneur utilise directement la pile réseau de l'hôte. Pas d'isolation. Performance réseau maximale, monitoring
overlay Réseau multi-hôte pour Docker Swarm. Clusters, microservices distribués
macvlan Attribue une adresse MAC propre au conteneur, visible sur le LAN. Intégration réseau LAN, appareils IoT
none Aucune connectivité réseau. Sécurité, traitements isolés

6.2 Commandes réseau

# Lister les réseaux
docker network ls

# Créer un réseau bridge personnalisé
docker network create mon_reseau
docker network create --subnet=172.28.0.0/16 --gateway=172.28.0.1 mon_reseau

# Inspecter un réseau (voir les conteneurs connectés)
docker network inspect mon_reseau

# Connecter un conteneur existant à un réseau
docker network connect mon_reseau mon-conteneur

# Déconnecter un conteneur d'un réseau
docker network disconnect mon_reseau mon-conteneur

# Supprimer un réseau
docker network rm mon_reseau

# Supprimer tous les réseaux inutilisés
docker network prune

6.3 Réseau bridge personnalisé (recommandé)

Les réseaux bridge personnalisés offrent la résolution DNS automatique par nom de conteneur, contrairement au bridge par défaut :

# Créer un réseau
docker network create app_network

# Lancer des conteneurs sur ce réseau
docker run -d --name web --network app_network nginx:alpine
docker run -d --name api --network app_network node:20-alpine

# Le conteneur "web" peut joindre "api" par son nom
# curl http://api:3000 fonctionne depuis le conteneur "web"
Attention : Le réseau bridge par défaut (docker0) ne supporte PAS la résolution DNS par nom. Créez toujours un réseau bridge personnalisé pour vos applications multi-conteneurs.

6.4 Réseau host

# Le conteneur partage la pile réseau de l'hôte
# Pas besoin de mapper les ports (-p)
docker run -d --name monitoring --network host prometheus:latest
Astuce : Le mode host est utile pour les outils de monitoring ou de découverte réseau qui ont besoin de voir tout le trafic de l'hôte. En revanche, il supprime complètement l'isolation réseau.

6.5 Réseau macvlan

Permet d'attribuer une adresse IP du LAN directement au conteneur :

# Créer un réseau macvlan
docker network create -d macvlan \
    --subnet=192.168.1.0/24 \
    --gateway=192.168.1.1 \
    -o parent=eth0 \
    lan_network

# Lancer un conteneur avec une IP fixe sur le LAN
docker run -d --name srv-dns \
    --network lan_network \
    --ip 192.168.1.50 \
    pihole/pihole:latest

7. Docker Registry

7.1 Docker Hub

# Se connecter à Docker Hub
docker login

# Se connecter avec un token (CI/CD)
echo $DOCKER_TOKEN | docker login -u monuser --password-stdin

# Taguer une image pour le push
docker tag mon-app:1.0 monuser/mon-app:1.0
docker tag mon-app:1.0 monuser/mon-app:latest

# Pousser l'image
docker push monuser/mon-app:1.0
docker push monuser/mon-app:latest

# Télécharger une image
docker pull monuser/mon-app:1.0

# Se déconnecter
docker logout

7.2 Registry privé

Déployer un registry privé pour stocker vos images en interne :

# Lancer un registry privé
docker run -d -p 5000:5000 --restart=always \
    --name registry \
    -v registry_data:/var/lib/registry \
    registry:2

# Taguer et pousser vers le registry privé
docker tag mon-app:1.0 srv-registry.local:5000/mon-app:1.0
docker push srv-registry.local:5000/mon-app:1.0

# Télécharger depuis le registry privé
docker pull srv-registry.local:5000/mon-app:1.0

# Lister les images du registry (API v2)
curl -s http://srv-registry.local:5000/v2/_catalog | python3 -m json.tool

# Lister les tags d'une image
curl -s http://srv-registry.local:5000/v2/mon-app/tags/list | python3 -m json.tool
Attention : Par défaut, Docker refuse les registries HTTP (non-sécurisés). Pour un registry en HTTP, ajoutez-le dans /etc/docker/daemon.json :
{
  "insecure-registries": ["srv-registry.local:5000"]
}

7.3 Se connecter à d'autres registries

# GitHub Container Registry (ghcr.io)
echo $GITHUB_TOKEN | docker login ghcr.io -u USERNAME --password-stdin
docker push ghcr.io/USERNAME/mon-app:1.0

# GitLab Container Registry
docker login registry.gitlab.com
docker push registry.gitlab.com/groupe/projet/mon-app:1.0

# AWS ECR
aws ecr get-login-password --region eu-west-1 | docker login --username AWS --password-stdin 123456789.dkr.ecr.eu-west-1.amazonaws.com

7.4 Stratégie de tags

Adoptez une convention de nommage claire pour vos images :

# Tag par version sémantique
docker tag mon-app:build monuser/mon-app:1.2.3
docker tag mon-app:build monuser/mon-app:1.2
docker tag mon-app:build monuser/mon-app:1
docker tag mon-app:build monuser/mon-app:latest

# Tag par commit Git (utile en CI/CD)
docker tag mon-app:build monuser/mon-app:$(git rev-parse --short HEAD)

# Tag par date
docker tag mon-app:build monuser/mon-app:$(date +%Y%m%d-%H%M%S)
Astuce : Ne dépendez jamais uniquement du tag latest en production. Utilisez toujours un tag versionné explicite pour garantir la reproductibilité des déploiements.

8. Commandes de maintenance

8.1 Espace disque

# Voir l'espace utilisé par Docker (résumé)
docker system df

# Version détaillée (chaque image, conteneur, volume)
docker system df -v

8.2 Nettoyage (prune)

# Nettoyage complet (ATTENTION : supprime beaucoup de choses)
# Supprime : conteneurs arrêtés, réseaux inutilisés, images pendantes, cache de build
docker system prune

# Nettoyage complet + images non utilisées + volumes orphelins
docker system prune -a --volumes

# Nettoyage ciblé par type
docker container prune    # Conteneurs arrêtés
docker image prune         # Images dangling (sans tag)
docker image prune -a      # Toutes les images non utilisées
docker volume prune        # Volumes orphelins
docker network prune       # Réseaux inutilisés
docker builder prune       # Cache de build

# Supprimer les images de plus de 24h
docker image prune -a --filter "until=24h"

# Nettoyage sans confirmation
docker system prune -f
Attention : docker system prune -a --volumes est destructif. Il supprimera toutes les images non utilisées par un conteneur actif ET tous les volumes orphelins. Vérifiez avec docker system df -v avant d'exécuter cette commande.

8.3 Gestion des logs

# Voir la taille des logs de chaque conteneur
du -sh /var/lib/docker/containers/*/*-json.log

# Tronquer les logs d'un conteneur spécifique (sans redémarrage)
truncate -s 0 $(docker inspect --format='{{.LogPath}}' mon-conteneur)

# Configurer la rotation des logs globalement (/etc/docker/daemon.json)
{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}

# Configurer la rotation pour un conteneur spécifique
docker run -d \
    --log-opt max-size=5m \
    --log-opt max-file=3 \
    --name mon-app \
    mon-image:latest

8.4 Mise à jour des images

# Vérifier si des mises à jour sont disponibles
docker pull nginx:latest

# Mettre à jour un service Compose
docker compose pull
docker compose up -d

# Mettre à jour un service spécifique
docker compose pull db
docker compose up -d --no-deps db

# Script de mise à jour avec vérification de changement
#!/bin/bash
IMAGE="nginx:latest"
OLD_DIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' $IMAGE 2>/dev/null)
docker pull $IMAGE
NEW_DIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' $IMAGE)
if [ "$OLD_DIGEST" != "$NEW_DIGEST" ]; then
    echo "Image mise à jour, redémarrage du conteneur..."
    docker compose up -d --no-deps web
else
    echo "Image déjà à jour."
fi

8.5 Surveillance

# Stats en temps réel de tous les conteneurs
docker stats

# Stats formatées
docker stats --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.NetIO}}\t{{.BlockIO}}"

# Vérifier l'état de santé des conteneurs
docker ps --filter "health=unhealthy"

# Événements Docker en temps réel
docker events

# Événements filtrés
docker events --filter 'type=container' --filter 'event=die'
docker events --since '1h'
Astuce : Automatisez le nettoyage avec un cron job. Exemple : 0 3 * * 0 docker system prune -f --filter "until=168h" supprime chaque dimanche les ressources inutilisées de plus de 7 jours.

9. Dépannage courant

9.1 Le conteneur ne démarre pas

# Vérifier les logs du conteneur
docker logs mon-conteneur

# Inspecter la configuration
docker inspect mon-conteneur

# Vérifier l'état de sortie
docker inspect --format='{{.State.ExitCode}}' mon-conteneur
docker inspect --format='{{.State.Error}}' mon-conteneur

# Lancer le conteneur en mode interactif pour débugger
docker run -it --entrypoint /bin/sh mon-image:latest

9.2 Problèmes de réseau

# Vérifier l'adresse IP d'un conteneur
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' mon-conteneur

# Vérifier la connectivité entre conteneurs
docker exec mon-conteneur ping -c 3 autre-conteneur

# Vérifier la résolution DNS dans un conteneur
docker exec mon-conteneur nslookup autre-conteneur

# Tester un port depuis l'intérieur du conteneur
docker exec mon-conteneur curl -v http://autre-conteneur:8080

# Vérifier les ports exposés
docker port mon-conteneur

# Vérifier iptables (si les ports ne sont pas accessibles)
sudo iptables -L -n -t nat | grep DOCKER

9.3 Problèmes de permissions

# Vérifier l'utilisateur du conteneur
docker exec mon-conteneur whoami
docker exec mon-conteneur id

# Vérifier les permissions dans le volume
docker exec mon-conteneur ls -la /var/www/html

# Corriger les permissions (depuis l'hôte)
# UID 33 = www-data dans les images Debian/Ubuntu
sudo chown -R 33:33 /chemin/du/volume

# Corriger les permissions (dans le conteneur)
docker exec mon-conteneur chown -R www-data:www-data /var/www/html

# Lancer avec un utilisateur spécifique
docker run -u 1000:1000 mon-image:latest
Astuce : Les problèmes de permissions sur les bind mounts sont très fréquents. Vérifiez que l'UID/GID de l'utilisateur dans le conteneur correspond bien à celui qui possède les fichiers sur l'hôte.

9.4 Espace disque saturé

# Diagnostic rapide
docker system df
df -h /var/lib/docker

# Identifier les plus gros conteneurs (logs)
du -sh /var/lib/docker/containers/* | sort -rh | head -10

# Identifier les plus gros volumes
docker system df -v | grep -A 100 "VOLUME NAME"

# Nettoyage d'urgence
docker container prune -f
docker image prune -a -f
docker builder prune -f

# Tronquer les logs de TOUS les conteneurs
for c in $(docker ps -aq); do truncate -s 0 $(docker inspect --format='{{.LogPath}}' $c); done

9.5 Conteneur qui consomme trop de ressources

# Identifier le conteneur gourmand
docker stats --no-stream

# Limiter la mémoire
docker run -d --memory=512m --memory-swap=1g mon-image:latest

# Limiter le CPU
docker run -d --cpus=1.5 mon-image:latest

# Limiter dans Docker Compose
services:
  web:
    image: nginx:alpine
    deploy:
      resources:
        limits:
          cpus: '1.0'
          memory: 512M
        reservations:
          cpus: '0.5'
          memory: 256M

9.6 Problèmes courants avec Docker Compose

# "port is already allocated"
# Un autre service utilise déjà le port
sudo lsof -i :80
sudo ss -tlnp | grep :80

# "network not found" après un docker compose down
docker network prune
docker compose up -d

# "image not found" - forcer le rebuild
docker compose build --no-cache
docker compose up -d --build

# "depends_on" ne suffit pas (le service n'est pas prêt)
# Utilisez la condition "service_healthy" avec un healthcheck
services:
  app:
    depends_on:
      db:
        condition: service_healthy
  db:
    healthcheck:
      test: ["CMD", "pg_isready", "-U", "postgres"]
      interval: 5s
      timeout: 3s
      retries: 10

9.7 Démon Docker en panne

# Vérifier le statut du service
sudo systemctl status docker

# Redémarrer Docker
sudo systemctl restart docker

# Voir les logs du démon
sudo journalctl -u docker --since "10 minutes ago"
sudo journalctl -u docker -f

# Vérifier la configuration
docker info
dockerd --validate

9.8 Commandes utiles de debug

# Lancer un conteneur de debug sur le même réseau
docker run -it --rm --network container:mon-conteneur nicolaka/netshoot

# Lancer un conteneur de debug avec accès au PID namespace
docker run -it --rm --pid container:mon-conteneur alpine sh

# Obtenir un dump complet de la config d'un conteneur
docker inspect mon-conteneur | python3 -m json.tool

# Voir les différences entre l'image et le conteneur en cours
docker diff mon-conteneur

# Exporter un filesystem de conteneur pour analyse
docker export mon-conteneur > conteneur_fs.tar
Astuce : L'image nicolaka/netshoot est un outil précieux pour le dépannage réseau. Elle contient curl, ping, dig, nslookup, tcpdump, iperf et bien d'autres outils réseau, le tout dans un conteneur léger.