Docker sur Linux : installation et gestion en prod

Administration Serveur 10/04/2026 22:00:00 angularforall.com
Docker Linux Docker-Compose Nginx Production Containers Devops Deployment
Docker sur Linux : installation et gestion en prod

Installez et gérez Docker + Docker Compose sur Ubuntu/Debian : networks, volumes, Nginx reverse proxy, healthchecks, logs et cleanup automatique en production.

Installer Docker et Docker Compose sur Ubuntu/Debian

L'installation de Docker via le script officiel est la méthode la plus rapide et la plus fiable sur Ubuntu 22.04 / Debian 12. Elle installe automatiquement les dépendances, configure le dépôt GPG officiel et installe la dernière version stable.

Installation via le script officiel

Cette commande télécharge et exécute le script d'installation fourni par Docker Inc. :

# Télécharge et exécute le script d'installation officiel Docker
curl -fsSL https://get.docker.com | sh

# Ajoute l'utilisateur courant au groupe docker (évite de taper sudo)
sudo usermod -aG docker $USER

# Applique les changements de groupe sans se déconnecter
newgrp docker

# Vérifie que Docker est bien installé et tourne
docker --version
docker run hello-world
Note : Le script officiel ne doit pas être exécuté sur une machine de production sans audit préalable. Pour les environnements critiques, préférez l'installation manuelle via apt avec vérification de la clé GPG.

Installation manuelle via apt (recommandée en production)

Cette méthode donne un contrôle total sur les versions installées et est recommandée pour les serveurs de production :

# Supprime les anciennes versions Docker si présentes
sudo apt remove docker docker-engine docker.io containerd runc

# Met à jour la liste des paquets et installe les dépendances HTTPS
sudo apt update
sudo apt install -y ca-certificates curl gnupg lsb-release

# Crée le dossier pour la clé GPG Docker
sudo install -m 0755 -d /etc/apt/keyrings

# Télécharge et importe la clé GPG officielle Docker
curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
  | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

# Donne les permissions de lecture à la clé
sudo chmod a+r /etc/apt/keyrings/docker.gpg

# Ajoute le dépôt officiel Docker à la liste apt
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

# Installe Docker Engine, Docker CLI, containerd et Docker Compose plugin
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

# Vérifie que Docker Compose (plugin) fonctionne
docker compose version

Activer Docker au démarrage avec systemd

# Active Docker pour qu'il démarre automatiquement avec le serveur
sudo systemctl enable docker

# Démarre Docker immédiatement
sudo systemctl start docker

# Vérifie le statut du service Docker
sudo systemctl status docker
A retenir : En production, toujours activer Docker via systemd. En cas de redémarrage du serveur, tous vos containers configurés avec restart: always redémarreront automatiquement.

Concepts essentiels : images, containers, networks, volumes

Avant de déployer en production, il est crucial de maîtriser les quatre piliers de Docker. Comprendre ces concepts évite la majorité des erreurs de configuration.

Images, containers et couches

Une image Docker est un instantané en lecture seule de votre application et de ses dépendances. Un container est une instance en cours d'exécution de cette image. Plusieurs containers peuvent partager la même image de base.

# Télécharge une image depuis Docker Hub
docker pull nginx:1.25-alpine

# Liste les images disponibles localement
docker images

# Lance un container en mode détaché (-d) avec un nom explicite
# et mappe le port 8080 de la machine hôte vers le port 80 du container
docker run -d --name mon-nginx -p 8080:80 nginx:1.25-alpine

# Liste les containers en cours d'exécution
docker ps

# Liste TOUS les containers (y compris arrêtés)
docker ps -a

# Arrête proprement un container
docker stop mon-nginx

# Supprime un container arrêté
docker rm mon-nginx

Networks : isoler les services

Les réseaux Docker permettent aux containers de communiquer entre eux de façon isolée et sécurisée, sans exposer les ports internes à l'hôte.

# Crée un réseau bridge dédié à votre application
docker network create --driver bridge mon-reseau-app

# Lance un container sur ce réseau
docker run -d --name app-backend --network mon-reseau-app mon-image-app

# Lance un autre container sur le même réseau
# Les containers peuvent se joindre par leur nom (DNS interne Docker)
docker run -d --name app-db --network mon-reseau-app mysql:8.0

# Inspecte les détails d'un réseau (voir les containers connectés)
docker network inspect mon-reseau-app

# Liste tous les réseaux Docker
docker network ls

Volumes : persister les données

Les données écrites dans un container sont perdues à sa suppression. Les volumes Docker permettent de persister les données indépendamment du cycle de vie des containers.

# Crée un volume nommé pour la base de données
docker volume create mysql-data

# Monte le volume dans un container MySQL
# Les données de /var/lib/mysql sont stockées dans le volume mysql-data
docker run -d \
  --name db-mysql \
  --network mon-reseau-app \
  -v mysql-data:/var/lib/mysql \
  -e MYSQL_ROOT_PASSWORD=secretpwd \
  mysql:8.0

# Liste tous les volumes Docker
docker volume ls

# Inspecte un volume (voir son chemin réel sur l'hôte)
docker volume inspect mysql-data
Note : En production, préférez les volumes nommés (-v nom-volume:/chemin) aux montages bind (-v /chemin/hôte:/chemin/container) pour les bases de données. Les volumes nommés sont gérés par Docker et offrent de meilleures performances sur Linux.
Concept Description Usage production
Image Snapshot immuable, construit via Dockerfile Versionnée, taguée, stockée dans un registry
Container Instance en cours d'exécution d'une image Configuré avec restart policy, limites CPU/RAM
Network Réseau virtuel isolé entre containers Un réseau dédié par application/stack
Volume Stockage persistant indépendant du container Obligatoire pour BDD, uploads, configs

docker-compose.yml : exemple complet avec app et base de données

Docker Compose permet de définir et orchestrer plusieurs containers dans un seul fichier YAML déclaratif. C'est l'outil de référence pour les déploiements mono-serveur en production.

Structure du fichier docker-compose.yml

Voici un exemple complet avec une application Node.js, MySQL et un réseau dédié, incluant les bonnes pratiques de production :

# docker-compose.yml — Stack production Node.js + MySQL
# Version 3.9 est stable et supportée en production

services:
  # ----- Application Node.js -----
  app:
    # Image custom construite depuis le Dockerfile local
    build:
      context: .
      dockerfile: Dockerfile
    # Nom explicite pour faciliter le débogage
    container_name: mon-app
    # Redémarre automatiquement sauf si arrêté manuellement
    restart: unless-stopped
    # Variables d'environnement (valeurs sensibles via .env)
    environment:
      NODE_ENV: production
      DB_HOST: db          # Nom du service Docker = hostname DNS interne
      DB_PORT: 3306
      DB_NAME: ${DB_NAME}
      DB_USER: ${DB_USER}
      DB_PASSWORD: ${DB_PASSWORD}
    # Ne pas exposer le port app directement — Nginx fait le reverse proxy
    expose:
      - "3000"
    # Dépend du démarrage sain de la BDD avant de lancer l'app
    depends_on:
      db:
        condition: service_healthy
    # Limite les ressources pour éviter qu'un container monopolise le serveur
    deploy:
      resources:
        limits:
          cpus: "1.0"      # Maximum 1 vCPU
          memory: 512M     # Maximum 512 Mo de RAM
    # Réseau dédié à cette stack applicative
    networks:
      - app-network

  # ----- Base de données MySQL -----
  db:
    image: mysql:8.0
    container_name: mon-db
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_DATABASE: ${DB_NAME}
      MYSQL_USER: ${DB_USER}
      MYSQL_PASSWORD: ${DB_PASSWORD}
    # Volume nommé pour persister les données entre redémarrages
    volumes:
      - mysql-data:/var/lib/mysql
      # Optionnel : fichier d'initialisation SQL au premier démarrage
      - ./sql/init.sql:/docker-entrypoint-initdb.d/init.sql:ro
    # Contrôle de santé : vérifie que MySQL répond avant d'autoriser les dépendants
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p${MYSQL_ROOT_PASSWORD}"]
      interval: 10s       # Vérifie toutes les 10 secondes
      timeout: 5s         # Timeout de la vérification
      retries: 5          # 5 tentatives avant de marquer unhealthy
      start_period: 30s   # Délai avant la première vérification (MySQL met du temps à démarrer)
    # Pas de port exposé à l'hôte : accessible uniquement via le réseau interne
    expose:
      - "3306"
    deploy:
      resources:
        limits:
          cpus: "0.5"
          memory: 256M
    networks:
      - app-network

# ----- Volumes nommés -----
volumes:
  mysql-data:
    driver: local         # Driver local par défaut, adapté pour un seul serveur

# ----- Réseaux -----
networks:
  app-network:
    driver: bridge        # Bridge = réseau virtuel isolé sur la machine hôte

Fichier .env pour les secrets

Ne jamais stocker les mots de passe directement dans le docker-compose.yml. Utilisez un fichier .env exclu du dépôt Git :

# .env — Variables d'environnement sensibles (JAMAIS commité dans Git)
# Ajoutez .env à votre .gitignore

DB_NAME=mon_app_db
DB_USER=app_user
DB_PASSWORD=MotDePasseFort2024!
MYSQL_ROOT_PASSWORD=RootPasswordTresSecret!

Commandes Docker Compose essentielles

# Démarre tous les services en mode détaché (arrière-plan)
docker compose up -d

# Affiche les logs de tous les services en temps réel
docker compose logs -f

# Affiche les logs d'un service spécifique
docker compose logs -f app

# Arrête et supprime les containers (les volumes sont conservés)
docker compose down

# Arrête, supprime les containers ET les volumes (attention : perte de données BDD !)
docker compose down -v

# Recrée uniquement les containers dont l'image a changé
docker compose up -d --build

# Affiche le statut de tous les services
docker compose ps

# Exécute une commande dans un container en cours d'exécution
docker exec -it mon-app sh
A retenir : Toujours définir des limites mémoire et CPU dans docker-compose.yml via la clé deploy.resources.limits. Sans limites, un container défaillant peut consommer toutes les ressources du serveur et faire tomber les autres services.

Nginx comme reverse proxy devant des containers

En production, il ne faut jamais exposer directement les ports applicatifs (Node.js, PHP, etc.) à Internet. Nginx agit comme reverse proxy : il reçoit les requêtes HTTP/HTTPS et les redirige vers le bon container.

Configuration Nginx pour un container Node.js

Créez le fichier de configuration dans /etc/nginx/sites-available/mon-app :

# /etc/nginx/sites-available/mon-app
# Nginx reverse proxy vers un container Docker sur le port 3000

# Redirige tout le trafic HTTP vers HTTPS
server {
    listen 80;
    server_name monapp.exemple.com;

    # Redirection permanente vers HTTPS
    return 301 https://$host$request_uri;
}

# Configuration HTTPS principale
server {
    listen 443 ssl http2;
    server_name monapp.exemple.com;

    # Certificats Let's Encrypt (générés avec certbot)
    ssl_certificate     /etc/letsencrypt/live/monapp.exemple.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/monapp.exemple.com/privkey.pem;

    # Paramètres SSL recommandés Mozilla (Modern)
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers off;

    # En-têtes de sécurité HTTP
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header Referrer-Policy "no-referrer-when-downgrade" always;
    add_header X-XSS-Protection "1; mode=block" always;

    # Limite la taille des uploads (adapter selon l'application)
    client_max_body_size 10M;

    # Proxy vers le container Docker sur le port 3000
    # Docker crée un réseau bridge : l'hôte accède au container via 127.0.0.1:3000
    location / {
        proxy_pass         http://127.0.0.1:3000;
        proxy_http_version 1.1;

        # Headers nécessaires pour les WebSockets et les proxies en chaîne
        proxy_set_header   Upgrade $http_upgrade;
        proxy_set_header   Connection 'upgrade';
        proxy_set_header   Host $host;
        proxy_set_header   X-Real-IP $remote_addr;
        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Proto $scheme;

        # Désactive le cache Nginx pour le contenu dynamique
        proxy_cache_bypass $http_upgrade;

        # Timeouts adaptés aux APIs (ajuster si nécessaire)
        proxy_connect_timeout 60s;
        proxy_send_timeout    60s;
        proxy_read_timeout    60s;
    }

    # Chemin pour Let's Encrypt (renouvellement automatique)
    location /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }
}

Exposer le port du container vers l'hôte

Pour que Nginx sur l'hôte puisse atteindre le container, exposez le port uniquement sur l'interface locale (127.0.0.1), pas sur toutes les interfaces (0.0.0.0) :

# Dans docker-compose.yml — exposer le port seulement sur localhost
services:
  app:
    # Bind uniquement sur 127.0.0.1 : accessible depuis l'hôte (Nginx)
    # mais PAS depuis l'extérieur directement
    ports:
      - "127.0.0.1:3000:3000"

Activer la configuration et recharger Nginx

# Crée le lien symbolique pour activer le site
sudo ln -s /etc/nginx/sites-available/mon-app /etc/nginx/sites-enabled/

# Vérifie la syntaxe de la configuration Nginx
sudo nginx -t

# Recharge Nginx sans interruption de service
sudo systemctl reload nginx
Astuce : Pour les architectures multi-containers, vous pouvez aussi utiliser le container Nginx officiel dans votre stack Compose et le connecter aux autres services via le réseau interne Docker, sans exposer aucun port à l'hôte sauf 80 et 443.

Healthchecks et redémarrage automatique

Les healthchecks permettent à Docker de surveiller l'état réel de votre application, pas seulement si le processus tourne. Combinés aux restart policies, ils garantissent une haute disponibilité automatique.

HEALTHCHECK dans un Dockerfile

Ajoutez un healthcheck directement dans votre Dockerfile pour que Docker surveille l'état de santé du container :

# Dockerfile — Application Node.js avec healthcheck intégré
FROM node:20-alpine

# Installe curl pour le healthcheck (nécessaire sur Alpine)
RUN apk add --no-cache curl

WORKDIR /app

# Copie les fichiers de dépendances et installe
COPY package*.json ./
RUN npm ci --only=production

# Copie le code source de l'application
COPY . .

# Expose le port applicatif (documentation)
EXPOSE 3000

# Healthcheck : vérifie toutes les 30s que l'app répond sur /health
# --fail : retourne un code d'erreur si HTTP != 2xx
# || exit 1 : force le code de sortie 1 si curl échoue
HEALTHCHECK --interval=30s --timeout=10s --start-period=15s --retries=3 \
  CMD curl --fail http://localhost:3000/health || exit 1

# Lance l'application
CMD ["node", "server.js"]

Endpoint /health dans votre application Node.js

// server.js — Endpoint healthcheck minimal pour Docker
// Retourne 200 si l'app est saine, utilisable par le HEALTHCHECK Docker

const express = require('express');
const app = express();

// Route healthcheck — vérifiée par Docker toutes les 30 secondes
// Peut inclure des vérifications BDD, cache, dépendances externes
app.get('/health', (req, res) => {
  // Vérification simple : retourne 200 OK avec le statut
  res.status(200).json({
    status: 'healthy',
    uptime: process.uptime(),    // Temps en secondes depuis le démarrage
    timestamp: new Date().toISOString()
  });
});

