5.3 · Docker pour Python

Niveau 5 · Niveau pro & industrialisation

5.3Docker pour Python

Objectif : Conteneuriser une application Python (web/data) avec Docker.
Temps estimé : 15 min · lecture autonome · Si vous n'avez que 5 min : lisez « L'essentiel en 30s » + le schéma.

L'essentiel en 30 secondes

  • Fini le « ça marche sur ma machine » : le conteneur embarque l'app avec son environnement et tourne identiquement partout.
  • Dépendances avant code : base slim, requirements copiés et installés d'abord — le cache survit aux modifications.
  • Dev vs prod : bind mount + reload en dev, code copié + workers en prod — même image de base.

Mini-cas filé — Nabil conteneurise à Alger

Le pipeline async de Nabil tourne parfaitement à Alger — mais plante chez sa collègue (version de Python différente, dépendances manquantes, port injoignable). Il écrit un Dockerfile : base slim, requirements installés avant le code, utilisateur non-root, lancement sur toutes les interfaces. Puis un Compose avec la base de données. Suite des cas 5.1-5.2 — Nabil rend son analyse portable.

Suite des cas 5.1-5.2 — Nabil passe de « chez moi ça marche » à « partout pareil ».

1. Le Dockerfile Python qui marche

Docker empaquette l'app Python avec son environnement complet (version de Python, dépendances, système) dans un conteneur qui s'exécute à l'identique partout. La recette (Dockerfile) : base python:3.12-slim, COPY requirements.txt puis pip install avant le code (le cache de build survit aux modifications), USER non-root, CMD qui lance. Le .dockerignore exclut .venv, __pycache__ et .git : le contexte maigrit, le build accélère. Nabil ne débat plus des versions : l'environnement voyage avec le code.

Réflexe : tout ce qui vit sur votre poste et manque dans l'image est un futur plantage ailleurs — l'image doit tout contenir, dépendances comprises.

2. Dev vs prod : deux visages

Même image de base, deux lancements. En dev : bind mount du code + --reload (FastAPI/Flask) — on modifie, ça recharge sans reconstruire. En prod : code copié dans l'image, serveur gunicorn/uvicorn en multi-workers, config par variables -e, écoute sur 0.0.0.0 (jamais localhost, injoignable en conteneur). Nabil développe en bind et livre en copié : deux visages, une seule recette.

À éviter : confondre les deux — du reload en prod, ou du code copié figé en dev qui force un rebuild à chaque virgule.

3. Compose pour l'appli complète

Une appli réelle, c'est plusieurs conteneurs : api (build du Dockerfile) + bdd (base + volume persistant) sur un même réseau, DATABASE_URL en variable, depends_on + retry au démarrage. Compose décrit tout ça et monte le stack local identique à la CI d'une commande. Nabil ajoute la base au Compose : sa collègue démarre en minutes, avec les mêmes versions.

Le niveau 3 du guide Docker détaille chaque ligne : ici, on retient le geste — une commande, tout le stack, partout pareil.

Erreur d'interprétation fréquente : « Docker remplace le venv, et localhost comme host suffit ». Double erreur. Le venv isole les dépendances Python sur votre machine ; Docker isole l'application entière (Python, système, dépendances) dans un portable — on utilise souvent les deux (venv en dev, Docker pour livrer). Et en conteneur, localhost n'est joignable que depuis le conteneur lui-même : le serveur doit écouter sur 0.0.0.0.
Python conteneurisé Même image, du PC au serveur slim + cache Dépendancesavant le codeUSER + .dockerignore Non-root,contexte maigreCompose (api+bdd) Stackcomplet d'une commande
Même image, du PC au serveur
Version texte du schéma (SEO / lecteurs d'écran / traduction) : 1) Dockerfile : Nabil part d'une base slim à Alger, copie requirements puis installe avant le code (cache), exclut .venv via .dockerignore, crée un USER non-root. 2) Build/run : l'image fige l'app et son environnement, le conteneur écoute sur 0.0.0.0. 3) Compose : api + bdd lancées ensemble, DATABASE_URL en variable. Leçon : l'environnement voyage avec le code.

🔎 Exemple concret — L'API de Nabil en conteneur

Recette générique : slim, cache, non-root, écoute ouverte.

FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
RUN useradd -m app && chown -R app:app /app
USER app
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

Lecture : le requirements caché avant le code changeant — le cache survit aux virgules.

Leçon : --host 0.0.0.0 obligatoire en conteneur, jamais localhost.

Vocabulaire de la section

Docker
Outil qui empaquette l'app et son environnement dans un conteneur portable.

Exemple simple : L'analyse de Nabil tourne pareil à Alger et chez sa collègue.

Ce que ce n'est pas : un venv recréé à la main sur chaque poste.

Réflexe : mon app dépend-elle encore de mon poste ?

Image
Modèle figé de l'app + dépendances, construit depuis le Dockerfile.

Exemple simple : Nabil construit une image versionnée de chaque livraison.

Ce que ce n'est pas : le conteneur en cours d'exécution.

Réflexe : puis-je reconstruire cette image à l'identique ?

Dockerfile
Recette de construction : base slim, dépendances, code, lancement.

Exemple simple : La recette lisible de Nabil, requirements avant code.

Ce que ce n'est pas : une install manuelle de Python sur un serveur.

