Skip to main content

Code that compiles on the first try! CodeWithMpia wishes you very happy holidays.✨

Aller au contenu principal

Docker pour les débutants : Le guide complet pour enfin comprendre les conteneurs

Si jongler entre machines virtuelles, dépendances capricieuses et « ça marche sur ma machine » fait partie de ton quotidien, ce guide Docker pour débutants est là pour t’aider à comprendre enfin les conteneurs et les utiliser sans prise de tête.

M
Mpia
12/17/2025 87 min
78 vues
1 comme.
#Docker#Container#Server
Docker pour les débutants : Le guide complet pour enfin comprendre les conteneurs

Tu entends parler de Docker partout. On te dit: lance juste le conteneur, maîtrise de Docker, et tu voie des docker run dans tous les tutoriels... mais tu ne comprends toujours pas ce que c'est vraiment ?

Si "ça marche sur ma machine" est ta phrase préférée et que tu as déjà passé des heures à installer des dépendances... cet article est fait pour toi.

Docker, ce n'est pas sorcier. Une fois que tu comprends le concept de base, tout devient limpide. Et je vais t'expliquer ça simplement, sans jargon inutile.

Dans ce guide, on va apprendre Docker en pratique, avec des exemples concrets et des situations réelles que tu vas rencontrer.

Ce que tu vas apprendre :

  • C'est quoi Docker et pourquoi c'est révolutionnaire

  • La différence entre conteneurs et machines virtuelles

  • Les commandes essentielles expliquées simplement

  • Créer tes propres images avec Dockerfile

  • Docker Compose pour les projets multi-conteneurs

  • Les bonnes pratiques pour ne pas galérer

  • Déployer tes applications comme un pro

Allez, on démarre de zéro ! 🚀

Partie 1 : Comprendre Docker (la théorie simple)

C'est quoi Docker, concrètement ?

Imagine que tu prépares un gâteau. Tu as la recette, les ingrédients, le bon four... et ça marche parfaitement chez toi. Maintenant, tu veux que ton ami fasse exactement le même gâteau chez lui. Problème : il n'a pas le même four, pas les mêmes ustensiles, et ses ingrédients sont légèrement différents.

Docker, c'est comme si tu pouvais emballer ta cuisine entière (four, ustensiles, ingrédients, recette) dans une boîte portable. Ton ami n'a qu'à ouvrir la boîte, et il a exactement le même environnement que toi.

En termes techniques :

Docker est une plateforme de conteneurisation. Il permet d'empaqueter une application avec toutes ses dépendances (librairies, configurations, outils) dans un "conteneur" isolé et portable.

Avec Docker, tu peux :

  • Exécuter n'importe quelle application sans installer ses dépendances

  • Garantir que ton code fonctionne partout (dev, test, prod)

  • Isoler tes applications les unes des autres

  • Déployer en quelques secondes

  • Partager ton environnement avec ton équipe

Le problème que Docker résout

Avant Docker :

Développeur : "Ça marche sur ma machine !"
Ops : "Mais pas sur le serveur..."
Développeur : "Tu as quelle version de Python ?"
Ops : "3.8"
Développeur : "Ah, il faut 3.11... et tu as installé libpq-dev ?"
Ops : "C'est quoi ça ?"
[3 heures plus tard...]

Avec Docker :

Développeur : "Voici le conteneur"
Ops : "docker run... C'est en prod."
[30 secondes plus tard...]

Conteneur vs Machine virtuelle

Machine virtuelle (VM) :

┌─────────────────────────────────────┐
│           Ton Application           │
├─────────────────────────────────────┤
│         Système d'exploitation      │  ← OS complet (Windows, Linux...)
├─────────────────────────────────────┤
│            Hyperviseur              │  ← VMware, VirtualBox, etc.
├─────────────────────────────────────┤
│      Système hôte (ton PC)          │
└─────────────────────────────────────┘
  • Lourd (plusieurs Go par VM)

  • Lent à démarrer (minutes)

  • Isole complètement avec un OS entier

Conteneur Docker :

┌─────────────────────────────────────┐
│           Ton Application           │
├─────────────────────────────────────┤
│     Librairies et dépendances       │  ← Seulement ce qui est nécessaire
├─────────────────────────────────────┤
│           Docker Engine             │
├─────────────────────────────────────┤
│      Système hôte (ton PC)          │
└─────────────────────────────────────┘
  • Léger (quelques Mo à quelques centaines de Mo)

  • Démarre en secondes

  • Partage le kernel de l'hôte

