Objectif: Créer une image Docker simple avec Nginx qui affiche une page personnalisée.
Instructions:
index.html
avec un message de votre choixindex.html
dans le répertoire appropriémkdir nginx-docker-simple
cd nginx-docker-simple
index.html
:<!DOCTYPE html>
<html>
<head>
<title>Mon Premier Docker</title>
</head>
<body>
<h1>Bonjour depuis mon conteneur Docker !</h1>
<p>Cette page est servie par Nginx dans un conteneur Docker.</p>
</body>
</html>
FROM nginx:latest
COPY index.html /usr/share/nginx/html/
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
docker build -t mon-nginx:v1 .
docker run -d -p 8080:80 --name mon-premier-nginx mon-nginx:v1
curl http://localhost:8080
Objectif: Créer une image Docker optimisée pour Nginx qui inclut un HEALTHCHECK et utilise les meilleures pratiques.
Instructions:
nginx:alpine
)<!DOCTYPE html>
<html>
<head>
<title>Nginx Optimisé</title>
<style>
body { font-family: Arial, sans-serif; margin: 40px; }
h1 { color: #2c3e50; }
</style>
</head>
<body>
<h1>Nginx sur Alpine Linux</h1>
<p>Cette page est servie par une image Docker optimisée.</p>
</body>
</html>
FROM nginx:1.27.4-alpine3.21
# Installation des outils pour healthcheck en une seule couche
RUN apk add --no-cache curl && \
rm -rf /var/cache/apk/*
# Définition du répertoire de travail
WORKDIR /usr/share/nginx/html
# Copie du fichier HTML
COPY index.html .
# Exposition du port
EXPOSE 80
# Configuration du healthcheck
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost/ || exit 1
# Commande de démarrage
CMD ["nginx", "-g", "daemon off;"]
docker build -t nginx-optimise:v1 .
docker images nginx-optimise:v1 # Vérifiez la taille
docker run -d -p 8080:80 --name nginx-healthcheck nginx-optimise:v1
# Après quelques secondes pour permettre au healthcheck de s'exécuter
docker ps
# Vous devriez voir "healthy" dans la colonne STATUS
Objectif: Créer une image Docker optimisée pour une application Flask en utilisant un multi-stage build pour réduire la taille de l'image finale et améliorer la sécurité.
Contexte: Vous avez une application web Flask avec des dépendances qui sont nécessaires pour le build mais pas pour l'exécution. Vous voulez créer une image Docker aussi légère que possible pour le déploiement en production.
Instructions:
Créez la structure de projet suivante:
flask-app/
├── app/
│ ├── __init__.py
│ ├── app.py
│ └── templates/
│ └── index.html
├── requirements.txt
├── requirements-dev.txt
└── Dockerfile
Contenu des fichiers:
app.py
: Un simple serveur Flask qui affiche un message de bienvenue avec la version de l'applicationrequirements.txt
: Les dépendances minimales pour l'exécutionrequirements-dev.txt
: Les dépendances supplémentaires pour le développement et les testsindex.html
: Une page HTML simpleCréez un Dockerfile multi-stage qui:
Construisez l'image et comparez sa taille avec une approche standard à étape unique.
Lancez un conteneur et vérifiez que l'application fonctionne et que le HEALTHCHECK est opérationnel.
# Fichier d'initialisation du package
app/app.py
from flask import Flask, render_template
import os
app = Flask(__name__)
# Configuration
APP_VERSION = os.environ.get('APP_VERSION', '1.0.0')
ENV_TYPE = os.environ.get('FLASK_ENV', 'production')
@app.route('/')
def index():
return render_template('index.html', version=APP_VERSION, env=ENV_TYPE)
@app.route('/health')
def health():
return {"status": "healthy"}, 200
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
app/templates/index.html
index.html
:
<!DOCTYPE html>
<html>
<head>
<title>Flask App</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
.container {
background-color: #f5f5f5;
border-radius: 5px;
padding: 20px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.info {
color: #2c3e50;
margin-top: 20px;
}
</style>
</head>
<body>
<div class="container">
<h1>Flask Application</h1>
<div class="info">
<p>Version: <strong>{{ version }}</strong></p>
<p>Environnement: <strong>{{ env }}</strong></p>
</div>
</div>
</body>
</html>
requirements.txt
:flask==3.1.0
gunicorn==23.0.0
requirements-dev.txt
-r requirements.txt
pytest==8.3.5
flake8==7.1.2
black==25.1.0
isort==6.0.1
mypy==1.15.0
# Étape 1: Image de build
FROM python:3.9-alpine AS builder
# Installation des dépendances de build
RUN apk add --no-cache gcc musl-dev linux-headers
WORKDIR /app
# Copie des fichiers de requirements
COPY requirements.txt requirements-dev.txt ./
# Installation de toutes les dépendances dans un environnement virtuel
RUN python -m venv /venv && \
/venv/bin/pip install --no-cache-dir --upgrade pip && \
/venv/bin/pip install --no-cache-dir -r requirements-dev.txt
# Copie du code de l'application
COPY app/ ./app/
# Étape 2: Image finale de production
FROM python:3.9-alpine AS production
# Création d'un utilisateur non-root
RUN addgroup -g 1000 appgroup && \
adduser -D -u 1000 -G appgroup appuser && \
mkdir -p /app && \
chown -R appuser:appgroup /app
# Installation des dépendances minimales pour l'exécution
RUN apk add --no-cache curl
# Configuration des variables d'environnement
ENV APP_VERSION="1.0.0" \
FLASK_ENV="production" \
PATH="/venv/bin:$PATH"
# Copie de l'environnement virtuel depuis l'étape de build
COPY --from=builder /venv /venv
# Copie du code de l'application
WORKDIR /app
COPY --from=builder --chown=appuser:appgroup /app/app ./app
# Définition du HEALTHCHECK
HEALTHCHECK --interval=30s --timeout=5s --start-period=5s --retries=3 \
CMD curl -f http://localhost:5000/health || exit 1
# Exposition du port
EXPOSE 5000
# Passage à l'utilisateur non-root
USER appuser
# Commande de démarrage
CMD ["gunicorn", "--bind", "0.0.0.0:5000", "app:app"]
FROM python:3.9-alpine
RUN apk add --no-cache gcc musl-dev linux-headers curl
WORKDIR /app
COPY requirements.txt requirements-dev.txt ./
RUN pip install --no-cache-dir -r requirements-dev.txt
COPY app/ ./app/
ENV APP_VERSION="1.0.0" \
FLASK_ENV="production"
HEALTHCHECK --interval=30s --timeout=5s --start-period=5s --retries=3 \
CMD curl -f http://localhost:5000/health || exit 1
EXPOSE 5000
CMD ["gunicorn", "--bind", "0.0.0.0:5000", "app:app"]
Commandes pour construire et comparer les images:
# Construction de l'image multi-stage
docker build -t flask-app:multi-stage .
# Construction de l'image à étape unique
docker build -f Dockerfile.single -t flask-app:single .
# Comparaison des tailles
docker images | grep flask-app
Résultat attendu de la comparaison:
REPOSITORY TAG IMAGE ID CREATED SIZE
flask-app multi-stage xxxxxxxxxx xx minutes ago ~80-90MB
flask-app single xxxxxxxxxx xx minutes ago ~150-200MB
Lancement et test de l'application:
# Lancement du conteneur
docker run -d -p 5000:5000 -e APP_VERSION=2.1.0 -e FLASK_ENV=staging --name flask-app flask-app:multi-stage
# Vérification que l'application répond
curl http://localhost:5000
# Vérification du statut de santé
curl http://localhost:5000/health
# Vérification du statut du conteneur (doit afficher "healthy")
docker ps