Module Technique 1 — Introduction à Docker

Conteneuriser tes applications pour les rendre portables et reproductibles

docker
mlops
technique
Auteur·rice

François Boussengui

Date de publication

6 janvier 2026

0.0.1 🎯 Objectifs d’apprentissage

À l’issue de ce module, tu seras capable de :

  1. Expliquer pourquoi Docker est essentiel en Data Science et MLOps
  2. Distinguer les concepts d’image, conteneur, volume et réseau
  3. Installer Docker sur ta machine (Windows, Mac ou Linux)
  4. Écrire un Dockerfile basique pour une application Python
  5. Utiliser les commandes essentielles pour gérer tes conteneurs

📚 Prérequis : Notions de base en ligne de commande (terminal/bash)

⏱️ Temps estimé : 3 heures (installation incluse)


1 Pourquoi Docker ?

1.1 Le problème du “ça marche sur ma machine”

Tu as sûrement déjà vécu cette situation : tu développes un script Python, tout fonctionne parfaitement sur ton ordinateur, et quand tu le partages avec un collègue ou que tu le déploies en production… rien ne marche.

Les causes possibles sont nombreuses :

  • Versions de Python différentes (3.8 vs 3.11)
  • Packages manquants ou versions incompatibles
  • Variables d’environnement absentes
  • Dépendances système (librairies C, drivers…)
  • Différences d’OS (Windows vs Linux)

🎯 Exemple concret

Tu as développé un modèle de prédiction de sinistralité avec scikit-learn 1.3, pandas 2.0 et numpy 1.24. Ton collègue a des versions différentes → le modèle crashe ou, pire, donne des résultats différents silencieusement.

1.2 La solution Docker : tout empaqueter

Docker résout ce problème en empaquetant ton application avec tout son environnement :

flowchart LR
    subgraph SANS["❌ Sans Docker"]
        A1[Ton code] --> B1[Machine 1<br>Python 3.8]
        A1 --> C1[Machine 2<br>Python 3.11]
        A1 --> D1[Serveur<br>Python ???]
    end
    
    subgraph AVEC["✅ Avec Docker"]
        A2[Ton code<br>+ Dockerfile] --> B2[Conteneur<br>Python 3.10]
        B2 --> C2[Machine 1]
        B2 --> D2[Machine 2]
        B2 --> E2[Serveur]
    end

Sans Docker vs Avec Docker

💡 Point clé

Un conteneur Docker embarque ton code ET son environnement complet. Il fonctionnera de façon identique sur n’importe quelle machine où Docker est installé.

1.3 Docker vs Machines Virtuelles

Tu connais peut-être les machines virtuelles (VM). Docker est différent et plus léger :

1.3.0.1 🖥️ Machine Virtuelle

  • Virtualise tout le système (OS complet)
  • Démarre en minutes
  • Consomme beaucoup de ressources (RAM, disque)
  • Isolation totale
  • Taille : plusieurs Go

1.3.0.2 🐳 Conteneur Docker

  • Virtualise seulement l’application
  • Démarre en secondes
  • Consomme peu de ressources
  • Partage le noyau de l’OS hôte
  • Taille : quelques Mo à centaines de Mo

flowchart TB
    subgraph VM["Machine Virtuelle"]
        direction TB
        V1[App 1] --> VOS1[OS Guest 1]
        V2[App 2] --> VOS2[OS Guest 2]
        VOS1 --> HYP[Hyperviseur]
        VOS2 --> HYP
        HYP --> VH[Hardware]
    end
    
    subgraph DOCKER["Conteneurs Docker"]
        direction TB
        D1[App 1] --> DE[Docker Engine]
        D2[App 2] --> DE
        D3[App 3] --> DE
        DE --> DOS[OS Hôte]
        DOS --> DH[Hardware]
    end

Architecture VM vs Docker


2 Les concepts fondamentaux

2.1 Image vs Conteneur

C’est LA distinction cruciale à comprendre :

Concept Analogie Description
Image Recette de cuisine Template en lecture seule qui définit l’environnement
Conteneur Plat cuisiné Instance en cours d’exécution d’une image

🍳 Analogie culinaire

  • L’image c’est la recette du gâteau : les ingrédients, les étapes, les quantités
  • Le conteneur c’est le gâteau que tu as préparé à partir de la recette
  • Tu peux faire plusieurs gâteaux (conteneurs) à partir de la même recette (image)