Analogie :

  • VM = Maison entière avec fondations, murs, toit, jardin

  • Conteneur = Appartement dans un immeuble (partage les fondations)

Les concepts clés à comprendre

Image : Un template en lecture seule contenant tout ce qu'il faut pour exécuter une application. C'est comme une recette de cuisine ou un moule.

Conteneur : Une instance en cours d'exécution d'une image. C'est le gâteau fait à partir de la recette. Tu peux avoir plusieurs conteneurs à partir de la même image.

Dockerfile : Un fichier texte contenant les instructions pour construire une image. C'est la recette écrite étape par étape.

Docker Hub : Un registre public où trouver et partager des images. C'est comme GitHub mais pour les images Docker.

Volume : Un espace de stockage persistant. Les données dans un conteneur disparaissent quand il est supprimé, sauf si tu utilises un volume.

Réseau : Permet aux conteneurs de communiquer entre eux et avec l'extérieur.

Garde ces définitions en tête, on va les utiliser tout de suite en pratique !

Partie 2 : Installation

Installer Docker

Linux (Ubuntu/Debian) :

# Mettre à jour les paquets
sudo apt update

# Installer les prérequis
sudo apt install apt-transport-https ca-certificates curl software-properties-common

# Ajouter la clé GPG officielle de Docker
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

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

# Installer Docker
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io

# Vérifier l'installation
docker --version

Linux (Alma/Rocky/RHEL) :

# Installer les prérequis
sudo dnf install -y dnf-plugins-core

# Ajouter le repository Docker
sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

# Installer Docker
sudo dnf install docker-ce docker-ce-cli containerd.io

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

# Vérifier
docker --version

macOS :

  1. Télécharge Docker Desktop depuis https://docker.com

  2. Installe le .dmg

  3. Lance Docker Desktop

  4. Vérifie dans le terminal : docker --version

Windows :

  1. Active WSL 2 (Windows Subsystem for Linux)

  2. Télécharge Docker Desktop depuis https://docker.com

  3. Installe et redémarre

  4. Vérifie : docker --version

Configuration post-installation (Linux)

Exécuter Docker sans sudo :

# Ajouter ton utilisateur au groupe docker
sudo usermod -aG docker $USER

# Appliquer les changements (déconnecte-toi et reconnecte-toi, ou)
newgrp docker

# Tester sans sudo
docker run hello-world

Vérifier que tout fonctionne

# Le test classique
docker run hello-world

Tu devrais voir :

Hello from Docker!
This message shows that your installation appears to be working correctly.
...

Félicitations ! 🎉 Docker est installé et fonctionnel !

Partie 3 : Les commandes de base

Ton premier conteneur

# Lancer un conteneur Ubuntu
docker run ubuntu echo "Bonjour depuis Docker !"

# Que s'est-il passé ?
# 1. Docker a téléchargé l'image "ubuntu" (si pas en local)
# 2. Docker a créé un conteneur à partir de cette image
# 3. Docker a exécuté la commande "echo ..."
# 4. Le conteneur s'est arrêté

Mode interactif

# Lancer Ubuntu en mode interactif
docker run -it ubuntu bash

# -i : interactif (garde STDIN ouvert)
# -t : alloue un pseudo-TTY (terminal)

# Tu es maintenant DANS le conteneur !
root@abc123:/# ls
root@abc123:/# cat /etc/os-release
root@abc123:/# exit

Lister les conteneurs

# Conteneurs en cours d'exécution
docker ps

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

# Format personnalisé
docker ps --format "table {{.ID}}\t{{.Image}}\t{{.Status}}"

Gérer les conteneurs

# Lancer un conteneur en arrière-plan (détaché)
docker run -d --name mon-nginx nginx

# -d : détaché (en arrière-plan)
# --name : donner un nom au conteneur

# Voir les logs
docker logs mon-nginx
docker logs -f mon-nginx  # -f : suivre en temps réel

# Arrêter un conteneur
docker stop mon-nginx

# Démarrer un conteneur arrêté
docker start mon-nginx

# Redémarrer
docker restart mon-nginx

# Supprimer un conteneur (doit être arrêté)
docker rm mon-nginx

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

Exécuter une commande dans un conteneur

