« Chez moi, ça marche ! » Cette phrase, Docker l’a rendue obsolète. Dans ce guide Docker pour développeur web, tu montes en 5 minutes un environnement complet PHP 8.4 + Apache + MySQL + phpMyAdmin avec un seul fichier compose.yaml. Chaque ligne est expliquée, pour que tu comprennes ce que tu lances et que tu puisses l’adapter à tous tes projets.

🐳 Docker🐘 PHP 8.4 + Apache🐬 MySQL 8.4🧰 phpMyAdmin⏱️ 5 min d’installation

Tu installes WampServer sur ton PC, ton collègue utilise MAMP sur son Mac, le serveur de production tourne sous Linux… et chacun a une version différente de PHP et de MySQL. Résultat : des bugs qui n’apparaissent que chez l’un ou chez l’autre. Docker pour développeur web, c’est la solution à ce problème : ton environnement est décrit dans un fichier, et il est identique sur toutes les machines.

Docker pour développeur web : Docker pour développeur web : ton environnement PHP + MySQL en 5 minutes
Docker pour développeur web : ton environnement PHP + MySQL en 5 minutes

Dans ce guide, on construit pas à pas un environnement PHP et MySQL complet. Pas besoin de connaître Docker : chaque notion est expliquée au moment où on en a besoin.

Docker pour développeur web : trois conteneurs PHP, MySQL et phpMyAdmin
L’environnement que tu vas créer : trois conteneurs qui communiquent sur un réseau privé.
🎯
Ce que tu vas obtenir
  • Un serveur Apache + PHP 8.4 avec les extensions courantes.
  • Une base de données MySQL 8.4 dont les données survivent aux redémarrages.
  • phpMyAdmin pour gérer ta base depuis le navigateur.
  • Un environnement qui démarre avec une seule commande : docker compose up -d.
  • Un modèle réutilisable pour tous tes projets PHP.

Docker en 2 minutes : les notions essentielles

Avant de taper la moindre commande, voici les quatre mots à connaître :

NotionDéfinition simpleAnalogie
ImageUn modèle figé qui contient un système et des logiciels (par exemple PHP 8.4 + Apache)Une recette de cuisine
ConteneurUne image en cours d’exécution, isolée du reste de ton systèmeLe plat préparé à partir de la recette
VolumeUn espace de stockage qui survit à la suppression du conteneurLe congélateur où tu gardes les restes
Docker ComposeUn fichier qui décrit plusieurs conteneurs et la façon dont ils communiquentLe menu complet du repas
💡
Docker n’est pas une machine virtuelle

Une machine virtuelle embarque un système d’exploitation complet (plusieurs Go, démarrage en minutes). Un conteneur partage le noyau du système hôte et n’embarque que le nécessaire : il démarre en quelques secondes et consomme beaucoup moins de ressources. C’est pour ça qu’on peut lancer trois conteneurs sur un simple ordinateur portable.

Étape 1 : installer Docker

Sous Windows et macOS : Docker Desktop

  1. Télécharge Docker Desktop depuis le site officiel de Docker.
  2. Sous Windows, l’installateur active WSL 2 (le sous-système Linux de Windows) : accepte et redémarre si demandé.
  3. Lance Docker Desktop et attends que l’icône de la baleine indique que Docker est démarré.
⚠️
Licence de Docker Desktop

Docker Desktop est gratuit pour un usage personnel, l’éducation, les projets open source et les petites entreprises (moins de 250 employés et moins de 10 millions de dollars de chiffre d’affaires annuel). Au-delà, un abonnement payant est requis. Docker Engine sous Linux, lui, reste entièrement gratuit.

Sous Linux : Docker Engine

# Script officiel d'installation (Ubuntu, Debian, Fedora…)
curl -fsSL https://get.docker.com | sh

# Utiliser docker sans sudo (déconnecte-toi puis reconnecte-toi ensuite)
sudo usermod -aG docker $USER
Bash