flowchart LR
    I[🖼️ Image<br>python:3.10] --> C1[📦 Conteneur 1<br>mon-app-dev]
    I --> C2[📦 Conteneur 2<br>mon-app-test]
    I --> C3[📦 Conteneur 3<br>mon-app-prod]

Relation Image → Conteneur

2.2 Dockerfile : la recette

Le Dockerfile est un fichier texte qui contient les instructions pour construire une image.

Voici un exemple simple pour une application Python :

# Image de base : Python 3.10 sur Linux léger (Alpine)
FROM python:3.10-slim

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

# Copier le fichier des dépendances
COPY requirements.txt .

# Installer les dépendances
RUN pip install --no-cache-dir -r requirements.txt

# Copier le code de l'application
COPY . .

# Commande par défaut au démarrage du conteneur
CMD ["python", "main.py"]

Chaque instruction crée une couche (layer) dans l’image :

flowchart TB
    L1[Layer 1: Image de base Python 3.10] --> L2
    L2[Layer 2: WORKDIR /app] --> L3
    L3[Layer 3: COPY requirements.txt] --> L4
    L4[Layer 4: RUN pip install] --> L5
    L5[Layer 5: COPY . .] --> L6
    L6[Layer 6: CMD python main.py]
    
    style L1 fill:#06436e,color:#fff
    style L4 fill:#f8d65c,color:#333
    style L6 fill:#72f1b8,color:#333

Les couches d’une image Docker

💡 Point clé

Docker met en cache les couches. Si tu modifies seulement ton code (pas les dépendances), seules les dernières couches seront reconstruites. C’est pourquoi on copie requirements.txt avant le code !

2.3 Volumes : persister les données

Par défaut, les données dans un conteneur sont éphémères : elles disparaissent quand le conteneur s’arrête.

Les volumes permettent de persister les données et de les partager entre le conteneur et ta machine :

flowchart LR
    subgraph HOST["🖥️ Machine hôte"]
        H1[/home/user/data]
    end
    
    subgraph CONTAINER["📦 Conteneur"]
        C1[/app/data]
    end
    
    H1 <-->|Volume monté| C1

Volume Docker


3 Installation de Docker

3.1 Sur Windows

  1. Prérequis : Windows 10/11 64-bit avec WSL2 activé

  2. Télécharger Docker Desktop : https://www.docker.com/products/docker-desktop

  3. Installer en suivant l’assistant

  4. Vérifier l’installation :

\(</span> docker --version<br> <span class="output">Docker version 24.0.7, build afdd53b</span><br><br> <span class="prompt">\) docker run hello-world
Hello from Docker!
This message shows that your installation appears to be working correctly.

3.2 Sur macOS

  1. Télécharger Docker Desktop pour Mac : https://www.docker.com/products/docker-desktop

    • Choisir Apple Silicon (M1/M2/M3) ou Intel selon ton Mac
  2. Installer en glissant dans Applications

  3. Lancer Docker Desktop

  4. Vérifier dans le terminal

3.3 Sur Linux (Ubuntu/Debian)

# Mettre à jour les packages
\(</span> sudo apt update<br><br> <span class="comment"># Installer les prérequis</span><br> <span class="prompt">\) sudo apt install ca-certificates curl gnupg

# Ajouter la clé GPG officielle de Docker
\(</span> sudo install -m 0755 -d /etc/apt/keyrings<br> <span class="prompt">\) curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg –dearmor -o /etc/apt/keyrings/docker.gpg

# Ajouter le repository
\(</span> 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<br><br> <span class="comment"># Installer Docker</span><br> <span class="prompt">\) sudo apt update
\(</span> sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin<br><br> <span class="comment"># Permettre d'utiliser Docker sans sudo</span><br> <span class="prompt">\) sudo usermod -aG docker $USER
# Puis déconnecte-toi et reconnecte-toi

⚠️ Important

Après l’installation sur Linux, n’oublie pas de te déconnecter/reconnecter (ou redémarrer) pour que les permissions Docker soient prises en compte.


4 Les commandes essentielles

4.1 Cheat sheet

Voici les commandes que tu utiliseras au quotidien :

4.1.1 Gestion des images

Commande Description
docker build -t nom:tag . Construire une image depuis un Dockerfile
docker images Lister les images locales
docker pull nom:tag Télécharger une image depuis Docker Hub
docker rmi nom:tag Supprimer une image

4.1.2 Gestion des conteneurs

Commande Description
docker run nom:tag Créer et démarrer un conteneur
docker run -it nom:tag bash Démarrer en mode interactif
docker run -d nom:tag Démarrer en arrière-plan (detached)
docker ps Lister les conteneurs en cours
docker ps -a Lister tous les conteneurs (y compris arrêtés)
docker stop id Arrêter un conteneur
docker rm id Supprimer un conteneur
docker logs id Voir les logs d’un conteneur
docker exec -it id bash Entrer dans un conteneur en cours

4.1.3 Options utiles de docker run

Option Description
-p 8080:80 Mapper le port 80 du conteneur au port 8080 de l’hôte
-v /host/path:/container/path Monter un volume
-e VAR=value Définir une variable d’environnement
--name mon-conteneur Donner un nom au conteneur
--rm Supprimer le conteneur automatiquement à l’arrêt

4.2 Exemples pratiques

4.2.1 Lancer un conteneur Python interactif

$ docker run -it python:3.10 python
Python 3.10.13 (main, Nov 15 2023, 03:40:21)
>>> print(“Hello depuis Docker!”)
Hello depuis Docker!
>>> exit()

4.2.2 Construire et lancer ta propre image

# Se placer dans le dossier contenant le Dockerfile
\(</span> cd mon-projet<br><br> <span class="comment"># Construire l'image (le point = contexte courant)</span><br> <span class="prompt">\) docker build -t mon-app:v1 .

# Lancer un conteneur
\(</span> docker run --rm mon-app:v1<br><br> <span class="comment"># Lancer avec un volume pour le développement</span><br> <span class="prompt">\) docker run –rm -v $(pwd):/app mon-app:v1


5 Ton premier Dockerfile Data Science

5.1 Structure du projet

Créons un projet simple qui calcule des indicateurs de sinistralité :

mon-projet/
├── Dockerfile
├── requirements.txt
├── main.py
└── data/
    └── sinistres.csv

5.2 Le fichier requirements.txt

pandas==2.0.3
numpy==1.24.3
matplotlib==3.7.2

5.3 Le script main.py

"""
Calcul d'indicateurs de sinistralité
Premier script dockerisé !
"""
import pandas as pd
import numpy as np

def calculer_indicateurs(df: pd.DataFrame) -> dict:
    """Calcule les indicateurs clés de sinistralité."""
    
    # Fréquence = nombre de sinistres / exposition
    frequence = len(df) / df['exposition'].sum()
    
    # Sévérité moyenne = coût total / nombre de sinistres
    severite = df['cout'].mean()
    
    # Prime pure = fréquence × sévérité
    prime_pure = frequence * severite
    
    return {
        'frequence': frequence,
        'severite': severite,
        'prime_pure': prime_pure,
        'nb_sinistres': len(df),
        'cout_total': df['cout'].sum()
    }

def main():
    print("=" * 50)
    print("🐳 Script de sinistralité dockerisé")
    print("=" * 50)
    
    # Créer des données d'exemple
    np.random.seed(42)
    n_sinistres = 1000
    
    df = pd.DataFrame({
        'id_sinistre': range(n_sinistres),
        'cout': np.random.lognormal(mean=7, sigma=1, size=n_sinistres),
        'exposition': np.random.uniform(0.5, 1.0, size=n_sinistres)
    })
    
    # Calculer les indicateurs
    indicateurs = calculer_indicateurs(df)
    
    print("\n📊 Indicateurs calculés :")
    print(f"   Nombre de sinistres : {indicateurs['nb_sinistres']:,}")
    print(f"   Coût total         : {indicateurs['cout_total']:,.0f} €")
    print(f"   Fréquence          : {indicateurs['frequence']:.4f}")
    print(f"   Sévérité moyenne   : {indicateurs['severite']:,.0f} €")
    print(f"   Prime pure         : {indicateurs['prime_pure']:,.0f} €")
    print("\n✅ Calcul terminé avec succès !")

if __name__ == "__main__":
    main()

5.4 Le Dockerfile

# Image de base Python 3.10
FROM python:3.10-slim

# Métadonnées
LABEL maintainer="François Boussengui"
LABEL description="Calcul d'indicateurs de sinistralité"

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

# Copier et installer les dépendances (pour profiter du cache Docker)
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Copier le code source
COPY main.py .

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

5.5 Build et Run

# Construire l’image
\(</span> docker build -t sinistralite:v1 .<br> <span class="output">[+] Building 15.3s (9/9) FINISHED</span><br> <span class="output"> => [1/4] FROM python:3.10-slim</span><br> <span class="output"> => [2/4] WORKDIR /app</span><br> <span class="output"> => [3/4] COPY requirements.txt .</span><br> <span class="output"> => [4/4] RUN pip install ...</span><br> <span class="output"> => [5/5] COPY main.py .</span><br><br> <span class="comment"># Lancer le conteneur</span><br> <span class="prompt">\) docker run –rm sinistralite:v1
==================================================
🐳 Script de sinistralité dockerisé
==================================================

📊 Indicateurs calculés :
Nombre de sinistres : 1,000
Coût total : 1,847,293 €
Fréquence : 1.3245
Sévérité moyenne : 1,847 €
Prime pure : 2,447 €

✅ Calcul terminé avec succès !


6 Bonnes pratiques

6.1 Optimiser la taille de l’image

6.1.0.1 ❌ À éviter

FROM python:3.10
RUN apt-get update
RUN apt-get install -y gcc
RUN pip install pandas
RUN pip install numpy
COPY . .
  • Image de base lourde
  • Plusieurs RUN = plusieurs couches
  • Pas de nettoyage du cache

6.1.0.2 ✅ Recommandé

FROM python:3.10-slim
RUN apt-get update && \
    apt-get install -y --no-install-recommends gcc && \
    rm -rf /var/lib/apt/lists/*
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
  • Image slim (plus légère)
  • Commandes groupées
  • Cache nettoyé

6.2 Utiliser un .dockerignore

Comme .gitignore, le fichier .dockerignore exclut des fichiers du contexte de build :

# .dockerignore
__pycache__/
*.pyc
*.pyo
.git/
.gitignore
.env
*.md
.vscode/
.idea/
data/raw/

💡 Point clé

Un bon .dockerignore accélère le build et réduit la taille de l’image en évitant de copier des fichiers inutiles.

6.3 Ne pas lancer en root

Par défaut, les conteneurs s’exécutent en tant que root. En production, c’est un risque de sécurité :

FROM python:3.10-slim

# Créer un utilisateur non-root
RUN useradd --create-home appuser
WORKDIR /home/appuser/app

# Copier les fichiers
COPY --chown=appuser:appuser . .

# Passer à l'utilisateur non-root
USER appuser

# Installer les dépendances pour cet utilisateur
RUN pip install --user --no-cache-dir -r requirements.txt

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

Synthèse

6.3.1 🎯 Les 5 points essentiels à retenir

  1. Docker résout le “ça marche sur ma machine” — En empaquetant ton code avec son environnement complet

  2. Image ≠ Conteneur — L’image est la recette, le conteneur est le plat cuisiné

  3. Le Dockerfile définit l’image — C’est la recette étape par étape pour construire ton environnement

  4. Les volumes persistent les données — Sans volume, les données sont perdues à l’arrêt du conteneur

  5. L’ordre des instructions compte — Mets les éléments qui changent peu (dépendances) avant ceux qui changent souvent (code) pour profiter du cache


Auto-évaluation

Réponse : Une image est un template en lecture seule qui contient l’environnement (OS, dépendances, code). Un conteneur est une instance en cours d’exécution de cette image. On peut créer plusieurs conteneurs à partir de la même image.

Réponse : Pour profiter du cache Docker. Les dépendances changent rarement, alors que le code change souvent. En copiant requirements.txt d’abord et en installant les dépendances, cette couche sera mise en cache. Les builds suivants seront beaucoup plus rapides car seules les couches après le changement seront reconstruites.

Réponse : En utilisant un volume. On monte un dossier de la machine hôte dans le conteneur avec l’option -v : docker run -v /chemin/hote:/chemin/conteneur mon-image. Les données écrites dans /chemin/conteneur seront en fait stockées dans /chemin/hote et persisteront.

Réponse : docker exec -it <container_id> bash (ou sh si bash n’est pas disponible). L’option -i garde STDIN ouvert et -t alloue un pseudo-TTY pour avoir un terminal interactif.


Ressources complémentaires


🐳 Prochaine étape technique

Semaine 2 : Nous approfondirons Docker avec Docker Compose pour orchestrer plusieurs conteneurs, et nous dockeriserons ton application Streamlit de prédiction de prix de montres.


← Retour à la Semaine 1 Voir la Fiche de travail →