# Lancer un conteneur
docker run -d --name mon-ubuntu ubuntu sleep infinity

# Exécuter une commande dedans
docker exec mon-ubuntu ls /

# Entrer dans le conteneur
docker exec -it mon-ubuntu bash

# Tu es dedans !
root@xyz789:/# apt update
root@xyz789:/# exit

Exposer des ports

# Lancer Nginx et exposer le port 80
docker run -d -p 8080:80 --name web nginx

# -p 8080:80 : mappe le port 8080 de ta machine au port 80 du conteneur

# Maintenant, ouvre http://localhost:8080 dans ton navigateur !

Format des ports :

-p [IP_HOTE:]PORT_HOTE:PORT_CONTENEUR

Exemples :
-p 8080:80          # localhost:8080 → conteneur:80
-p 127.0.0.1:8080:80  # Seulement accessible en local
-p 80:80            # Même port

Gérer les images

# Lister les images locales
docker images

# Télécharger une image (sans lancer de conteneur)
docker pull python:3.11

# Supprimer une image
docker rmi python:3.11

# Supprimer les images non utilisées
docker image prune

# Rechercher sur Docker Hub
docker search postgres

Nettoyer le système

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

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

# Supprimer tout ce qui n'est pas utilisé (attention !)
docker system prune

# Voir l'espace utilisé
docker system df

Partie 4 : Les images Docker

Comprendre les tags

Une image a un nom et un tag (version) :

nom:tag

Exemples :
python:3.11
python:3.11-slim
python:latest
ubuntu:22.04
nginx:alpine

Tags courants :

  • latest : La dernière version (par défaut si pas de tag)

  • alpine : Version ultra-légère basée sur Alpine Linux

  • slim : Version allégée

  • Version spécifique : 3.11, 22.04, etc.

# Ces deux commandes sont identiques
docker pull nginx
docker pull nginx:latest

# Image légère
docker pull python:3.11-alpine  # ~50 Mo vs ~1 Go pour la version complète

Conseil : En production, utilise toujours un tag précis, jamais latest !

Le Docker Hub

Docker Hub (hub.docker.com) est le registre public par défaut. Tu y trouveras :

  • Images officielles : python, nginx, postgres, redis...

  • Images vérifiées : De grandes entreprises (Microsoft, Oracle...)

  • Images communautaires : N'importe qui peut publier

# Rechercher des images
docker search flask

# Voir les détails sur hub.docker.com
# https://hub.docker.com/_/python

Créer ta propre image avec Dockerfile

Le Dockerfile est la recette pour construire ton image.

Structure de base :

# Image de base
FROM python:3.11-slim

# Métadonnées
LABEL maintainer="ton@email.com"

# Définir le répertoire de travail
WORKDIR /app

# Copier les fichiers
COPY requirements.txt .

# Exécuter des commandes
RUN pip install --no-cache-dir -r requirements.txt

# Copier le reste de l'application
COPY . .

# Exposer un port
EXPOSE 5000

# Commande par défaut
CMD ["python", "app.py"]

Exemple concret : Application Flask

Créons une structure de projet :

mon-app/
├── app.py
├── requirements.txt
└── Dockerfile

app.py :

from flask import Flask

app = Flask(__name__)

@app.route("/")
def hello():
    return "Bonjour depuis Docker ! 🐳"

@app.route("/health")
def health():
    return {"status": "ok"}

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000)

requirements.txt :

flask==3.0.0

Dockerfile :

# Image de base Python
FROM python:3.11-slim

# Répertoire de travail
WORKDIR /app

# Copier et installer les dépendances
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Copier le code
COPY app.py .

# Port exposé
EXPOSE 5000

# Commande de lancement
CMD ["python", "app.py"]

Construire l'image :

# Se placer dans le dossier du projet
cd mon-app

# Construire l'image
docker build -t mon-app-flask .

# -t : tag (nom de l'image)
# . : contexte de build (dossier courant)

# Vérifier
docker images | grep mon-app

Lancer le conteneur :

docker run -d -p 5000:5000 --name flask-app mon-app-flask

# Tester
curl http://localhost:5000
# Bonjour depuis Docker ! 🐳

Les instructions Dockerfile essentielles

FROM : Image de base

FROM python:3.11-slim
FROM node:20-alpine
FROM ubuntu:22.04

WORKDIR : Répertoire de travail

WORKDIR /app
# Toutes les commandes suivantes s'exécutent dans /app

COPY : Copier des fichiers

COPY fichier.txt /app/
COPY . /app/
COPY --chown=user:group fichier.txt /app/

ADD : Comme COPY, mais avec des super-pouvoirs

ADD archive.tar.gz /app/          # Extrait automatiquement
ADD https://example.com/file /app/ # Télécharge depuis une URL

RUN : Exécuter une commande (pendant le build)

RUN apt-get update && apt-get install -y curl
RUN pip install flask

CMD : Commande par défaut (au lancement)

CMD ["python", "app.py"]
CMD ["npm", "start"]

ENTRYPOINT : Point d'entrée (plus strict que CMD)

ENTRYPOINT ["python"]
CMD ["app.py"]
# Résultat : python app.py
# docker run mon-image script.py → python script.py

ENV : Variables d'environnement

ENV FLASK_ENV=production
ENV DATABASE_URL=postgres://localhost/db

ARG : Arguments de build

ARG VERSION=1.0
RUN echo "Version: $VERSION"

# docker build --build-arg VERSION=2.0 .

EXPOSE : Documenter les ports

EXPOSE 5000
EXPOSE 80 443

USER : Changer d'utilisateur

RUN useradd -m appuser
USER appuser

VOLUME : Déclarer un volume

VOLUME /data

Multi-stage builds (builds multi-étapes)

Pour des images plus légères, utilise les builds multi-étapes :

# Étape 1 : Build
FROM node:20 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build

# Étape 2 : Production
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

Avantages :

  • L'image finale ne contient pas les outils de build

  • Image beaucoup plus légère

  • Meilleure sécurité

Partie 5 : Les volumes (persistance des données)

Le problème

Par défaut, les données dans un conteneur sont éphémères. Quand le conteneur est supprimé, tout est perdu.

# Créer un fichier dans un conteneur
docker run -it --name test ubuntu bash
root@abc:/# echo "Hello" > /data.txt
root@abc:/# exit

# Supprimer et recréer
docker rm test
docker run -it --name test ubuntu bash
root@xyz:/# cat /data.txt
# cat: /data.txt: No such file or directory

Les volumes Docker

# Créer un volume
docker volume create mes-donnees

# Lister les volumes
docker volume ls

# Utiliser un volume
docker run -d -v mes-donnees:/app/data --name app ubuntu sleep infinity

# -v nom-volume:chemin-dans-conteneur

# Les données persistent même si le conteneur est supprimé !

Bind mounts (montage de dossiers)

Monte un dossier de ta machine dans le conteneur :

# Monter le dossier courant
docker run -v $(pwd):/app -w /app python:3.11 python script.py

# -v chemin-hôte:chemin-conteneur
# -w : définir le répertoire de travail

# Exemple pratique : développement avec rechargement automatique
docker run -d -p 5000:5000 -v $(pwd):/app mon-app-flask

Utilisation courante : Développement

# Ton code est monté dans le conteneur
# Chaque modification est immédiatement visible
docker run -d \
  -p 5000:5000 \
  -v $(pwd):/app \
  -e FLASK_DEBUG=1 \
  mon-app-flask

Volumes vs Bind mounts

Aspect Volume Bind mount
Gestion Par Docker Par toi
Emplacement /var/lib/docker/volumes N'importe où
Backup Via Docker Directement
Performance Optimisé Dépend du système
Cas d'usage Production, données Développement, config

Exemples pratiques

Base de données PostgreSQL :

# Les données survivent au redémarrage
docker run -d \
  --name postgres \
  -e POSTGRES_PASSWORD=secret \
  -v postgres-data:/var/lib/postgresql/data \
  -p 5432:5432 \
  postgres:15

Partager des données entre conteneurs :

# Créer un volume
docker volume create shared-data

# Conteneur 1 : écrit
docker run -v shared-data:/data alpine sh -c "echo 'Hello' > /data/message.txt"

# Conteneur 2 : lit
docker run -v shared-data:/data alpine cat /data/message.txt
# Hello

Partie 6 : Les réseaux Docker

Les types de réseaux

# Lister les réseaux
docker network ls

# Par défaut, tu as :
# - bridge : réseau par défaut pour les conteneurs
# - host : partage le réseau de l'hôte
# - none : pas de réseau

Communication entre conteneurs

Méthode 1 : Réseau bridge par défaut (par IP)

# Lancer deux conteneurs
docker run -d --name web nginx
docker run -d --name app python:3.11 sleep infinity

# Trouver l'IP
docker inspect web | grep IPAddress

# Depuis app, accéder à web par IP
docker exec app curl http://172.17.0.2

Méthode 2 : Réseau personnalisé (par nom) - RECOMMANDÉ

# Créer un réseau
docker network create mon-reseau

# Lancer les conteneurs sur ce réseau
docker run -d --name web --network mon-reseau nginx
docker run -d --name app --network mon-reseau python:3.11 sleep infinity

# Depuis app, accéder à web PAR SON NOM
docker exec app curl http://web
# Ça marche ! Docker fait la résolution DNS automatiquement

Exemple : Application avec base de données

# Créer le réseau
docker network create app-network

# Lancer PostgreSQL
docker run -d \
  --name db \
  --network app-network \
  -e POSTGRES_PASSWORD=secret \
  -e POSTGRES_DB=myapp \
  postgres:15

# Lancer l'application (qui se connecte à "db")
docker run -d \
  --name web \
  --network app-network \
  -p 5000:5000 \
  -e DATABASE_URL=postgresql://postgres:secret@db:5432/myapp \
  mon-app

L'application peut accéder à la base de données via db:5432 !

Partie 7 : Docker Compose (le game changer)

C'est quoi Docker Compose ?

Docker Compose permet de définir et gérer des applications multi-conteneurs avec un fichier YAML.

Avant (sans Compose) :

docker network create app-net
docker volume create db-data
docker run -d --name db --network app-net -v db-data:/var/lib/postgresql/data -e POSTGRES_PASSWORD=secret postgres:15
docker run -d --name redis --network app-net redis:alpine
docker run -d --name web --network app-net -p 5000:5000 -e DATABASE_URL=... mon-app

Après (avec Compose) :

docker compose up -d

Installation de Docker Compose

Docker Compose v2 est inclus avec Docker Desktop. Sur Linux :

# Vérifier si installé
docker compose version

# Si pas installé
sudo apt install docker-compose-plugin

Le fichier docker-compose.yml

Structure de base :

version: "3.8"

services:
  web:
    image: nginx
    ports:

      - "80:80"

  db:
    image: postgres:15
    environment:
      POSTGRES_PASSWORD: secret

Exemple complet : Application Flask + PostgreSQL + Redis

Structure du projet :

mon-projet/
├── app/
│   ├── app.py
│   └── requirements.txt
├── Dockerfile
└── docker-compose.yml

app/app.py :

from flask import Flask
import redis
import psycopg2
import os

app = Flask(__name__)

# Connexion Redis
cache = redis.Redis(host='redis', port=6379)

@app.route("/")
def hello():
    # Incrémenter le compteur de visites
    visits = cache.incr('visits')
    return f"Bonjour ! Cette page a été vue {visits} fois."

@app.route("/health")
def health():
    return {"status": "ok", "services": {"redis": "up", "db": "up"}}

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000, debug=True)

app/requirements.txt :

flask==3.0.0
redis==5.0.0
psycopg2-binary==2.9.9

Dockerfile :

FROM python:3.11-slim

WORKDIR /app

COPY app/requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY app/ .

EXPOSE 5000

CMD ["python", "app.py"]

docker-compose.yml :

version: "3.8"

services:
  web:
    build: .
    ports:

      - "5000:5000"
    environment:

      - FLASK_DEBUG=1

      - DATABASE_URL=postgresql://postgres:secret@db:5432/myapp
    volumes:

      - ./app:/app
    depends_on:

      - db

      - redis
    restart: unless-stopped

  db:
    image: postgres:15-alpine
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: secret
      POSTGRES_DB: myapp
    volumes:

      - postgres-data:/var/lib/postgresql/data
    restart: unless-stopped

  redis:
    image: redis:alpine
    restart: unless-stopped

volumes:
  postgres-data:

Les commandes Docker Compose

# Lancer tous les services
docker compose up

# En arrière-plan
docker compose up -d

# Voir les logs
docker compose logs
docker compose logs -f web  # Suivre les logs du service "web"

# Voir le statut
docker compose ps

# Arrêter
docker compose stop

# Arrêter et supprimer
docker compose down

# Supprimer aussi les volumes (ATTENTION : perte de données)
docker compose down -v

# Reconstruire les images
docker compose build
docker compose up --build

# Exécuter une commande dans un service
docker compose exec web bash
docker compose exec db psql -U postgres

# Scaler un service (plusieurs instances)
docker compose up -d --scale web=3

Les options du docker-compose.yml

build : Construire depuis un Dockerfile

services:
  web:
    build: .  # Dockerfile dans le dossier courant

    # Ou avec options
    build:
      context: ./app
      dockerfile: Dockerfile.prod
      args:
        VERSION: 1.0

image : Utiliser une image existante

services:
  db:
    image: postgres:15-alpine

ports : Exposer des ports

services:
  web:
    ports:

      - "5000:5000"        # host:container

      - "127.0.0.1:80:80"  # Seulement en local

volumes : Monter des volumes

services:
  web:
    volumes:

      - ./code:/app              # Bind mount

      - data-volume:/app/data    # Volume nommé

volumes:
  data-volume:

environment : Variables d'environnement

services:
  web:
    environment:

      - DEBUG=1

      - DATABASE_URL=postgresql://...

    # Ou depuis un fichier
    env_file:

      - .env

depends_on : Ordre de démarrage

services:
  web:
    depends_on:

      - db

      - redis

  db:
    image: postgres:15

  redis:
    image: redis:alpine

restart : Politique de redémarrage

services:
  web:
    restart: unless-stopped  # Redémarre sauf si arrêté manuellement
    # Autres options : no, always, on-failure

healthcheck : Vérifier la santé

services:
  web:
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:5000/health"]
      interval: 30s
      timeout: 10s
      retries: 3

networks : Réseaux personnalisés

services:
  web:
    networks:

      - frontend

      - backend

  db:
    networks:

      - backend

networks:
  frontend:
  backend:

Fichier .env avec Docker Compose

docker-compose.yml :

services:
  db:
    image: postgres:15
    environment:
      POSTGRES_PASSWORD: ${DB_PASSWORD}

.env :

DB_PASSWORD=super_secret_password
# Docker Compose charge automatiquement .env
docker compose up -d

Partie 8 : Bonnes pratiques

1. Images légères

# MAUVAIS : Image complète (1+ Go)
FROM python:3.11

# BON : Image slim (~150 Mo)
FROM python:3.11-slim

# ENCORE MIEUX : Alpine (~50 Mo)
FROM python:3.11-alpine

2. Ordonne tes instructions (cache)

Docker met en cache chaque instruction. Mets les instructions qui changent rarement en premier.

# MAUVAIS : Réinstalle les dépendances à chaque changement de code
FROM python:3.11-slim
COPY . /app
RUN pip install -r /app/requirements.txt

# BON : Les dépendances sont en cache
FROM python:3.11-slim
COPY requirements.txt /app/
RUN pip install -r /app/requirements.txt
COPY . /app

3. Un processus par conteneur

# MAUVAIS : Tout dans un conteneur
services:
  monolithe:
    # web + db + cache + queue...

# BON : Un service par conteneur
services:
  web:
    image: mon-app
  db:
    image: postgres
  redis:
    image: redis
  worker:
    image: mon-worker

4. Ne pas tourner en root

# Créer un utilisateur non-root
FROM python:3.11-slim

RUN useradd -m -r appuser && \
    mkdir /app && \
    chown appuser:appuser /app

WORKDIR /app
USER appuser

COPY --chown=appuser:appuser . .

5. Utilise .dockerignore

Comme .gitignore, mais pour Docker :

.dockerignore :

.git
.gitignore
__pycache__
*.pyc
.env
.env.local
venv/
node_modules/
.pytest_cache/
*.md
docker-compose*.yml
Dockerfile*

6. Tags explicites

# MAUVAIS : Quelle version ?
FROM python:latest

# BON : Version précise
FROM python:3.11.6-slim-bookworm

7. Variables d'environnement pour la configuration

# Permettre la configuration sans reconstruire
ENV FLASK_ENV=production
ENV PORT=5000

CMD ["python", "app.py"]
# Overrider au lancement
docker run -e FLASK_ENV=development -e PORT=8080 mon-app

8. Healthchecks

HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
  CMD curl -f http://localhost:5000/health || exit 1

9. Multi-stage pour la production

# Build
FROM node:20 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# Production
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
USER node
CMD ["node", "dist/index.js"]

10. Logs sur stdout/stderr

# Les logs doivent aller sur stdout, pas dans des fichiers
import logging
import sys

logging.basicConfig(
    stream=sys.stdout,
    level=logging.INFO
)

Docker capture automatiquement stdout/stderr avec docker logs.

Partie 9 : Debugging et dépannage

Voir ce qui se passe

# Logs d'un conteneur
docker logs mon-conteneur
docker logs -f mon-conteneur  # Suivre en temps réel
docker logs --tail 100 mon-conteneur  # 100 dernières lignes

# Statistiques en temps réel
docker stats

# Inspecter un conteneur
docker inspect mon-conteneur

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

Entrer dans un conteneur

# Conteneur en cours d'exécution
docker exec -it mon-conteneur bash
docker exec -it mon-conteneur sh  # Si pas de bash

# Démarrer un conteneur arrêté en mode debug
docker run -it --entrypoint bash mon-image

Problèmes courants

"port is already allocated"

# Trouver ce qui utilise le port
sudo lsof -i :5000
# ou
docker ps  # Un autre conteneur ?

# Solution : utiliser un autre port
docker run -p 5001:5000 mon-app

"no space left on device"

# Voir l'espace utilisé
docker system df

# Nettoyer
docker system prune -a

# Supprimer les volumes orphelins
docker volume prune

"container exited immediately"

# Voir les logs
docker logs mon-conteneur

# Le conteneur a besoin d'un processus qui tourne
# MAUVAIS :
CMD ["echo", "hello"]  # Se termine immédiatement

# BON :
CMD ["python", "app.py"]  # Processus qui reste actif

"cannot connect to database"

# Vérifier que les conteneurs sont sur le même réseau
docker network inspect mon-reseau

# Vérifier que le service est prêt
docker compose logs db

# Utiliser depends_on avec condition
services:
  web:
    depends_on:
      db:
        condition: service_healthy

Debug avec Docker Compose

# Voir tous les logs
docker compose logs

# Logs d'un service spécifique
docker compose logs -f web

# Reconstruire et relancer
docker compose up --build

# Voir la configuration finale (variables résolues)
docker compose config

Partie 10 : Déploiement en production

Construire pour la production

# Dockerfile.prod
FROM python:3.11-slim

# Métadonnées
LABEL maintainer="toi@email.com"
LABEL version="1.0"

# Variables d'environnement de production
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1

# Utilisateur non-root
RUN useradd -m -r appuser

WORKDIR /app

# Dépendances
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Code
COPY --chown=appuser:appuser . .

USER appuser

EXPOSE 5000

# Healthcheck
HEALTHCHECK --interval=30s --timeout=10s --retries=3 \
  CMD curl -f http://localhost:5000/health || exit 1

# Gunicorn au lieu du serveur de développement Flask
CMD ["gunicorn", "--bind", "0.0.0.0:5000", "--workers", "4", "app:app"]

Docker Compose pour la production

docker-compose.prod.yml :

version: "3.8"

services:
  web:
    build:
      context: .
      dockerfile: Dockerfile.prod
    ports:

      - "5000:5000"
    environment:

      - FLASK_ENV=production

      - DATABASE_URL=${DATABASE_URL}
    restart: always
    deploy:
      replicas: 2
      resources:
        limits:
          cpus: "0.5"
          memory: 512M

  db:
    image: postgres:15-alpine
    environment:
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    volumes:

      - postgres-data:/var/lib/postgresql/data
    restart: always

  nginx:
    image: nginx:alpine
    ports:

      - "80:80"

      - "443:443"
    volumes:

      - ./nginx.conf:/etc/nginx/nginx.conf:ro
    depends_on:

      - web
    restart: always

volumes:
  postgres-data:

Pousse vers un registre

# Se connecter à Docker Hub
docker login

# Taguer l'image
docker tag mon-app:latest ton-username/mon-app:1.0

# Pousser
docker push ton-username/mon-app:1.0

# Sur le serveur de production
docker pull ton-username/mon-app:1.0
docker run -d -p 5000:5000 ton-username/mon-app:1.0

Registres privés

# GitHub Container Registry
docker login ghcr.io
docker tag mon-app ghcr.io/ton-username/mon-app:1.0
docker push ghcr.io/ton-username/mon-app:1.0

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

Cheat Sheet : Commandes essentielles

Conteneurs

