# Exercice Dockerfile C ## Objectifs * Choisir une image de base adaptée. * Structurer un **Dockerfile** avec bonnes pratiques : `LABEL`, `ARG`, `ENV`, `WORKDIR`, `COPY`, `RUN`, `EXPOSE`, `VOLUME`, `HEALTHCHECK`, `USER`, `ENTRYPOINT`/`CMD`. * Réduire la taille d’image via **multi-stage build** et couche cache. * Exécuter le service en **non-root**. * Comprendre **.dockerignore**, variables d’env, et ports. * Donner toutes les commandes Docker utilisées. --- ## Énoncé Vous devez conteneuriser une petite API Flask qui expose : * `GET /` → `{"msg":"Hello from Docker!"}` * `GET /health` → `{"status":"ok"}` ### *Contraintes :* 1. Écrire un **Dockerfile multi-stage**: * **Stage builder** : installation des dépendances (roue/compilation si nécessaire). * **Stage runtime** : image plus légère, copie minimaliste. 2. Ajouter des **LABEL** (auteur, version, description). 3. Gérer un **ARG** `APP_ENV` (valeurs: `dev` ou `prod`) avec une **ENV** par défaut. 4. Définir `WORKDIR`, `COPY` (en respectant un `.dockerignore`). 5. Créer un **utilisateur non-root** et exécuter l’appli avec cet utilisateur. 6. Ouvrir le **port 8000** (`EXPOSE 8000`). 7. Ajouter un **HEALTHCHECK** qui vérifie `http://localhost:8000/health`. 8. Utiliser `ENTRYPOINT` + `CMD` correctement (ENTRYPOINT = processus, CMD = args). 9. Déclarer un **VOLUME** `/app/logs` (les logs y sont écrits). ### *Livrables :* * `Dockerfile` * `.dockerignore` * Code minimal de l’API (`app.py`, `requirements.txt`) * Commandes pour **build**, **run**, **test**, **inspecter** la santé. --- ## Squelette de projet ``` project/ ├─ app.py ├─ requirements.txt ├─ Dockerfile └─ .dockerignore ``` ### app.py ```python from flask import Flask, jsonify import os, sys, pathlib app = Flask(__name__) LOG_DIR = pathlib.Path("/app/logs") LOG_DIR.mkdir(parents=True, exist_ok=True) open(LOG_DIR / "app.log", "a").close() @app.route("/") def root(): return jsonify(msg="Hello from Docker!", env=os.getenv("APP_ENV", "dev")) @app.route("/health") def health(): return jsonify(status="ok") if __name__ == "__main__": # Bind sur 0.0.0.0 pour être accessible depuis le conteneur app.run(host="0.0.0.0", port=8000) ``` ### requirements.txt ``` python flask==3.0.3 ``` ### .dockerignore Voici une version incomplete, veuillez le completer pour éviter que des fichiers ou répertoires non désirés ce retrouvent dans l'image Docker. ``` __pycache__/ *.pyc *.log .git .gitignore .env .cache/ ``` ### Tips * Voici les packages apt qui seront utiles d'installer : `build-essential`, `curl`, `ca-certificates` * Utiliser de préférence `pip wheel` pour optimiser la taille de l'image - [Pip Wheel Doc](https://pip.pypa.io/en/stable/cli/pip_wheel/) * Pour le health check utiliser `curl` comme ceci : ```sh HEALTHCHECK --interval=10s --timeout=2s --retries=3 CMD curl -f http://localhost:8000/health || exit 1 ``` ## Pour aller plus loin * Mesurer la **taille** de l’image et la réduire (changer de base : `slim` vs `alpine`). * Ajouter un **USER ID** via `--build-arg UID=10001`. * Multi-stage avancé : figer `pip wheel` dans le builder puis copier uniquement les wheels.