app.listen(3000, () => {
  console.log('App démarrée sur le port 3000');
});

Restart policies Docker

Les restart policies définissent quand Docker doit relancer un container automatiquement :

# Dans docker-compose.yml — Restart policies
services:
  app:
    restart: unless-stopped
    # Options disponibles :
    # "no"              — ne relance jamais (défaut)
    # "always"          — relance toujours, même après docker stop
    # "on-failure"      — relance uniquement si le container quitte avec erreur
    # "unless-stopped"  — relance toujours SAUF si arrêté manuellement (recommandé prod)

Surveiller l'état de santé des containers

# Affiche le statut de tous les containers (voir colonne STATUS)
# Les containers healthy affichent "healthy", unhealthy affichent "unhealthy"
docker ps

# Inspecte les détails du healthcheck d'un container
# Affiche le log des 5 derniers checks dans "Health.Log"
docker inspect --format='{{json .State.Health}}' mon-app | python3 -m json.tool

# Surveille l'utilisation CPU/RAM en temps réel de tous les containers
docker stats

# Surveille un container spécifique
docker stats mon-app mon-db
A retenir : Un container peut être en statut "running" mais son application peut être bloquée. Sans healthcheck, Docker ne le sait pas et ne le redémarre pas. Le healthcheck est la seule façon de détecter ce type de panne silencieuse.

Gérer les logs Docker en production

Par défaut, Docker stocke tous les logs dans des fichiers JSON sur le disque. Sans configuration, ces fichiers peuvent remplir le disque en quelques semaines sur une application active. Il faut impérativement configurer la rotation des logs.

Configurer la rotation des logs globalement

Modifiez le fichier de configuration du daemon Docker pour appliquer une limite à tous les containers :

# Ouvre (ou crée) le fichier de configuration Docker daemon
sudo nano /etc/docker/daemon.json
{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}
# Recharge Docker pour appliquer la nouvelle configuration
# Attention : cela redémarre Docker, les containers "unless-stopped" reprennent automatiquement
sudo systemctl restart docker

Configurer les logs par service dans docker-compose.yml

Pour un contrôle plus fin, définissez les limites de logs au niveau de chaque service :

# docker-compose.yml — Configuration des logs par service
services:
  app:
    image: mon-image-app
    # Configuration de la rotation des logs pour ce service
    logging:
      driver: json-file
      options:
        max-size: "10m"    # Taille maximale par fichier de log
        max-file: "3"      # Nombre maximum de fichiers (rotation)
        # Total max = 10m × 3 = 30 Mo par container
        tag: "{{.Name}}/{{.ID}}"  # Tag pour identifier le container dans les logs

  db:
    image: mysql:8.0
    logging:
      driver: json-file
      options:
        max-size: "5m"
        max-file: "2"

Consulter et filtrer les logs

# Affiche les 100 dernières lignes de logs du container app
docker logs --tail 100 mon-app

# Suit les logs en temps réel (comme tail -f)
docker logs -f mon-app

# Filtre les logs depuis les 30 dernières minutes
docker logs --since 30m mon-app

# Filtre les logs entre deux timestamps
docker logs --since "2024-01-15T10:00:00" --until "2024-01-15T11:00:00" mon-app

# Affiche les logs avec les timestamps
docker logs -t mon-app

# Affiche les logs de tous les services avec docker compose
docker compose logs -f --tail 50
Note : Pour les environnements avec plusieurs serveurs ou un fort volume de logs, envisagez le driver syslog ou fluentd pour centraliser les logs dans un système comme Graylog, Loki ou Elasticsearch.

Cleanup automatique : images, containers et volumes inutilisés

Chaque build Docker crée de nouvelles couches d'image. Sans nettoyage régulier, le serveur peut se retrouver avec des dizaines de gigaoctets d'images orphelines. Un cleanup hebdomadaire automatique est indispensable.

Commandes de nettoyage Docker