Vérifier l’installation

docker --version
docker compose version
docker run --rm hello-world
Bash

Si le message Hello from Docker! s’affiche, tout fonctionne.

Étape 2 : créer la structure du projet

mon-projet/
├── compose.yaml        ← la description de l'environnement
├── .env                ← les mots de passe (hors de Git)
├── docker/
│   └── php/
│       └── Dockerfile  ← notre image PHP personnalisée
└── src/
    └── index.php       ← ton code PHP
Texte
mkdir -p mon-projet/docker/php mon-projet/src
cd mon-projet
Bash

Étape 3 : l’image PHP personnalisée (Dockerfile)

L’image officielle php:8.4-apache contient PHP et Apache, mais pas l’extension MySQL. On crée donc notre propre image à partir d’elle, avec un Dockerfile :

# docker/php/Dockerfile
FROM php:8.4-apache

# Paquets système nécessaires à certaines extensions
RUN apt-get update && apt-get install -y --no-install-recommends \
        libicu-dev libzip-dev libpng-dev unzip \
    && rm -rf /var/lib/apt/lists/*

# Extensions PHP : MySQL, internationalisation, zip, images
RUN docker-php-ext-install pdo_mysql mysqli intl zip gd opcache

# Configuration de développement (affichage des erreurs)
RUN cp "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini"

# Réécriture d'URL Apache (indispensable pour la plupart des frameworks)
RUN a2enmod rewrite

# Composer, copié depuis son image officielle
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer

WORKDIR /var/www/html
Dockerfile
InstructionRôle
FROML’image de départ (PHP 8.4 avec Apache, sur Debian)
RUNExécute une commande pendant la construction de l’image
docker-php-ext-installScript fourni par l’image officielle pour compiler les extensions PHP
COPY --from=Copie un fichier depuis une autre image (ici, le binaire Composer)
WORKDIRLe dossier courant dans le conteneur
💡
Pourquoi enchaîner les commandes avec && dans un seul RUN ?

Chaque instruction RUN crée une couche dans l’image. En regroupant l’installation et le nettoyage (rm -rf /var/lib/apt/lists/*) dans la même couche, l’image finale est plus légère.

Étape 4 : les mots de passe dans le fichier .env

Docker Compose lit automatiquement un fichier .env placé à côté de compose.yaml. On y met les valeurs sensibles :

# .env
MYSQL_ROOT_PASSWORD=root_motdepasse_local
MYSQL_DATABASE=boutique
MYSQL_USER=app
MYSQL_PASSWORD=app_motdepasse_local
INI

Et on l’exclut de Git :

# .gitignore
.env
Texte

Pense à fournir un fichier .env.example (sans les vrais mots de passe) pour que tes collègues sachent quelles variables définir.

Étape 5 : le fichier compose.yaml

C’est le cœur de l’environnement. Il décrit les trois services et la façon dont ils se connectent :

# compose.yaml
services:
  web:
    build: ./docker/php
    ports:
      - "8080:80"
    volumes:
      - ./src:/var/www/html
    environment:
      DB_HOST: db
      DB_NAME: ${MYSQL_DATABASE}
      DB_USER: ${MYSQL_USER}
      DB_PASSWORD: ${MYSQL_PASSWORD}
    depends_on:
      db:
        condition: service_healthy

  db:
    image: mysql:8.4
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_DATABASE: ${MYSQL_DATABASE}
      MYSQL_USER: ${MYSQL_USER}
      MYSQL_PASSWORD: ${MYSQL_PASSWORD}
    volumes:
      - db_data:/var/lib/mysql
    ports:
      - "127.0.0.1:3307:3306"
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-p${MYSQL_ROOT_PASSWORD}"]
      interval: 5s
      timeout: 5s
      retries: 20

  phpmyadmin:
    image: phpmyadmin:latest
    ports:
      - "8081:80"
    environment:
      PMA_HOST: db
    depends_on:
      - db

volumes:
  db_data:
YAML

Décortiquons les lignes importantes :

LigneExplication
build: ./docker/phpConstruit l’image à partir de notre Dockerfile
ports: "8080:80"Le port 80 du conteneur est accessible sur localhost:8080 de ton ordinateur
volumes: ./src:/var/www/htmlTon dossier src est partagé avec le conteneur : tes modifications sont visibles immédiatement
DB_HOST: dbEntre conteneurs, on se joint par le nom du service : la base s’appelle simplement db
depends_on + service_healthyLe serveur web attend que MySQL soit réellement prêt avant de démarrer
db_data:/var/lib/mysqlUn volume nommé : tes données MySQL survivent à l’arrêt et à la suppression des conteneurs
127.0.0.1:3307:3306MySQL est joignable depuis ton poste (port 3307), mais pas depuis le réseau local
healthcheckDocker vérifie toutes les 5 secondes que MySQL répond
🛡️
Pourquoi 127.0.0.1 devant le port MySQL ?

Sans cette précision, Docker publie le port sur toutes les interfaces réseau : n’importe qui sur ton Wi-Fi pourrait tenter de se connecter à ta base. En le limitant à 127.0.0.1, seul ton ordinateur y a accès. On utilise aussi le port 3307 pour ne pas entrer en conflit avec un MySQL déjà installé sur ton poste.

Étape 6 : un fichier PHP de test

<?php
// src/index.php
declare(strict_types=1);

$dsn = sprintf('mysql:host=%s;dbname=%s;charset=utf8mb4', getenv('DB_HOST'), getenv('DB_NAME'));

try {
    $pdo = new PDO($dsn, getenv('DB_USER'), getenv('DB_PASSWORD'), [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    ]);

    $pdo->exec('CREATE TABLE IF NOT EXISTS visites (
        id INT AUTO_INCREMENT PRIMARY KEY,
        vue_le DATETIME DEFAULT CURRENT_TIMESTAMP
    )');
    $pdo->exec('INSERT INTO visites () VALUES ()');
    $total = $pdo->query('SELECT COUNT(*) FROM visites')->fetchColumn();
    $mysql = $pdo->query('SELECT VERSION()')->fetchColumn();

    echo '<h1>Docker fonctionne 🐳</h1>';
    echo '<p>PHP ' . PHP_VERSION . ' · MySQL ' . htmlspecialchars($mysql) . '</p>';
    echo '<p>Cette page a été vue ' . (int) $total . ' fois.</p>';
} catch (PDOException $e) {
    http_response_code(500);
    echo 'Connexion impossible : ' . htmlspecialchars($e->getMessage());
}
PHP

On lit les identifiants avec getenv() : ils viennent des variables environment du compose.yaml, elles-mêmes alimentées par le .env. Aucun mot de passe n’est écrit dans le code.

Étape 7 : lancer l’environnement

docker compose up -d --build
Bash
  • up crée et démarre les conteneurs ;
  • -d (detached) les lance en arrière-plan ;
  • --build construit notre image PHP (seulement nécessaire la première fois ou après une modification du Dockerfile).

La première exécution télécharge les images (quelques minutes selon ta connexion). Ensuite, le démarrage prend quelques secondes. Vérifie que tout tourne :

docker compose ps
Bash

Ouvre ensuite :

AdresseService
http://localhost:8080Ton application PHP
http://localhost:8081phpMyAdmin (utilisateur app et son mot de passe)
localhost:3307MySQL depuis un client comme DBeaver ou HeidiSQL

Recharge la page de l’application : le compteur de visites augmente. Tes données sont bien enregistrées dans MySQL.

Les commandes Docker du quotidien

CommandeEffet
docker compose up -dDémarre l’environnement
docker compose stopArrête les conteneurs (sans les supprimer)
docker compose downArrête et supprime les conteneurs (les volumes sont conservés)
docker compose down -vSupprime aussi les volumes : ⚠️ ta base de données est effacée
docker compose logs -f webAffiche les journaux du service web en continu
docker compose exec web bashOuvre un terminal dans le conteneur PHP
docker compose exec web composer installLance Composer dans le conteneur
docker compose exec db mysql -u app -p boutiqueOuvre la console MySQL
docker compose build --no-cacheReconstruit l’image depuis zéro
✅
Composer sans rien installer sur ton poste

Grâce à la ligne COPY --from=composer:2 du Dockerfile, Composer est disponible dans le conteneur. docker compose exec web composer require vlucas/phpdotenv installe la librairie dans src/vendor/, sans que PHP ni Composer soient installés sur ta machine.

Sauvegarder et restaurer la base de données

# Sauvegarde : crée un fichier SQL sur ton poste
docker compose exec db sh -c 'mysqldump -u root -p"$MYSQL_ROOT_PASSWORD" "$MYSQL_DATABASE"' > sauvegarde.sql

# Restauration
docker compose exec -T db sh -c 'mysql -u root -p"$MYSQL_ROOT_PASSWORD" "$MYSQL_DATABASE"' < sauvegarde.sql
Bash

Les variables $MYSQL_ROOT_PASSWORD et $MYSQL_DATABASE sont lues dans le conteneur (les guillemets simples empêchent ton terminal de les interpréter), donc le mot de passe n’apparaît pas dans ton historique de commandes.

Astuce : tout fichier .sql placé dans le dossier /docker-entrypoint-initdb.d du conteneur MySQL est exécuté automatiquement à la première création de la base. Ajoute la ligne - ./docker/mysql:/docker-entrypoint-initdb.d dans les volumes du service db pour créer tes tables et tes données de test automatiquement.

Adapter l’environnement à ton projet

Le modèle est facile à faire évoluer :

  • Changer de version de PHP : remplace php:8.4-apache par php:8.3-apache dans le Dockerfile, puis docker compose up -d --build. Tu peux tester ton projet sur une nouvelle version de PHP en une minute, sans rien désinstaller.
  • Utiliser MariaDB : remplace mysql:8.4 par mariadb:11 (les variables sont les mêmes, préfixées MARIADB_ dans les versions récentes ; les anciennes MYSQL_ restent acceptées).
  • Framework avec dossier public (Laravel, Symfony) : change la racine d’Apache dans le Dockerfile :
ENV APACHE_DOCUMENT_ROOT=/var/www/html/public
RUN sed -ri -e 's!/var/www/html!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/sites-available/*.conf
Dockerfile
  • Capturer les e-mails : ajoute un service Mailpit pour voir tous les e-mails envoyés par ton application, sans qu’ils partent réellement.
  mailpit:
    image: axllent/mailpit
    ports:
      - "8025:8025"   # interface web
YAML
💡
Et pour WordPress ?

Le principe est exactement le même, avec l’image officielle wordpress. Notre guide WordPress en local avec Docker te donne le fichier compose complet.

Docker pour développeur web : les bonnes pratiques

Quelques règles qui distinguent un environnement Docker bricolé d’un environnement professionnel :

  • Épingle les versions des images. mysql:8.4 plutôt que mysql:latest : sinon, une mise à jour de l’image peut changer ta version de MySQL du jour au lendemain, sans prévenir.
  • Un service par conteneur. PHP dans un conteneur, MySQL dans un autre, Mailpit dans un troisième. C’est ce qui permet de les mettre à jour, de les redémarrer et de les remplacer indépendamment.
  • Les données dans des volumes nommés. Tout ce qui doit survivre (bases de données, fichiers envoyés par les utilisateurs) va dans un volume. Le conteneur, lui, doit pouvoir être supprimé et recréé à tout moment.
  • Aucun secret dans les images. Les mots de passe passent par le fichier .env ou par les secrets de Docker, jamais par une ligne ENV du Dockerfile : ils seraient visibles par toute personne qui récupère l’image.
  • Des images légères. Supprime les caches des gestionnaires de paquets dans la même instruction RUN, et ajoute un fichier .dockerignore pour ne pas copier node_modules, .git ou les fichiers de logs dans l’image.
  • Nettoie régulièrement. Les images et volumes inutilisés s’accumulent vite. docker system df montre l’espace occupé et docker system prune supprime ce qui ne sert plus (lis bien l’avertissement avant de valider).
# .dockerignore
.git
.env
node_modules
vendor
*.log
Texte

Dépannage

ProblèmeCauseSolution
port is already allocatedLe port 8080 (ou 3307) est déjà utiliséChange le port de gauche : "8090:80"
SQLSTATE[HY000] [2002] Connection refusedMySQL pas encore prêtLe healthcheck et depends_on règlent ce cas ; sinon attends quelques secondes
Access denied for user 'app'Mots de passe modifiés après la première créationLes variables MySQL ne servent qu’à la première initialisation : docker compose down -v puis relance (⚠️ efface la base)
could not find driverExtension pdo_mysql absenteVérifie le Dockerfile et relance avec --build
Très lent sous WindowsProjet stocké sur le disque WindowsPlace ton projet dans le système de fichiers WSL (\\wsl$\Ubuntu\home\…)
Fichiers créés par le conteneur non modifiables (Linux)Le conteneur écrit en tant que www-data ou rootAjuste les droits ou configure l’utilisateur du conteneur

Docker en développement, et en production ?

Cet environnement est conçu pour le développement : erreurs affichées, code partagé en direct, phpMyAdmin exposé. Pour la production, on construit une image différente : php.ini-production, code copié dans l’image (pas partagé), pas de phpMyAdmin, mots de passe gérés par des secrets, et souvent PHP-FPM derrière Nginx. Mais la logique reste la même, et c’est tout l’intérêt de Docker : ce que tu testes sur ton poste ressemble enfin à ce qui tourne en ligne.

Docker pour développeur web : les points essentiels à retenir
Les points essentiels à retenir de ce guide.

FAQ

Docker remplace-t-il WampServer ou XAMPP ?

Oui, pour le développement. L’avantage : chaque projet a sa propre version de PHP et de MySQL, isolée des autres, et l’environnement est décrit dans un fichier partageable avec ton équipe. Si tu préfères une installation sans Docker, notre guide pour installer PHP 8.4 et Composer sous Windows est une excellente alternative.

Mes données MySQL sont-elles perdues quand j’arrête Docker ?

Non. Elles sont stockées dans le volume db_data, qui survit à docker compose stop et docker compose down. Seul docker compose down -v supprime les volumes.

Docker est-il gourmand en ressources ?

Beaucoup moins qu’une machine virtuelle. Cet environnement consomme quelques centaines de Mo de mémoire. Sous Windows, tu peux limiter la mémoire allouée à WSL 2 avec un fichier .wslconfig.

Faut-il commiter compose.yaml et le Dockerfile ?

Oui, absolument : ils font partie du projet et permettent à n’importe qui de le lancer avec docker compose up. Seul le fichier .env (qui contient les mots de passe) reste en dehors de Git.

Conclusion

Avec trois fichiers (Dockerfile, compose.yaml et .env), tu disposes d’un environnement de développement PHP et MySQL complet, reproductible et isolé. Docker pour développeur web, c’est la fin des « chez moi ça marche » : n’importe qui clone ton projet, tape docker compose up -d et obtient exactement le même environnement que toi.

Garde ce modèle sous la main : il te servira de base pour tous tes futurs projets. Pour versionner ces fichiers et les partager, notre guide Git et GitHub pour débutant t’explique comment. Et la documentation officielle de Docker Compose détaille toutes les options disponibles.

Comments

No comments yet. Why don’t you start the discussion?

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *