Docker + IA : conteneuriser ses services intelligents
Vous avez un serveur qui fait tourner une API, une base de données, un reverse proxy, et peut-être un modèle de langage. Tout est installé directement sur l'OS. Un jour, vous mettez à jour Python et tout casse. Votre API ne démarre plus, vos dépendances sont en conflit, et vous passez 4 heures à tout réparer.
Avec Docker, ce scénario n'existe plus. Chaque service tourne dans son conteneur isolé, avec ses propres dépendances, sa propre version de Python, son propre environnement. Mettez à jour ce que vous voulez — les autres services ne bougent pas.
Dans ce guide, on va conteneuriser des services IA concrets : une API FastAPI, un pipeline LLM, et tout l'écosystème autour. Du vrai self-hosting propre et reproductible.
L'essentiel
- Docker isole chaque service IA avec ses propres dépendances, évitant les conflits entre versions de Python ou de bibliothèques.
- Docker Compose orchestre plusieurs conteneurs (API, base de données, reverse proxy) via un seul fichier de configuration.
- Les volumes garantissent la persistance des données, même après suppression ou redémarrage des conteneurs.
- Les health checks empêchent les services de démarrer avant que leurs dépendances ne soient prêtes.
- Pour une mise en production complète, consultez notre guide sur le VPS + IA : le setup complet pour tout auto-héberger.
🐳 Pourquoi Docker pour l'IA
🏛️ Les 4 piliers
| Pilier | Sans Docker | Avec Docker |
|---|---|---|
| Isolation | Python 3.11 casse votre app Python 3.9 | Chaque service a sa propre version |
| Reproductibilité | "Ça marche sur ma machine" | Même image = même résultat partout |
| Scaling | Redémarrer tout le serveur | Scaler juste le service qui en a besoin |
| Déploiement | 47 commandes à taper dans l'ordre | docker compose up -d |
🎯 Pourquoi c'est particulièrement important pour l'IA
Les projets IA ont des dépendances lourdes et conflictuelles. Un projet peut nécessiter PyTorch 2.1 avec NumPy 1.24, tandis qu'un autre requiert TensorFlow 2.14 avec NumPy 1.21. Sans Docker, c'est le cauchemar des virtual environments. Avec Docker, chaque projet tourne dans son conteneur isolé avec ses versions spécifiques, sans aucun conflit.
⚡ Docker vs VM
| Aspect | Docker | VM (VirtualBox, etc.) |
|---|---|---|
| Démarrage | Secondes | Minutes |
| Taille | MBs (image) | GBs (OS complet) |
| Performance | Quasi-native | Overhead virtualisation |
| Isolation | Processus | OS complet |
| Cas d'usage IA | ✅ Idéal | Overkill |
📦 Les bases Docker en 5 minutes
📚 Vocabulaire essentiel
Une Image est le plan de construction (comme une classe), un Container est l'instance en cours d'exécution (comme un objet). Le Dockerfile est la recette pour créer une image, un Volume assure le stockage persistant, un Network crée un réseau virtuel entre conteneurs, et Compose orchestre le tout.
💻 Commandes de survie
Les commandes indispensables : docker ps pour voir les conteneurs actifs, docker ps -a pour voir aussi les arrêtés, docker images pour lister les images, docker logs pour consulter les journaux (avec -f pour le temps réel), docker exec -it pour entrer dans un conteneur, docker stop et docker rm pour l'arrêter et le supprimer, et docker system prune -a pour nettoyer les éléments inutilisés.
📥 Installer Docker
L'installation sur Ubuntu/Debian se fait via le script officiel (curl -fsSL https://get.docker.com | sh), suivi de l'ajout de votre utilisateur au groupe docker pour éviter sudo (sudo usermod -aG docker $USER). Docker Compose est inclus dans Docker Desktop, sinon installez le plugin via apt. Vérifiez avec docker --version et docker compose version.
🏗️ Docker Compose : orchestrer plusieurs services
🤔 Pourquoi Compose ?
Un projet IA typique a besoin d'une API (FastAPI, Flask), d'une base de données (SQLite, PostgreSQL), d'un reverse proxy (Nginx, Caddy), et peut-être d'un cache (Redis) ou d'un worker (Celery). Gérer tout ça avec des docker run individuels est ingérable. Docker Compose définit tout dans un seul fichier.
Le fichier docker-compose.yml décrit chaque service avec son image ou son chemin de build, ses ports exposés, ses volumes de données, ses variables d'environnement, ses dépendances et sa politique de redémarrage. On y définit aussi les health checks qui vérifient périodiquement que chaque service répond correctement.
⌨️ Les commandes Compose essentielles
docker compose up -d démarre tous les services en arrière-plan, docker compose logs -f affiche les logs en temps réel (ajoutez le nom du service pour le filtrer), docker compose restart relance un service spécifique, docker compose down arrête tout, et docker compose up -d --build reconstruit les images après modification du Dockerfile. Attention : docker compose down -v supprime aussi les volumes (perte de données).
🤖 Exemple 1 : API FastAPI + SQLite conteneurisée
📂 Structure du projet
L'architecture suit une structure classique : un dossier api/ contenant le Dockerfile, les dépendances (requirements.txt) et le code Python (main.py), un dossier nginx/ pour la configuration du reverse proxy, un dossier data/ pour la base SQLite, et à la racine le fichier docker-compose.yml et le fichier .env pour les secrets.
🐋 Le Dockerfile de l'API
Le Dockerfile part d'une image python:3.11-slim, désactive les questions interactives et active le mode unbuffered pour Python. Il installe curl pour les health checks, copie les dépendances et les installe avec --no-cache-dir, puis copie le code. Le port 8000 est exposé et un health check vérifie l'endpoint /health toutes les 30 secondes. La commande finale lance uvicorn.
📋 Les dépendances
Le fichier requirements.txt liste les paquets nécessaires : FastAPI 0.109.0, uvicorn avec ses dépendances standards, SQLAlchemy 2.0.25 pour l'ORM, httpx 0.26.0 pour les appels HTTP asynchrones, et Pydantic 2.5.3 pour la validation des données.
⚡ L'API FastAPI
L'application FastAPI expose trois endpoints. /health renvoie le statut et l'horodatage. /ask (POST) reçoit une question et un modèle, appelle l'API OpenRouter via httpx, sauvegarde la requête et la réponse en base SQLite via SQLAlchemy, et renvoie le résultat avec l'ID de la query. /queries (GET) liste les dernières requêtes enregistrées avec pagination.
Pour le choix du provider d'API, consultez notre comparatif des APIs IA : OpenRouter vs appels directs.
🔧 Configuration Nginx
La configuration Nginx définit un upstream vers le service API sur le port 8000. Le bloc server écoute sur le port 80, limite la taille des requêtes à 10Mo, et proxifie tout vers l'API avec les headers nécessaires (X-Real-IP, X-Forwarded-For). Les timeouts sont augmentés à 60 secondes pour les requêtes IA qui peuvent être lentes. L'endpoint /health est proxifié séparément sans logging.
🔑 Le fichier .env
Le fichier .env contient vos secrets : la clé API OpenRouter (OPENROUTER_API_KEY) et le mot de passe de la base de données (DB_PASSWORD). Ce fichier ne doit jamais être commité dans git.
🚀 Lancer le tout
Créez le dossier data (mkdir -p data), lancez l'ensemble avec docker compose up -d --build, vérifiez que tous les conteneurs sont actifs avec docker compose ps, puis testez l'API avec un curl sur /health et un POST sur /ask.
🧠 Exemple 2 : Pipeline LLM conteneurisé
Architecture
Un pipeline LLM typique en conteneurs suit ce flux : la requête utilisateur arrive sur un conteneur API Gateway, qui la transmet à un conteneur Preprocessing (nettoyage du texte, extraction d'intent), puis au conteneur LLM Service (appel au modèle avec gestion du cache Redis), enfin au conteneur Postprocessing (formatage de la réponse, logging) avant de renvoyer la réponse.
Pour une architecture complète, consultez notre guide VPS + IA : le setup complet pour tout auto-héberger.
Docker Compose multi-services
Le fichier compose définit quatre services. Le gateway expose le port 8080 et communique avec le service LLM et Redis. Le llm service gère les appels au modèle avec cache, utilise la clé OpenRouter depuis les variables d'environnement, et possède un health check sur son endpoint. Le cache Redis est configuré avec 256Mo max et une politique d'éviction LRU. Le worker traite les tâches asynchrones et écrit les logs en base. Tous les services dépendent du cache avec la condition service_healthy.
Le service LLM avec cache
Le service LLM implémente un système de cache avec Redis. À chaque requête sur /complete, il calcule un hash MD5 du couple modèle+prompt et vérifie si le résultat est en cache. Si oui, il le renvoie avec le flag cached: true. Sinon, il appelle l'API OpenRouter, stocke le résultat dans Redis avec un TTL d'une heure, puis le renvoie. L'endpoint /health vérifie la connexion Redis et renvoie le statut du cache.
🔧 Tips avancés
Volumes : persister les données
Docker offre trois types de montages : le bind mount lie un dossier local à un chemin du conteneur, le named volume est géré par Docker et persiste même après un docker compose down (supprimé uniquement avec -v), et le montage en read-only (:ro) restreint l'accès en écriture pour renforcer la sécurité. Règle d'or : tout ce qui doit survivre à un docker compose down doit être dans un volume.
Networking : communication entre conteneurs
On peut définir plusieurs réseaux : un réseau frontend accessible depuis l'extérieur (où se trouve Nginx avec les ports exposés), et un réseau backend interne (où communiquent l'API et la base de données). Le flag internal: true empêche tout accès internet depuis ce réseau. Les conteneurs se trouvent par leur nom de service : par exemple, l'URL de base de données utilise db:5432 comme hôte.
Health checks : ne pas démarrer tant que ce n'est pas prêt
Les health checks s'utilisent avec depends_on et la condition service_healthy pour garantir l'ordre de démarrage. On configure l'intervalle de vérification (ex: 30s), le timeout (10s), le nombre de retries avant de déclarer le service unhealthy (3), et un start_period qui donne un délai de grâce au démarrage (ex: 40s) avant de commencer les vérifications.
Optimiser les images Docker
L'ordre des instructions dans le Dockerfile est crucial car Docker met en cache chaque couche. Copiez d'abord requirements.txt et installez les dépendances, puis copiez le code. Ainsi, si seul le code change, Docker réutilise le cache de pip install. Utilisez les images -slim ou -alpine (3 à 5x plus petites), ajoutez --no-cache-dir sur pip, et créez un fichier .dockerignore pour exclure .git, __pycache__, node_modules, les fichiers .md et le dossier tests/ du contexte de build.
🔐 Sécurité Docker
Les bases
Plusieurs mesures de durcissement : faire tourner les conteneurs avec un user non-root (user: "1000:1000"), limiter les ressources CPU et mémoire avec deploy.resources.limits, monter le système de fichiers en read-only (read_only: true) avec un tmpfs pour /tmp, et désactiver l'escalade de privilèges avec security_opt: no-new-privileges:true.
Secrets : ne jamais mettre dans l'image
Ne jamais encoder de clé API dans un ENV du Dockerfile (elle serait visible dans l'image). Passez vos secrets via un fichier .env chargé par Docker Compose (docker compose --env-file .env up -d), ou via Docker Secrets en mode Swarm.
Scanner les vulnérabilités
Docker Scout (intégré) permet de scanner une image avec docker scout cves mon-image:latest. Trivy (gratuit, open source) est une alternative qui s'exécute en conteneur et analyse les vulnérabilités des paquets de l'image.
📊 Monitoring des conteneurs
La commande docker stats affiche les ressources en temps réel (CPU, mémoire, réseau, disque) pour tous les conteneurs actifs. Pour vérifier l'état de santé, docker inspect avec le format approprié retourne le statut des health checks pour chaque conteneur (healthy, unhealthy, ou no-healthcheck).
Script de monitoring Docker
Un script bash de monitoring peut automatiser ces vérifications : lister les conteneurs en cours d'exécution avec leur statut et ports, identifier les conteneurs arrêtés (potentiel problème), afficher l'utilisation CPU et mémoire de chaque conteneur, montrer l'espace disque utilisé par Docker via docker system df, et boucler sur chaque conteneur pour afficher son état de santé.
🚀 Déploiement en production
Checklist pré-production
Avant de passer en prod, vérifiez six points : que .env est bien dans .gitignore, que tous les conteneurs sont "healthy" via docker compose ps, que chaque service a une policy restart: unless-stopped, que les limites de ressources sont configurées, qu'un arrêt-relance complet fonctionne correctement, et que les données persistent bien après un docker compose down puis up.
Mise à jour sans downtime
Pour mettre à jour un service sans interruption : reconstruisez uniquement le service modifié avec docker compose build api, puis relancez-le sans toucher aux dépendances avec docker compose up -d --no-deps api. Vérifiez ensuite le statut et les derniers logs du service.
🗺️ Architectures types
Simple : API + Base de données
Architecture minimale avec Nginx en frontal qui proxifie vers FastAPI, lui-même connecté à une base SQLite stockée dans un volume. Parfait pour un projet personnel, un MVP ou un outil interne.
Intermédiaire : API + PostgreSQL + Cache
Nginx proxifie vers FastAPI, qui communique avec PostgreSQL pour les données et Redis pour le cache. Parfait pour une application avec des utilisateurs et des besoins de performance.
Avancé : Pipeline LLM complet
Nginx envoie vers une API Gateway, qui dispatche vers le service LLM (appelant OpenRouter), un worker async alimenté par Redis, et PostgreSQL pour la persistance. Parfait pour un produit SaaS ou une plateforme IA.
Pour exposer ces architectures sans ouvrir de ports sur votre serveur, consultez notre guide Cloudflare Tunnel : exposer ses services sans ouvrir de ports.
⚠️ Erreurs courantes
| Erreur | Symptôme | Solution |
|---|---|---|
| Pas de volume pour la DB | Données perdues au restart | Ajouter un volumes: |
| Port déjà utilisé | "bind: address already in use" | Changer le port ou stopper le conflit |
Oublier depends_on |
"Connection refused" au démarrage | Ajouter les dépendances + health checks |
| Image trop grosse | Build lent, disque plein | Utiliser -slim, .dockerignore, multi-stage |
| Secrets dans l'image | Fuite de credentials | Utiliser .env + variables d'environnement |
| Pas de restart policy | Services qui ne reviennent pas après reboot | restart: unless-stopped |
| Logs qui remplissent le disque | Disque plein après quelques semaines | Configurer le log driver |
Limiter les logs
Pour éviter que les logs ne remplissent le disque, configurez le driver de logging dans le compose avec une taille max par fichier (ex: 10Mo) et un nombre maximum de fichiers de rotation (ex: 3), ce qui limite l'espace consommé à 30Mo par service.
FAQ
Est-ce que Docker impacte les performances de mes modèles IA ?
L'overhead est négligeable (environ 1-2% de perte) car Docker utilise le noyau de l'hôte, contrairement aux VMs. Pour le GPU, utilisez le runtime nvidia pour accéder directement à la carte graphique depuis les conteneurs.
Combien de RAM faut-il pour faire tourner plusieurs conteneurs IA ?
Comptez au minimum 2Go pour le système hôte + la mémoire de chaque service. Une stack API + PostgreSQL + Redis + Nginx consomme environ 1Go au repos. Prévoyez 4Go minimum sur un VPS dédié à de l'IA légère (appel d'API externes), et beaucoup plus si vous hébergez des modèles localement.
Peut-on utiliser Docker sur un VPS avec seulement 1Go de RAM ?
C'est possible mais très limité. Utilisez exclusivement des images -alpine ou -slim, fixez des limites de mémoire strictes, et évitez d'héberger des bases de données lourdes. Privilégiez SQLite à PostgreSQL dans ce cas.
Comment faire des backups de mes données conteneurisées ?
Pour les volumes nommés, utilisez docker run --rm -v mon_volume:/data -v $(pwd):/backup alpine tar czf /backup/backup.tar.gz /data. Pour les bind mounts, sauvegardez simplement le dossier local. Automatisez avec un cron.
Outils recommandés
- Docker Desktop : environnement de développement intégré avec interface GUI, idéal pour débuter sur Mac ou Windows.
- Portainer : interface web de gestion pour vos conteneurs en production, avec monitoring et gestion des stacks Compose.
- Trivy : scanner de vulnérabilités open source pour vos images Docker.
- Docker Scout : outil intégré à Docker CLI pour analyser les CVE et l'optimisation des images.
- Watchtower : met à jour automatiquement vos conteneurs quand une nouvelle image est publiée.
Conclusion
Docker n'est pas une option quand on self-héberge des services IA — c'est une nécessité. L'isolation des dépendances, la reproductibilité des environnements et la facilité de déploiement transforment un cauchemar opérationnel en un système prévisible et maintenable.
Commencez petit : conteneurisez une API FastAPI avec un reverse proxy Nginx. Puis ajoutez une base de données, un cache Redis, des health checks. Avant de vous en rendre compte, vous gérerez des pipelines LLM complets sans jamais redouter une mise à jour système.
Les bonnes pratiques (volumes, réseaux isolés, secrets via .env, limites de ressources) ne sont pas optionnelles en production. Appliquez-les dès le premier conteneur, pas quand ça casse à 3h du matin.