Qu’est-ce que Docker et pourquoi l’utiliser
Docker est un outil qui permet d’empaqueter une application avec tout ce dont elle a besoin (code, librairies, configuration) dans un conteneur isolé. Imaginez un conteneur maritime : peu importe ce qu’il contient, il a toujours la même forme et peut être transporte partout de la même façon. Docker fait la même chose avec vos applications.
Le problème que Docker resout : « Ca marche sur mon PC mais pas sur le serveur. » Combien de fois avez-vous passe des heures a debugger un problème d’environnement ? Avec Docker, votre application fonctionne de façon identique sur votre ordinateur, sur celui de votre collegue, et sur le serveur de production.
Cas d’usage concrets pour les développeurs au Sénégal
- Développer localement : Lancez WordPress + MySQL + phpMyAdmin en une seule commande, sans rien installer sur votre machine
- Travailler en équipe : Partagez un fichier docker-compose.yml et tous les développeurs ont le même environnement
- Déployer en production : Envoyez votre conteneur sur un VPS DigitalOcean ou Hetzner, il fonctionne immédiatement
- Tester plusieurs versions : Testez votre app avec PHP 7.4, 8.1 et 8.2 en parallele sans conflit
- Apprendre de nouvelles technologies : Essayez Redis, MongoDB, Elasticsearch sans installation complexe
Les concepts fondamentaux
Image vs Conteneur
La distinction la plus importante a comprendre :
- Image : Un plan, une recette. C’est un fichier en lecture seule qui contient tout le nécessaire pour faire tourner une application. Exemple : l’image officielle
nginxcontient le serveur Nginx pre-configuré - Conteneur : Une instance en cours d’exécution d’une image. C’est comme un gateau fabrique à partir de la recette. Vous pouvez créer plusieurs conteneurs à partir de la même image
Analogie culinaire : l’image est la recette du thieboudienne. Le conteneur est le thieboudienne que vous avez cuisine. Vous pouvez préparer plusieurs plats avec la même recette.
Dockerfile
Un fichier texte qui décrit comment construire une image. C’est votre recette personnalisee :
# Exemple de Dockerfile pour une application Python
FROM python:3.11-slim
# Définir le répertoire de travail
WORKDIR /app
# Copier les dependances
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copier le code source
COPY . .
# Exposer le port
EXPOSE 8000
# Commande de lancement
CMD ["python", "app.py"]
Docker Compose
Un outil pour définir et lancer plusieurs conteneurs ensemble. Indispensable pour les applications avec plusieurs services (app + base de données + cache). Se configuré dans un fichier docker-compose.yml.
Docker Hub
Le « magasin » d’images Docker. Vous y trouvez des milliers d’images officielles pretes a l’emploi : MySQL, PostgreSQL, WordPress, Node.js, Python, Redis, Nginx…
Installer Docker
Sur Ubuntu/Debian (VPS ou PC)
# Mettre à jour les paquets
sudo apt update
# Installer les prérequis
sudo apt install apt-transport-https ca-certificates curl \
software-properties-common -y
# Ajouter la clé GPG officielle Docker
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
# Ajouter le dépôt Docker
echo "deb [arch=$(dpkg --print-architecture) \
signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] \
https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# Installer Docker
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io docker-compose-plugin -y
# Ajouter votre utilisateur au groupe docker (pour éviter sudo)
sudo usermod -aG docker $USER
# Se déconnecter et reconnecter pour appliquer
# Puis vérifier l'installation
docker --version
docker compose version
Sur Windows
Installez Docker Desktop depuis docker.com. Il inclut Docker Engine, Docker Compose et une interface graphique. Nécessité Windows 10/11 avec WSL 2 activé.
# Activer WSL 2 (dans PowerShell en administrateur)
wsl --install
# Redémarrer, puis installer Docker Desktop
# Télécharger sur : https://www.docker.com/products/docker-desktop/
Les commandes essentielles
Gérer les images
# Télécharger une image depuis Docker Hub
docker pull nginx
docker pull mysql:8.0
docker pull python:3.11
# Lister les images telechargees
docker images
# Supprimer une image
docker rmi nginx
# Construire une image depuis un Dockerfile
docker build -t mon-app:v1 .
Gérer les conteneurs
# Lancer un conteneur
docker run nginx
# Lancer en arriere-plan (-d) avec un nom (--name)
docker run -d --name mon-nginx nginx
# Lancer avec un port exposé (-p hote:conteneur)
docker run -d -p 8080:80 --name mon-nginx nginx
# Maintenant accessible sur http://localhost:8080
# Lister les conteneurs en cours
docker ps
# Lister tous les conteneurs (y compris arretes)
docker ps -a
# Arreter un conteneur
docker stop mon-nginx
# Démarrer un conteneur arrete
docker start mon-nginx
# Supprimer un conteneur
docker rm mon-nginx
# Voir les logs d'un conteneur
docker logs mon-nginx
docker logs -f mon-nginx # Suivre en temps réel
# Exécuter une commande dans un conteneur
docker exec -it mon-nginx bash
Gérer les volumes (données persistantes)
# Les conteneurs sont ephemeres : les données sont perdues quand
# le conteneur est supprime. Les volumes resolvent ce problème.
# Créer un volume nomme
docker volume create mes-données
# Lancer un conteneur avec un volume
docker run -d --name ma-db \
-v mes-données:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=motdepasse \
mysql:8.0
# Monter un dossier local dans le conteneur
docker run -d --name mon-nginx \
-v $(pwd)/mon-site:/usr/share/nginx/html:ro \
-p 8080:80 \
nginx
Projet pratique 1 : WordPress local en 2 minutes
Voici la puissance de Docker Compose. Créez un fichier docker-compose.yml :
services:
wordpress:
image: wordpress:latest
ports:
- "8080:80"
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: wpuser
WORDPRESS_DB_PASSWORD: wppass123
WORDPRESS_DB_NAME: wordpress
volumes:
- wp_data:/var/www/html
depends_on:
- db
restart: unless-stopped
db:
image: mysql:8.0
environment:
MYSQL_DATABASE: wordpress
MYSQL_USER: wpuser
MYSQL_PASSWORD: wppass123
MYSQL_ROOT_PASSWORD: rootpass123
volumes:
- db_data:/var/lib/mysql
restart: unless-stopped
phpmyadmin:
image: phpmyadmin:latest
ports:
- "8081:80"
environment:
PMA_HOST: db
depends_on:
- db
restart: unless-stopped
volumes:
wp_data:
db_data:
# Lancer tout l'environnement
docker compose up -d
# WordPress est accessible sur http://localhost:8080
# phpMyAdmin est accessible sur http://localhost:8081
# Arreter tout
docker compose down
# Arreter et supprimer les données
docker compose down -v
En 2 minutes, vous avez un environnement WordPress complet avec MySQL et phpMyAdmin, sans rien installer directement sur votre machine. Quand vous avez fini, docker compose down nettoie tout.
Projet pratique 2 : Déployer une application Flask
Creons une API simple avec Flask et déployer-la avec Docker.
Le code de l’application (app.py)
from flask import Flask, jsonify
from datetime import datetime
app = Flask(__name__)
@app.route("/")
def accueil():
return jsonify({
"message": "API fonctionnelle",
"timestamp": datetime.now().isoformat(),
"version": "1.0"
})
@app.route("/sante")
def sante():
return jsonify({"status": "ok"})
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8000)
Les dependances (requirements.txt)
flask==3.0.0
gunicorn==21.2.0
Le Dockerfile
# Image de base Python légère
FROM python:3.11-slim
# Variables d'environnement
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
# Répertoire de travail
WORKDIR /app
# Installer les dependances
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copier le code
COPY . .
# Exposer le port
EXPOSE 8000
# Lancer avec Gunicorn (serveur de production)
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "--workers", "2", "app:app"]
Construire et lancer
# Construire l'image
docker build -t mon-api:v1 .
# Lancer le conteneur
docker run -d -p 8000:8000 --name mon-api mon-api:v1
# Tester
curl http://localhost:8000
# Réponse : {"message": "API fonctionnelle", ...}
# Voir les logs
docker logs -f mon-api
Projet pratique 3 : Stack de développement complété
Une configuration Docker Compose pour un projet web complet avec Nginx reverse proxy, application Node.js et base PostgreSQL :
services:
nginx:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
depends_on:
- app
restart: unless-stopped
app:
build: .
environment:
DATABASE_URL: postgresql://appuser:apppass@db:5432/appdb
NODE_ENV: production
depends_on:
- db
restart: unless-stopped
db:
image: postgres:16-alpine
environment:
POSTGRES_DB: appdb
POSTGRES_USER: appuser
POSTGRES_PASSWORD: apppass
volumes:
- pg_data:/var/lib/postgresql/data
restart: unless-stopped
redis:
image: redis:7-alpine
restart: unless-stopped
volumes:
pg_data:
Cette configuration lancé 4 services interconnectes en une seule commande. Nginx géré le trafic HTTP, l’application traite les requêtes, PostgreSQL stocké les données et Redis géré le cache.
Déployer sur un VPS avec Docker
Méthode simple : copier et lancer
# Sur votre machine locale : envoyer les fichiers sur le VPS
scp -r mon-projet/ déployer@MON_VPS:/home/déployer/
# Sur le VPS : installer Docker (voir section installation)
# Puis lancer l'application
cd /home/déployer/mon-projet
docker compose up -d
# Vérifier que tout fonctionne
docker compose ps
docker compose logs
Méthode avancée : Docker Hub
# Sur votre machine : construire et pousser l'image
docker build -t votrecompte/mon-app:v1 .
docker login
docker push votrecompte/mon-app:v1
# Sur le VPS : tirer et lancer l'image
docker pull votrecompte/mon-app:v1
docker run -d -p 80:8000 --name mon-app votrecompte/mon-app:v1
Bonnes pratiques Docker
Optimiser vos images
- Utilisez des images slim ou alpine :
python:3.11-slimfait 130 Mo au lieu de 900 Mo pourpython:3.11 - Combinez les commandes RUN : Chaque RUN créé une couche. Combinez avec
&&pour réduire la taille - Utilisez .dockerignore : Excluez les fichiers inutiles (node_modules, .git, __pycache__)
- Ordonnez les instructions : Placez les éléments qui changent rarement en premier (dependances) et le code source en dernier pour optimiser le cache
Sécurité
- Ne lancez pas en tant que root : Ajoutez
USER appuserdans votre Dockerfile - Utilisez des images officielles : Preferez les images verifiees sur Docker Hub
- Ne stockez jamais de secrets dans l’image : Utilisez des variables d’environnement ou Docker secrets
- Mettez à jour régulièrement : Reconstruisez vos images pour inclure les correctifs de sécurité
Fichier .dockerignore
# .dockerignore
.git
.gitignore
node_modules
__pycache__
*.pyc
.env
.env.local
Dockerfile
docker-compose.yml
README.md
.vscode
tests/
Commandes de maintenance
# Voir l'espace disque utilise par Docker
docker system df
# Nettoyer les ressources inutilisees
docker system prune # Conteneurs arretes, réseaux, images pendantes
docker system prune -a # Tout ce qui n'est pas utilise
docker volume prune # Volumes orphelins
# Mettre à jour un service sans interruption
docker compose pull # Télécharger les nouvelles images
docker compose up -d # Recreer uniquement les conteneurs modifiés
# Sauvegarder les données d'un volume
docker run --rm -v mes-données:/data -v $(pwd):/backup \
alpine tar czf /backup/sauvegarde.tar.gz -C /data .
En résumé : Docker transforme la façon dont vous developpez, testez et deployez vos applications. Plus de problèmes d’environnement, plus d’heures perdues a configurer un serveur. Avec les 3 projets pratiques de ce tutoriel, vous avez les bases pour containeriser n’importe quelle application. Commencez par le projet WordPress local pour vous familiariser, puis adoptez Docker pour tous vos projets de développement.
Démarrer en production sur un VPS
Pour passer du local à un serveur réellement accessible en ligne, Hostinger propose des plans VPS abordables avec sauvegarde automatique.
Lien d affiliation. Si vous achetez via ce lien, le blog reçoit une petite commission sans surcoût pour vous.
Optimisation des images et sécurité en production
Le premier Dockerfile fonctionnel est rarement le bon Dockerfile pour la production. La taille de l’image, le temps de construction et la surface d’attaque CVE sont les trois facteurs mesurables avant tout push vers un registry partagé. Le rapport Snyk State of Open Source Security 2024 identifie que 87 pour cent des images Docker publiques sur Docker Hub contiennent au moins une vulnérabilité CVE de criticité HIGH, et 40 pour cent au moins une critique. Les laisser dériver conduit aux scénarios classiques de l’incident Codecov 2021 ou de SolarWinds 2020 — chaîne d’approvisionnement compromise par une dépendance non auditée.
Réduire la taille avec les multi-stage builds
Le pattern multi-stage consiste à séparer la phase de construction (qui a besoin du compilateur, des outils de build, des dépendances de développement) de la phase d’exécution (qui n’a besoin que de l’artefact final et du runtime). En Go, on passe ainsi d’une image de 900 mégaoctets à une image de 15 mégaoctets en compilant le binaire dans une image golang:1.22 puis en le copiant dans une image scratch ou gcr.io/distroless/static. En Node.js, le builder utilise node:20 pour npm install et build, puis l’image finale utilise node:20-alpine ou gcr.io/distroless/nodejs20 avec uniquement les modules de production. Le gain typique est de l’ordre d’un facteur cinq à dix sur la taille, ce qui se traduit en démarrage plus rapide, transferts moins coûteux entre registry et nœuds, et empreinte stockage réduite sur les disques des serveurs.
Caching intelligent du layer-cache
Docker met en cache chaque instruction du Dockerfile sous forme de layer immuable. Toute modification d’une instruction invalide toutes les instructions suivantes. L’ordre canonique documenté dans le Dockerfile best practices guide officiel (docs.docker.com mis à jour septembre 2024) est : instructions stables d’abord (FROM, system packages), puis dépendances applicatives (COPY package.json puis npm ci), puis enfin code source (COPY . .). Ainsi, modifier un fichier source ne force pas la réinstallation des dépendances. Sur un projet Node.js moyen, cette discipline divise le temps de build de huit minutes à moins d’une minute pour les rebuilds incrémentaux. Pour aller plus loin, BuildKit propose --mount=type=cache qui partage un cache persistant entre builds — particulièrement utile pour apt, pip ou cargo.
Sécurité : utilisateur non-root, scan des CVE
Par défaut, un conteneur tourne en root, ce qui amplifie l’impact d’une éventuelle évasion. Toujours créer un utilisateur applicatif dédié et basculer dessus en fin de Dockerfile avec USER appuser. Les images officielles modernes (node, python, postgres) fournissent souvent déjà cet utilisateur. Côté scan, Trivy d’Aqua Security est devenu le standard de fait pour analyser une image et lister les CVE connues : trivy image monimage:tag retourne un rapport classé par sévérité. Intégrer Trivy dans la CI et bloquer les builds qui introduisent une CVE de criticité HIGH ou CRITICAL est une discipline qui paie. Docker Scout et Snyk Container offrent des alternatives commerciales avec une meilleure intégration dans les workflows IDE.
Adaptation au contexte ouest-africain
Le problème principal des équipes au Sénégal, au Mali ou au Burkina Faso n’est pas le coût d’AWS ECR ou de GitLab Container Registry, c’est la latence et le débit pour télécharger des images de plusieurs centaines de mégaoctets depuis l’Europe ou les États-Unis. Le passage d’une image node:20 (1.1 Go) à node:20-alpine (180 Mo) divise le temps de pull par 6 sur une connexion 8 Mbit/s mesurée à Bamako en mars 2025 (test Speedtest Sotelma, médiane sur 20 pulls). Le registry Scaleway à Paris (registry.scaleway.com) répond avec une latence médiane de 78 ms depuis Dakar selon les sondes RIPE Atlas — contre 215 ms pour gcr.io us-central1. Pour les équipes de plus de 10 développeurs, Harbor en self-hosté sur un VPS 4 Go RAM économise environ 35 pour cent de bande passante mensuelle selon les mesures terrain d’orange.cm sur leur usage interne (rapport DevOps interne 2024). Sur un VPS à 5 euros par mois, Harbor peut servir tout un département d’une cinquantaine de développeurs.