4.3 Premier Docker Compose
Créons notre premier Docker Compose en ajoutant une base de données et une interface pour l'administrer et une application
Maintenant, passons à la pratique de manière chirurgicale ! Pour cela, nous allons simplement utiliser Docker Compose pour lancer notre application, une base de données et une application qui va permettre de visualiser cette base de données. Dans notre cas, on va utiliser MySQL 8.0 et phpMyAdmin, qui sont deux grands classiques.
Dans un premier temps, nous allons définir un plan d'action comme nous aurions pu le faire lors de la création de notre Dockerfile pour l'application, sauf qu'ici, nous allons devoir schématiser cela de manière un peu plus large.
Voici un exemple d'un diagramme technique très simple :

On y voit donc une application Python (FastAPI dans notre cas), une application phpMyAdmin qui permet d'avoir une interface UI pour la base de données, et une base de données MySQL.
Revenons à nos moutons : nous avons maintenant une vue d'ensemble simple et rapide pour savoir comment nous allons conteneuriser tout cela efficacement !
Comme pour le cours sur la création d'un Dockerfile, nous allons découper cela en plusieurs morceaux digestes et logiques.
Le service applicatif
Voici ce que l'on sait du service applicatif :
- Développé en Python avec FastAPI -> port
8000généralement. - Nécessite une base de données pour fonctionner -> variables d'environnement à injecter.
- Pas de rétention d'information de son côté -> pas de volume à monter.
Avec ces informations, nous pouvons traduire ce service comme suit :
services:
python:
image: kernellab/fastapi_docker:latest
env_file:
- .env
ports:
- 8000:8000
Voilà un service Docker Compose des plus simples : on utilise l'image construite lors du cours précédent, on charge le fichier .env situé à la racine (au même niveau que le fichier compose.yaml), et on mappe le port 8000 du conteneur sur le port 8000 de notre machine hôte. Maintenant, passons au service de base de données, le plus critique.
Le service de base de données MySQL
Décortiquons également ce dont nous allons avoir besoin pour bien comprendre :
- C'est du MySQL, donc le port standard est le
3306. - Utilisation de variables d'environnement -> nécessitera un fichier
.env. - La base de données doit pouvoir conserver ses informations en cas de redémarrage -> nous allons devoir monter un volume.
Pour trouver nos informations et comprendre où monter le volume, nous nous rendons sur la documentation officielle Docker Hub de MySQL.
Grâce à cette documentation, nous obtenons plusieurs informations clés :
- Le volume doit être monté sur l'emplacement
/var/lib/mysql. - Variables d'environnement nécessaires pour lancer MySQL :
MYSQL_ROOT_PASSWORD: Le mot de passe rootMYSQL_USER: L'utilisateur applicatifMYSQL_PASSWORD: Le mot de passe de l'utilisateurMYSQL_DATABASE: La base de données créée par défaut
Ce sont des informations très précises et indispensables à connaître, sans quoi le conteneur plantera au démarrage pour différentes raisons pas toujours évidentes à comprendre au début.
Voici à quoi ressemble notre service de base de données :
database:
image: mysql:8.0
env_file:
- .env
ports:
- 3306:3306
volumes:
- database:/var/lib/mysql
Persistance et volumes Docker
Le volume monté sert d'espace de stockage persistant pour les données de votre conteneur. Dans notre situation, toutes les informations écrites dans /var/lib/mysql à l'intérieur du conteneur seront conservées sur la machine hôte.
Attention : les conteneurs et les volumes peuvent occuper beaucoup de place sur votre machine. Pensez de temps en temps à nettoyer votre environnement avec docker system prune !
Le service phpMyAdmin
Ce service va être également très simple car il ne contient pas de volume particulier et sert juste à se connecter à notre base de données en TCP via l'interface web pour visualiser les tables, les bases de données et interagir avec elles.
Pour ce faire, nous avons besoin de :
- Une visibilité web : mapper le port
8080de l'hôte sur le port80du conteneur.
En consultant la documentation Docker Hub de phpMyAdmin, nous trouvons une configuration prête à l'emploi :
phpmyadmin:
image: phpmyadmin
restart: always
ports:
- 8080:80
environment:
- PMA_ARBITRARY=1
PMA_ARBITRARY=1 pour pouvoir modifier des paramètres à la volée comme l'IP, le serveur hôte... Mais en production, ne laissez jamais cette option active.Maintenant que nous avons nos 3 services proprement découpés, nous allons les assembler dans un seul fichier !
L'assemblage des services
Pour cela, vous allez devoir créer un fichier nommé compose.yaml à la racine de votre repository / dossier, de manière à avoir les fichiers d'environnement au bon endroit.
Une fois votre fichier créé, nous allons y ajouter nos 3 services sous le mot-clé principal services: :
services:
python:
image: kernellab/fastapi_docker:latest
env_file:
- .env
ports:
- 8000:8000
database:
image: mysql:8.0
env_file:
- .env
ports:
- 3306:3306
volumes:
- database:/var/lib/mysql
phpmyadmin:
image: phpmyadmin
restart: always
ports:
- 8080:80
environment:
- PMA_ARBITRARY=1
Là, on commence à avoir quelque chose de propre ! Cependant, lancé tel quel, le Docker Compose ne marchera pas : il nous manque 2 éléments essentiels et 1 optionnel que nous allons mettre en place.
1. La déclaration du volume
Il existe deux façons de déclarer des volumes :
./database:/var/lib/mysql-> Bind Mount : lie un dossier de notre projet nommédatabasepour partager des fichiers en temps réel entre le conteneur et la machine hôte (très pratique en développement pour le hot reload).database:/var/lib/mysql-> Volume nommé (Named Volume) : Docker crée un volume géré par le système pour stocker des informations persistantes (très recommandé en production et pour le stockage de bases de données).
Dans notre cas, nous allons utiliser le volume nommé pour la base de données (option n°2). Il faudra donc déclarer ce volume à la racine du fichier Compose sous la clé volumes:.
2. Création du fichier de variables d'environnement (.env)
Pour lancer nos applications, nous avons besoin de variables d'environnement pour configurer les identifiants et accès.
Pour notre application Python, nous aurons besoin de :
- Le nom de la base de données
- Le port de la base de données
- L'utilisateur de la base de données
- Le mot de passe de la base de données
Règle d'or de sécurité
On n'utilisera jamais l'utilisateur root directement pour une application : ce serait une hérésie en matière de sécurité !
Pour notre service de base de données MySQL :
- Le mot de passe pour le compte
root - Le nom de la base de données à créer
- Un utilisateur pour l'application
- Un mot de passe pour l'utilisateur
Créons notre fichier .env :
DB_USER=kernellab
DB_PASSWORD=kernellab123
DB_HOST=database
DB_PORT=3306
DB_ROOT_PASSWORD=unmotdepasseroot
DB_DATABASE=kernellab
Bonne pratique .gitignore
Pensez à ajouter votre fichier .env dans votre .gitignore et .dockerignore pour ne jamais versionner ni commit de données sensibles (clés d'API, mots de passe...).
Le fichier .env est un simple fichier de paires CLÉ=VALEUR. Notre rôle sera de mapper ces valeurs dans le fichier Docker Compose avec la directive environment: :
services:
python:
image: kernellab/fastapi_docker:latest
env_file:
- .env
ports:
- 8000:8000
database:
image: mysql:8.0
environment:
- MYSQL_ROOT_PASSWORD=${DB_ROOT_PASSWORD:-root}
- MYSQL_DATABASE=${DB_DATABASE:-fastapi_docker}
- MYSQL_USER=${DB_USER:-fastapi_user}
- MYSQL_PASSWORD=${DB_PASSWORD:-fastapi_password}
ports:
- 3306:3306
volumes:
- database:/var/lib/mysql
phpmyadmin:
image: phpmyadmin
restart: always
ports:
- 8080:80
environment:
- PMA_ARBITRARY=1
volumes:
database:
MYSQL_ROOT_PASSWORD: La variable officielle attendue par l'image MySQL.DB_ROOT_PASSWORD: Notre variable injectée dynamiquement depuis le fichier.env.:-root: La valeur de repli par défaut si la variable n'est pas fournie dans le.env.${}: La syntaxe d'interpolation dynamique de Docker Compose.
3. Création du réseau interne (Networks)
Passons à la gestion du réseau Docker : c'est une notion essentielle qui permet de sécuriser vos applications à travers un système de réseaux internes pour isoler les services entre eux. Il existe plusieurs types de réseaux :
| Type de Réseau | Cas d'usage principal | Portée |
|---|---|---|
| Bridge | Applications web standards, bases de données | Une seule machine (Hôte local) |
| Overlay | Clusters Docker Swarm, haute disponibilité | Multi-machines (Serveurs multiples) |
| Host | Performances réseau maximales (ex: streaming) | Partage le réseau de la machine hôte |
| None | Tâches de traitement sécurisées hors ligne | Isolation totale (pas de réseau) |
1. Bridge (Le réseau par défaut)
C'est le réseau créé automatiquement quand vous lancez docker compose up. Il agit comme un switch virtuel privé à l'intérieur de votre machine.
- Avantage : Vos conteneurs peuvent communiquer entre eux via leurs noms de service (ex:
pythonpeut joindredatabase), tout en restant isolés du reste de votre machine sauf si vous exposez des ports (ports:).
2. Overlay (Le réseau distribué)
Il est utilisé quand votre application tourne sur plusieurs serveurs différents (généralement via Docker Swarm).
- Avantage : Il crée un tunnel sécurisé entre plusieurs machines physiques.
3. Host (La performance avant tout)
Le conteneur n'est plus isolé sur le plan réseau : il utilise directement l'adresse IP et les ports de la machine hôte.
- Avantage : Supprime la latence liée à l'isolation réseau de Docker.
4. None (La chambre forte)
Le conteneur est complètement déconnecté de tout réseau (aucun accès à Internet ni aux autres conteneurs).
- Avantage : Parfait pour exécuter des scripts hautement sensibles ou isolés en toute sécurité.
Le Docker Compose final sécurisé
Ce qui va nous intéresser ici, c'est d'utiliser le réseau Bridge pour isoler nos flux :
- Notre backend Python doit communiquer avec la base de données MySQL (
backend_network). - phpMyAdmin doit communiquer avec la base de données MySQL (
database_network). - phpMyAdmin n'a jamais besoin de communiquer avec l'application Python.
En créant deux réseaux distincts, nous cloisonnons les accès !
services:
python:
image: kernellab/fastapi_docker:latest
depends_on:
- database
networks:
- backend_network
env_file:
- .env
ports:
- 8000:8000
database:
image: mysql:8.0
networks:
- database_network
- backend_network
environment:
- MYSQL_ROOT_PASSWORD=${DB_ROOT_PASSWORD:-root}
- MYSQL_DATABASE=${DB_DATABASE:-fastapi_docker}
- MYSQL_USER=${DB_USER:-fastapi_user}
- MYSQL_PASSWORD=${DB_PASSWORD:-fastapi_password}
ports:
- 3306:3306
volumes:
- database:/var/lib/mysql
phpmyadmin:
image: phpmyadmin
depends_on:
- database
restart: always
networks:
- database_network
ports:
- 8080:80
environment:
- PMA_ARBITRARY=1
volumes:
database:
networks:
backend_network:
driver: bridge
database_network:
driver: bridge
depends_on: [database] ajoutée sur python et phpmyadmin indique à Docker Compose d'attendre le lancement du service de base de données avant de démarrer les services dépendants. Cela évite les plantages intempestifs si l'application démarre avant que MySQL ne soit initialisé.