Réflexe : les dépendances sont-elles installées avant le code ?

.dockerignore
Exclut l'inutile du contexte (.venv, caches, .git) pour maigrir le build.

Exemple simple : Nabil exclut .venv et __pycache__ : build plus rapide.

Ce que ce n'est pas : copier .venv dans l'image.

Réflexe : qu'est-ce qui alourdit mon contexte ?

Compose
Décrit plusieurs conteneurs (api + bdd) lancés ensemble.

Exemple simple : Nabil monte api et base d'une seule commande.

Ce que ce n'est pas : un seul conteneur isolé sans base.

Réflexe : un nouvel arrivant démarre-t-il en une commande ?

En pratique — Conteneuriser une application Python

  1. Installez Docker Desktop. Préparez une petite app Python (ex. un script ou une API FastAPI) avec son requirements.txt.
  2. Écrivez un Dockerfile : image de base « FROM python:3.12-slim », copie du code, « RUN pip install -r requirements.txt », commande de lancement (CMD).
  3. Construisez l'image : « docker build -t mon-app . », puis lancez un conteneur : « docker run mon-app » (avec -p pour exposer un port si c'est une API).
  4. Modifiez le code, reconstruisez, relancez : mesurez la reproductibilité — le conteneur tourne à l'identique partout.
Vous conteneurisez une application Python avec un Dockerfile et la lancez dans un conteneur : la clé d'un déploiement fiable et portable.

Script prêt à dire — proposer Docker à l'équipe

« Notre analyse marche sur mon poste à Alger mais pas ailleurs : c'est un problème d'environnement, pas de code — version de Python, dépendances. Je propose un Dockerfile slim avec requirements installés avant le code, USER non-root, plus un Compose avec la base. Chacun lancera la même image, et les secrets resteront hors de l'image, en variables d'environnement. »

À dire en réunion pour faire adopter la conteneurisation sans viser l'expertise DevOps.

Modèle copier-coller — Dockerfile Python + Compose génériques

FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
RUN useradd -m app && chown -R app:app /app
USER app
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
# --- docker-compose.yml (stack generique) ---
# services:
#   api:
#     build: .
#     ports: ["8000:8000"]
#     environment:
#       - DATABASE_URL=postgresql://db:5432/app
#   db:
#     image: postgres:16
#     volumes: ["pgdata:/var/lib/postgresql/data"]

Solo / petit budget

Nabil seul : un Dockerfile slim sans Compose suffit — l'image fige déjà Python et les dépendances.

TPE / équipe réduite

Compose api + bdd : chaque collègue démarre le stack complet sans installer Python ni la base.

PME à Alger

Nabil partage l'image à Alger : tout le monde teste la même version, fin des écarts de poste.

Équipe qui démarre

Binôme : l'un écrit le Dockerfile, l'autre vérifie USER, .dockerignore et 0.0.0.0 avant adoption.

Prudence : Ne mettez jamais de secrets (mots de passe, clés, jetons) dans le Dockerfile ni dans l'image : passez-les par l'environnement au lancement. Une image partagée garde tout son contenu — un secret intégré y reste lisible.

✓ Bonnes pratiques

  • slim + cache : requirements d'abord, code ensuite.
  • USER non-root systématique ; .dockerignore contre .venv et caches.
  • 0.0.0.0 en conteneur, jamais localhost.

✗ Pièges fréquents

  • Copier .venv dans l'image (lourde, non portable).
  • Écouter sur localhost : le service reste injoignable.
  • Confondre dev (bind + reload) et prod (copié + workers).

Points clés à retenir

  • Docker empaquette l'app + son environnement : fini le « ça marche sur ma machine ».
  • Image = modèle figé ; conteneur = instance en exécution.
  • Le Dockerfile décrit la recette de construction de l'image.
  • build (construire) puis run (lancer) : le cycle de base de Docker.

Défi 48h — appliquez demain

Écrivez le Dockerfile de votre app (modèle ci-dessus) et lancez-la en conteneur : répond-elle pareil que sur votre poste ?

Checklist sortie de section
  • Je peux expliquer image vs conteneur en une phrase.
  • Mon Dockerfile construit une image qui tourne.
  • Je sais pourquoi les secrets n'y figurent pas.
Auto-évaluation 1-5 : mon image est-elle reconstructible à l'identique ?un collègue démarrerait-il mon stack en une commande ?

Questions fréquentes

Docker remplace-t-il les environnements virtuels (venv) ?

Ils opèrent à des niveaux différents. Le venv isole les dépendances Python d'un projet sur votre machine. Docker isole l'application entière (Python, système, dépendances) dans un conteneur portable. En pratique, on utilise souvent un venv en développement et Docker pour livrer/déployer — complémentaires, pas concurrents.

Docker est-il nécessaire pour un débutant ?

Pas pour apprendre le langage. Mais dès qu'on déploie une application réelle, qu'on travaille en équipe ou qu'on vise le cloud, Docker devient un standard quasi incontournable. C'est une compétence très valorisée : l'aborder au niveau pro est le bon moment.

Vérifiez votre compréhension

Quel problème Docker résout-il principalement ?

Ressources supplémentaires (optionnel, pour aller plus loin)

Examen du niveau 5Questions inédites et durcies pour valider vos acquis