RousselTMLEARNING

Conteneurisation

Bonnes pratiques Docker : images, exécution, sécurité et exploitation

Les bonnes pratiques Docker : Dockerfile et builds multi-étapes, images minimales et reproductibles, exécution sans privilèges, limites de ressources, secrets, analyse de vulnérabilités, Compose, journaux et nettoyage.

1. Construire de bonnes images #

Petites, reproductibles et sûres.

Vue d'ensemble #

Familles de bonnes pratiques Docker
Chaque famille est détaillée dans cet article.

Dockerfile optimisé #

Build multi-étapes
L'image finale ne contient ni compilateur ni code source.
# syntax=docker/dockerfile:1
FROM golang:1.23-alpine AS build
WORKDIR /src
COPY go.mod go.sum ./
RUN --mount=type=cache,target=/go/pkg/mod go mod download      # couche de dépendances mise en cache
COPY . .
RUN CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o /out/app ./cmd/app

FROM gcr.io/distroless/static-debian12:nonroot
COPY --from=build /out/app /app
EXPOSE 8080
USER nonroot:nonroot
ENTRYPOINT ["/app"]
# .dockerignore : réduire le contexte de build et éviter les fuites
.git
node_modules
*.log
.env
**/*.pem

Reproductibilité #

  • Épinglez les versions : python:3.12.7-slim, jamais latest ; idéalement le digest (image@sha256:...).
  • Un processus par conteneur, journaux sur stdout/stderr.
  • Regroupez les RUN liés et nettoyez dans la même couche (apt-get ... && rm -rf /var/lib/apt/lists/*).
  • Ordonnez du moins changeant (dépendances) au plus changeant (code) pour exploiter le cache.
docker buildx build --platform linux/amd64,linux/arm64 -t registre.exemple.fr/shop/api:1.4.2 --push .
docker image inspect nginx:1.27 --format '{{index .RepoDigests 0}}'      # récupérer le digest
docker history --no-trunc registre.exemple.fr/shop/api:1.4.2 | head       # tailles par couche
docker run --rm wagoodman/dive:latest registre.exemple.fr/shop/api:1.4.2   # explorer les couches

2. Exécuter avec le moindre privilège #

Réduire la surface d'attaque.

Un conteneur durci #

docker run -d --name api \
  --user 10001:10001 \
  --read-only --tmpfs /tmp:rw,noexec,nosuid,size=64m \
  --cap-drop ALL --security-opt no-new-privileges:true \
  --memory 512m --memory-swap 512m --cpus 1.0 --pids-limit 200 \
  --restart unless-stopped \
  --health-cmd "wget -qO- http://localhost:8080/health || exit 1" --health-interval 30s \
  -p 127.0.0.1:8080:8080 \
  registre.exemple.fr/shop/api:1.4.2
OptionEffet
--userNe jamais exécuter en root
--read-onlySystème de fichiers en lecture seule (+ tmpfs si besoin)
--cap-drop ALLRetire toutes les capabilities Linux
no-new-privilegesInterdit l'élévation de privilèges
--memory / --cpusÉvite qu'un conteneur monopolise l'hôte
-p 127.0.0.1:...N'expose qu'en local derrière un reverse proxy
Erreur Courante : Ne montez jamais /var/run/docker.sock dans un conteneur applicatif et n'utilisez --privileged qu'en dernier recours : cela équivaut à donner root sur l'hôte.

Mode rootless #

dockerd-rootless-setuptool.sh install            # Docker sans privilèges root
export DOCKER_HOST=unix://$XDG_RUNTIME_DIR/docker.sock
docker info --format '{{.SecurityOptions}}'      # doit contenir rootless

3. Sécuriser la chaîne d'approvisionnement #

Secrets, scan et signature.

Secrets #

# ❌ À éviter : secret dans l'image
ENV DB_PASSWORD=secret
# ✅ Secrets de build (non conservés dans l'image)
docker build --secret id=npmrc,src=$HOME/.npmrc .
# Dockerfile : RUN --mount=type=secret,id=npmrc cp /run/secrets/npmrc .npmrc && npm ci
# ✅ Secrets à l'exécution (Compose / Swarm)
services:
  api:
    secrets: [db_password]
secrets:
  db_password: { file: ./secrets/db_password.txt }

Analyse et signature #

Analyse de vulnérabilités avec Trivy
Intégrez cette étape dans la CI et bloquez sur les vulnérabilités critiques.
trivy image --exit-code 1 --severity CRITICAL registre.exemple.fr/shop/api:1.4.2   # échoue la CI
trivy config .                                                              # Dockerfile / manifestes
cosign sign --key cosign.key registre.exemple.fr/shop/api:1.4.2             # signer
cosign verify --key cosign.pub registre.exemple.fr/shop/api:1.4.2           # vérifier avant déploiement
hadolint Dockerfile                                                         # linter de Dockerfile

4. Compose et exploitation #

Du poste de dev à la production.

Compose bien écrit #

services:
  api:
    image: registre.exemple.fr/shop/api:1.4.2
    env_file: [.env]
    depends_on: { db: { condition: service_healthy } }
    deploy: { resources: { limits: { cpus: "1", memory: 512M } } }
    logging: { driver: json-file, options: { max-size: "10m", max-file: "5" } }    # rotation des logs
    healthcheck: { test: ["CMD", "wget", "-qO-", "http://localhost:8080/health"], interval: 30s, retries: 3 }
    networks: [backend]
  db:
    image: postgres:16.4
    volumes: [pgdata:/var/lib/postgresql/data]
    networks: [backend]
networks: { backend: { internal: true } }          # pas d'accès Internet direct pour la base
volumes: { pgdata: {} }
docker compose config                          # valider et afficher la configuration finale

Supervision et nettoyage #

docker stats --no-stream --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}"
docker events --filter event=die --since 1h
docker inspect --format '{{.State.OOMKilled}} {{.State.ExitCode}}' api       # OOM ?
docker system df -v
docker system prune -af --filter "until=168h"       # supprimer ce qui est inutilisé depuis 7 jours
Bonne Pratique : Collectez les logs avec Alloy ou Fluent Bit plutôt qu'avec docker logs et exposez les métriques des conteneurs avec cAdvisor pour Prometheus.

Articles liés

Sécurité réseau des conteneurs (container network security) et networking Kubernetes

Sécuriser le réseau des conteneurs : fonctionnement du networking Docker et Kubernetes, CNI, NetworkPolicies …

Container registry : choisir et sécuriser son registre d'images (Docker Hub, Harbor, GHCR, ECR)

Comprendre les registres de conteneurs : Docker Hub, GitHub Container Registry, registres cloud (ECR, ACR, Ar…

Docker : vue d'ensemble, architecture et premiers pas

Découvrir Docker : conteneurs vs machines virtuelles, architecture client/daemon/registre, images et couches,…

Pour aller plus loin

Soutenir

♥ SOUTENIR

Soutenez RousselTM Learning

Les formations, articles, TP et attestations restent gratuits et sans publicité intrusive. Une contribution libre, du montant de votre choix, finance l’hébergement, les environnements de TP et l’écriture de nouveaux contenus.

Contribuer avec PayPal Montant libre · carte bancaire ou compte PayPalEn savoir plus
QR code PayPal
Ou scannez ce QR code avec votre téléphone

Merci, chaque contribution compte !