# Supprime les containers arrêtés, les réseaux inutilisés,
# les images non taguées et le cache de build
docker system prune -f

# Même chose PLUS la suppression des volumes non utilisés
# ATTENTION : cette commande est irréversible pour les données !
docker system prune -af --volumes

# Supprime uniquement les images non utilisées (non taguées)
docker image prune -f

# Supprime toutes les images inutilisées (taguées et non taguées)
docker image prune -af

# Supprime uniquement les containers arrêtés
docker container prune -f

# Supprime uniquement les volumes non attachés à un container
docker volume prune -f

# Affiche l'espace disque utilisé par Docker
docker system df

Cron hebdomadaire pour le cleanup automatique

Ajoutez une tâche cron pour automatiser le nettoyage chaque semaine, la nuit, quand le serveur est moins sollicité :

# Édite la crontab de root pour le cleanup Docker
sudo crontab -e
# Cleanup Docker automatique chaque dimanche à 3h00 du matin
# Supprime images, containers et volumes inutilisés
# Les logs sont enregistrés dans /var/log/docker-cleanup.log
0 3 * * 0 docker system prune -af --volumes >> /var/log/docker-cleanup.log 2>&1

Script de cleanup avancé avec rapport

Pour un nettoyage plus intelligent avec rapport d'activité :

#!/bin/bash
# /usr/local/bin/docker-cleanup.sh
# Script de nettoyage Docker avec rapport d'utilisation disque

# Date et heure pour le rapport
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
LOG_FILE="/var/log/docker-cleanup.log"

echo "[$TIMESTAMP] Début du cleanup Docker" >> "$LOG_FILE"

# Affiche l'espace utilisé avant nettoyage
echo "[$TIMESTAMP] Espace avant nettoyage :" >> "$LOG_FILE"
docker system df >> "$LOG_FILE" 2>&1

# Lance le nettoyage (images, containers, réseaux, cache build)
# Ne supprime PAS les volumes pour éviter les pertes de données accidentelles
docker image prune -af >> "$LOG_FILE" 2>&1
docker container prune -f >> "$LOG_FILE" 2>&1
docker network prune -f >> "$LOG_FILE" 2>&1
docker builder prune -af >> "$LOG_FILE" 2>&1

# Affiche l'espace utilisé après nettoyage
echo "[$TIMESTAMP] Espace après nettoyage :" >> "$LOG_FILE"
docker system df >> "$LOG_FILE" 2>&1

echo "[$TIMESTAMP] Cleanup Docker terminé" >> "$LOG_FILE"
# Rend le script exécutable
sudo chmod +x /usr/local/bin/docker-cleanup.sh

# Ajoute à la crontab (exécution chaque dimanche à 3h)
sudo crontab -e
# Ligne à ajouter :
# 0 3 * * 0 /usr/local/bin/docker-cleanup.sh

Sécurité Docker : utilisateur non-root, capabilities, secrets

Par défaut, les processus dans un container Docker tournent en tant que root. C'est un risque de sécurité majeur en production : si un attaquant exploite une faille applicative, il a potentiellement les droits root dans le container.

Créer un utilisateur non-root dans le Dockerfile

C'est la bonne pratique la plus importante pour sécuriser vos containers :

# Dockerfile — Application Node.js avec utilisateur non-root
FROM node:20-alpine

# Installe curl pour le healthcheck
RUN apk add --no-cache curl

# Crée un groupe et un utilisateur dédié à l'application
# -S : compte système (sans shell de login)
# -G node : ajoute au groupe "node" existant dans l'image officielle
RUN addgroup -S appgroup && adduser -S appuser -G appgroup

WORKDIR /app

# Copie et installe les dépendances en tant que root (nécessaire pour npm install)
COPY package*.json ./
RUN npm ci --only=production && npm cache clean --force

# Copie le code source
COPY . .

# Donne la propriété des fichiers à l'utilisateur appuser
RUN chown -R appuser:appgroup /app

