Exercice 07 : Projet Capstone - Construire et Déployer une Image Docker Personnalisée
🎯 Objectifs
À la fin de cet exercice, vous serez capable de :
- ✅ Écrire un
Dockerfilecomplet avecFROM,RUN,COPY,WORKDIR,ENV,EXPOSE,CMD - ✅ Construire une image avec
docker builden utilisant les bonnes pratiques de layers - ✅ Persister les données avec un volume nommé
- ✅ Connecter plusieurs conteneurs via un réseau bridge personnalisé
- ✅ Déboguer avec
docker execetdocker logs
Durée estimée : 45 minutes
Difficulté : ⭐⭐⭐⭐☆ (Avancé)
Prérequis :
- Docker installé et fonctionnel
- Module Docker Intermédiaire complété (Dockerfile, volumes, réseaux)
- Notions Python de base (lecture, pas écriture)
📖 Contexte
Votre équipe développe une petite API Python (Flask) qui doit être conteneurisée. Vous devez écrire le Dockerfile, créer un réseau isolé pour connecter l'API à sa base de données, et configurer un volume pour persister les données PostgreSQL.
📋 Énoncé
Construisez une image Docker pour une API Flask, connectez-la à un conteneur PostgreSQL via un réseau bridge dédié, et persistez les données avec un volume nommé.
🧭 Déroulement de l'exercice
Tâche 1 : Créer l'application Python
Créez l'arborescence suivante dans un nouveau dossier flask-app/ :
app.py: une application Flask qui expose/et/healthrequirements.txt: avecflask==3.0.3etpsycopg2-binary==2.9.9.dockerignore: excluant__pycache__,*.pyc,venv/,.env
Indice : Le fichier
.dockerignorefonctionne comme.gitignore- il empêche COPY de copier les fichiers inutiles et réduit la taille du build context.
Vérification : Les 3 fichiers existent dans flask-app/. cat flask-app/.dockerignore liste les exclusions.
Tâche 2 : Écrire le Dockerfile
Dans flask-app/, créez un Dockerfile respectant ces contraintes :
- Image de base :
python:3.12-slim - Répertoire de travail :
/app - Variable d'environnement
PYTHONDONTWRITEBYTECODE=1etPYTHONUNBUFFERED=1 - Installer les dépendances AVANT de copier le code source (optimisation du cache)
- Port exposé : 5000
- Utilisateur non-root : créer et utiliser l'utilisateur
appuser - Commande de démarrage :
python app.py
Indice : L'ordre des layers est crucial pour le cache.
COPY requirements.txt .puisRUN pip installavantCOPY . .: si seul le code change, Docker réutilise le layer des dépendances.
Vérification : docker build -t flask-app:v1 flask-app/ doit réussir sans erreur.
Tâche 3 : Créer le réseau et les volumes
Créez un réseau bridge nommé app-network et un volume nommé postgres-data pour la persistance.
Indice :
docker network create --driver bridge app-network.docker volume create postgres-data. Vérifiez avecdocker network lsetdocker volume ls.
Vérification : docker network inspect app-network retourne les détails du réseau. docker volume inspect postgres-data confirme la création.
Tâche 4 : Lancer PostgreSQL sur le réseau
Lancez PostgreSQL en l'attachant au réseau app-network, avec le volume postgres-data monté sur /var/lib/postgresql/data.
Indice :
docker run -d --name db --network app-network -v postgres-data:/var/lib/postgresql/data -e POSTGRES_PASSWORD=secret postgres:16-alpine. Sur le réseauapp-network, le conteneurflaskpourra joindredbpar son nom (résolution DNS automatique).
Vérification : docker exec db pg_isready -U postgres retourne accepting connections.
Tâche 5 : Lancer l'API Flask et tester la communication réseau
Lancez le conteneur flask en l'attachant au réseau app-network, avec le port 5000 mappé sur l'hôte.
Indice :
docker run -d --name flask --network app-network -p 5000:5000 flask-app:v1. Dansapp.py, la connexion à PostgreSQL utilisehost=db(nom du conteneur), qui est résolu automatiquement sur le réseauapp-network.
Vérification : curl http://localhost:5000/health retourne {"status": "ok"}.
Tâche 6 : Valider la persistance du volume
Arrêtez et supprimez le conteneur db, puis relancez-le avec le même volume. Vérifiez que les données sont toujours présentes.
Indice :
docker stop db && docker rm db, puis relancez avec le même-v postgres-data:/var/lib/postgresql/data. Le volume est indépendant du conteneur : ses données survivent à la suppression du conteneur.
Vérification : docker volume inspect postgres-data affiche le Mountpoint. Les données écrites avant la suppression du conteneur sont toujours accessibles après relancement.
🗂️ Mini-Projet : Stack Flask + PostgreSQL avec réseau isolé
Arborescence finale :
flask-app/
├── app.py
├── requirements.txt
├── Dockerfile
└── .dockerignoreCommandes de déploiement complet :
# Infrastructure réseau et stockage
docker network create --driver bridge app-network
docker volume create postgres-data
# Base de données
docker run -d \
--name db \
--network app-network \
-v postgres-data:/var/lib/postgresql/data \
-e POSTGRES_USER=devops \
-e POSTGRES_PASSWORD=secret \
-e POSTGRES_DB=appdb \
postgres:16-alpine
# Build et lancement de l'API
docker build -t flask-app:v1 flask-app/
docker run -d \
--name flask \
--network app-network \
-p 5000:5000 \
flask-app:v1
# Vérification
sleep 3
docker ps
curl http://localhost:5000/health
docker exec flask curl -s http://db:5432 2>&1 | head -2Checkpoints de validation :
docker build -t flask-app:v1 flask-app/réussit sans erreurdocker network inspect app-networkliste les deux conteneurscurl http://localhost:5000/healthretourne{"status": "ok"}docker exec flask curl -s db:5432montre que la communication réseau fonctionne- Après
docker rm db+ relancement, les données PostgreSQL sont intactes docker exec flask whoamiretourneappuser(utilisateur non-root)