docker run IMAGE                    # Lancer un conteneur
docker run -d IMAGE                 # En arrière-plan
docker run -it IMAGE bash           # Mode interactif
docker run -p 8080:80 IMAGE         # Exposer un port
docker run -v /host:/container IMAGE # Monter un volume
docker run --name NOM IMAGE         # Nommer le conteneur
docker run -e VAR=valeur IMAGE      # Variable d'environnement
docker run --rm IMAGE               # Supprimer après arrêt

docker ps                           # Conteneurs actifs
docker ps -a                        # Tous les conteneurs
docker stop CONTENEUR               # Arrêter
docker start CONTENEUR              # Démarrer
docker restart CONTENEUR            # Redémarrer
docker rm CONTENEUR                 # Supprimer
docker rm -f CONTENEUR              # Forcer la suppression

docker logs CONTENEUR               # Voir les logs
docker logs -f CONTENEUR            # Suivre les logs
docker exec -it CONTENEUR bash      # Entrer dans le conteneur
docker inspect CONTENEUR            # Détails complets

Images

docker images                       # Lister les images
docker pull IMAGE:TAG               # Télécharger
docker build -t NOM .               # Construire depuis Dockerfile
docker tag IMAGE NOM:TAG            # Taguer
docker push NOM:TAG                 # Pousser vers registre
docker rmi IMAGE                    # Supprimer
docker image prune                  # Nettoyer les images inutilisées

Volumes

docker volume ls                    # Lister
docker volume create NOM            # Créer
docker volume rm NOM                # Supprimer
docker volume prune                 # Nettoyer

Réseaux

docker network ls                   # Lister
docker network create NOM           # Créer
docker network connect NET CONT     # Connecter un conteneur
docker network inspect NOM          # Détails

Docker Compose

docker compose up                   # Lancer
docker compose up -d                # En arrière-plan
docker compose up --build           # Reconstruire et lancer
docker compose down                 # Arrêter et supprimer
docker compose down -v              # + supprimer les volumes
docker compose ps                   # Statut
docker compose logs                 # Logs
docker compose logs -f SERVICE      # Suivre les logs d'un service
docker compose exec SERVICE bash    # Entrer dans un service
docker compose build                # Construire les images
docker compose pull                 # Mettre à jour les images

Nettoyage

docker system df                    # Espace utilisé
docker system prune                 # Nettoyer tout
docker system prune -a              # Tout, y compris images non utilisées
docker container prune              # Conteneurs arrêtés
docker image prune                  # Images orphelines
docker volume prune                 # Volumes orphelins

Conclusion

Félicitations ! Tu connais maintenant Docker et ses fondamentaux.

Ce qu'on a couvert :

  • Les concepts de base (images, conteneurs, volumes, réseaux)

  • Les commandes essentielles

  • Créer tes propres images avec Dockerfile

  • Docker Compose pour les applications multi-conteneurs

  • Les bonnes pratiques de production

  • Le debugging et dépannage

Les commandements du Docker-fu :

  1. Un processus par conteneur

  2. Images légères (alpine, slim)

  3. Ne pas tourner en root

  4. Tags explicites, jamais latest en prod

  5. Utilise .dockerignore

  6. Ordonne tes instructions pour le cache

  7. Variables d'environnement pour la config

  8. Volumes pour les données persistantes

  9. Réseaux personnalisés pour la communication

  10. Docker Compose pour tout projet sérieux

Rappelle-toi :

  • Docker simplifie énormément le déploiement

  • "Ça marche sur ma machine" n'est plus une excuse

  • Commence simple, complexifie progressivement

  • La documentation officielle est excellente

Prochaines étapes :

  1. Dockerise un de tes projets existants

  2. Crée un docker-compose.yml pour ta stack

  3. Explore Docker Swarm ou Kubernetes pour l'orchestration

  4. Mets en place un pipeline CI/CD avec Docker

  5. Pratique, pratique, pratique !

Docker, c'est comme le vélo : au début on tombe, puis on ne peut plus s'en passer. Dans quelques semaines, tu ne pourras plus imaginer développer sans conteneurs.

Tu as des questions sur Docker ? Un conteneur qui refuse de démarrer ? Partage en commentaire ! Et si ce guide t'a aidé, partage-le avec d'autres devs qui veulent enfin comprendre les conteneurs.

Commentaires (1)

Laisser un commentaire