# Bascule vers l'utilisateur non-root pour tout ce qui suit
USER appuser

EXPOSE 3000

# Healthcheck (fonctionne avec l'utilisateur non-root si curl est installé)
HEALTHCHECK --interval=30s --timeout=10s --start-period=15s --retries=3 \
  CMD curl --fail http://localhost:3000/health || exit 1

CMD ["node", "server.js"]
A retenir : Ne jamais lancer Docker en mode --privileged en production sans raison explicite. Ce mode désactive pratiquement toutes les protections de sécurité du kernel Linux pour ce container.

Gérer les secrets Docker en production

En production, évitez les variables d'environnement pour les secrets très sensibles. Docker Secrets (disponible avec Docker Swarm) ou des fichiers montés en lecture seule sont plus sûrs :

# Option 1 : Monter un fichier secret en lecture seule dans le container
# Le fichier /run/secrets/db_password est accessible dans le container
# mais n'apparaît pas dans les variables d'environnement (docker inspect)
services:
  app:
    image: mon-image-app
    volumes:
      # Montage du fichier secret en lecture seule (:ro)
      - /etc/mon-app/secrets/db_password:/run/secrets/db_password:ro
    environment:
      # L'app lit le secret depuis le fichier plutôt que l'env var
      DB_PASSWORD_FILE: /run/secrets/db_password
# Option 2 : Variables d'environnement via fichier .env sécurisé
# Le fichier .env doit avoir des permissions restrictives
sudo chmod 600 /var/www/mon-app/.env
sudo chown root:docker /var/www/mon-app/.env

Bonnes pratiques de sécurité complémentaires

  • Utiliser des images officielles et vérifiées (Docker Hub Official Images)
  • Toujours spécifier un tag de version précis (jamais :latest en production)
  • Scanner les images avec docker scout ou trivy pour détecter les CVE
  • Activer le no-new-privileges pour empêcher l'élévation de privilèges
  • Limiter les capabilities Linux avec cap_drop: ALL et n'ajouter que celles nécessaires
  • Utiliser un filesystem en lecture seule quand c'est possible (read_only: true)
# docker-compose.yml — Configuration sécurité avancée
services:
  app:
    image: mon-image-app:1.2.3    # Tag de version précis, pas "latest"
    restart: unless-stopped
    # Empêche le processus d'acquérir de nouveaux privilèges
    security_opt:
      - no-new-privileges:true
    # Supprime toutes les capabilities Linux (principe du moindre privilège)
    cap_drop:
      - ALL
    # Ajoute uniquement les capabilities strictement nécessaires
    # NET_BIND_SERVICE : bind sur les ports < 1024 (si nécessaire)
    # CHOWN : changer le propriétaire de fichiers (si nécessaire)
    cap_add: []
    # Filesystem en lecture seule (l'app ne peut pas écrire sur le disque)
    # Combiner avec des volumes tmpfs pour les répertoires tmp
    read_only: true
    tmpfs:
      - /tmp:noexec,nosuid,size=64m    # /tmp temporaire en RAM

Conclusion

Docker transforme radicalement la façon de déployer et gérer des applications en production sur Linux. De l'installation via le script officiel jusqu'aux configurations de sécurité avancées, chaque étape couverte dans ce guide contribue à un environnement de production fiable, maintenable et sécurisé.

L'approche progressive recommandée est la suivante : commencez par maîtriser les commandes de base, mettez en place un fichier docker-compose.yml solide avec limits et healthchecks, configurez Nginx comme reverse proxy, puis renforcez progressivement la sécurité en supprimant root et en réduisant les capabilities. Le cleanup automatique via cron est une tâche souvent oubliée mais critique pour la longévité du serveur.

A retenir : Les quatre piliers d'un déploiement Docker production réussi sont : des containers non-root avec limits CPU/RAM, des healthchecks configurés, une rotation des logs activée, et un cleanup automatique planifié.

Partager