Docker pour PrestaShop : environnement de développement
Docker pour le développement PrestaShop : tests multi-versions, workflow modules, gestion de base de données, Xdebug et production.
Pourquoi nous faisons tourner chaque PrestaShop sous Docker
Chez mypresta.rocks, toute notre infrastructure de développement et de préproduction repose sur Docker, un seul hôte TrueNAS, des conteneurs dédiés comme ps176-dev, ps178-dev, ps8-dev et ps9-dev, un ps-redis partagé, et Nginx Proxy Manager en frontal. Nous avons commis chacune des erreurs décrites sur cette page au moins une fois.
Le problème : PS 1.7 réclame PHP 7.1, PS 8.x veut 8.1, PS 9.x exige 8.3 ou plus. MySQL 5.7 contre 8.0 change le plugin d'authentification. Installer tout cela en natif, c'est la garantie de passer un samedi entier à résoudre des incidents au lieu d'écrire des modules. Chaque conteneur embarque exactement l'environnement d'exécution que son PrestaShop attend.
- Tests multi-versions. PS 1.7, 8.x et 9.x en même temps. Un audit de module devient l'affaire d'un après-midi, pas d'une semaine à reconstruire des stacks LAMP.
- Isolation. Chaque boutique a son propre PHP, sa propre base MySQL, son propre système de fichiers. Une installation ratée ne peut pas contaminer une autre.
- Reproductibilité. Tout est dans
docker-compose.yml. Ordinateur portable, préproduction, machine d'un collègue, la même configuration partout. - Nettoyage facile.
docker compose down -vet tout disparaît.
Nous faisons tourner des conteneurs PrestaShop distincts, de la version 1.6 à la 9.1, sur une seule machine TrueNAS. Les schémas présentés ci-dessous sont ce que nous avons conservé après une décennie d'affinage.
Prérequis
Installer Docker
Ubuntu/Debian : curl -fsSL https://get.docker.com | sh, puis sudo usermod -aG docker $USER. macOS : Docker Desktop : basculez l'implémentation de partage de fichiers sur VirtioFS dans les réglages. Windows : WSL2 d'abord, puis Docker Desktop avec le backend WSL2. Le mode Hyper-V est plus lent ; nous l'éviterions.
Les quatre notions qui comptent
- Image : modèle en lecture seule. L'image officielle est
prestashop/prestashopsur Docker Hub. - Conteneur : une instance en cours d'exécution. Plusieurs à partir d'une même image, c'est ainsi que fonctionnent les configurations multi-versions.
- Volume : stockage persistant. Pas de volume, pas de données une fois le conteneur supprimé. Nous avons perdu des données de test en l'oubliant.
- Réseau : réseau virtuel permettant aux conteneurs de communiquer entre eux (PrestaShop ↔ MySQL).
Matériel
Prévoyez 1,5 à 2 Go de RAM par instance PrestaShop. 16 Go suffisent confortablement sur un ordinateur portable de développeur pour 2 à 3 versions. Notre machine de développement dispose de 64 Go et d'un disque NVMe, car nous faisons tourner plusieurs conteneurs versionnés en parallèle. Les disques mécaniques vous feront détester Docker, n'essayez même pas.
Configuration à conteneur unique
Déposez ceci dans un fichier docker-compose.yml :
version: '3.8'
services:
prestashop:
image: prestashop/prestashop:8.2
container_name: <your-shop>
ports:
- "8080:80"
environment:
- DB_SERVER=db
- DB_USER=prestashop
- DB_PASSWD=prestashop_password
- DB_NAME=prestashop
- PS_DOMAIN=localhost:8080
- PS_FOLDER_ADMIN=admin-dev
- PS_FOLDER_INSTALL=disabled
- ADMIN_MAIL=admin@yourshop.com
- ADMIN_PASSWD=admin_password_123
volumes:
- shop-data:/var/www/html
depends_on:
- db
db:
image: mysql:8.0
container_name: <your-shop>-db
environment:
- MYSQL_ROOT_PASSWORD=root_password
- MYSQL_DATABASE=prestashop
- MYSQL_USER=prestashop
- MYSQL_PASSWORD=prestashop_password
volumes:
- shop-db-data:/var/lib/mysql
volumes:
shop-data:
shop-db-data:
DB_SERVER doit correspondre exactement au nom du service (db), c'est la cause la plus fréquente d'échec d'un compose tout neuf. PS_FOLDER_INSTALL=disabled empêche l'installateur de se relancer à chaque redémarrage. docker compose up -d, puis surveillez avec docker compose logs -f prestashop ; comptez 1 à 2 minutes au premier lancement.
La boutique est sur http://localhost:8080, le Back Office sur http://localhost:8080/admin-dev.
Utilisez toujours des volumes nommés pour la base de données. Sans cela, la suppression du conteneur détruit chaque produit, chaque commande et chaque client. Nous avons perdu une demi-journée de données de test en l'oubliant sur un conteneur jetable monté « vite fait ».
Tests multi-versions
C'est le cas d'usage pour lequel Docker a été conçu. Trois versions de PrestaShop côte à côte, chacune sur son propre port et sa propre base de données :
version: '3.8'
services:
ps176-dev:
image: prestashop/prestashop:1.7.6
container_name: ps176-dev
ports: ["8076:80"]
environment:
- DB_SERVER=<your-db-176>
- PS_DOMAIN=localhost:8076
# ... même schéma que ci-dessus
volumes:
- ps176-data:/var/www/html
networks: [ps-network]
<your-db-176>:
image: mysql:5.7
volumes: [your-db-176-data:/var/lib/mysql]
networks: [ps-network]
ps8-dev:
image: prestashop/prestashop:8.2
container_name: ps8-dev
ports: ["8082:80"]
environment:
- DB_SERVER=<your-db-8>
- PS_DOMAIN=localhost:8082
volumes:
- ps8-data:/var/www/html
networks: [ps-network]
<your-db-8>:
image: mysql:8.0
command: --default-authentication-plugin=mysql_native_password
volumes: [your-db-8-data:/var/lib/mysql]
networks: [ps-network]
ps9-dev:
image: prestashop/prestashop:9.0
container_name: ps9-dev
ports: ["8083:80"]
environment:
- DB_SERVER=<your-db-9>
- PS_DOMAIN=localhost:8083
volumes:
- ps9-data:/var/www/html
networks: [ps-network]
<your-db-9>:
image: mysql:8.0
command: --default-authentication-plugin=mysql_native_password
volumes: [your-db-9-data:/var/lib/mysql]
networks: [ps-network]
networks:
ps-network:
driver: bridge
Choisissez un plan de ports. Le nôtre est 8178 pour PS 1.7.8, 8082 pour 8.2, 8090 pour 9.0. Passé une dizaine de conteneurs, les numéros de port cessent d'être mémorisables ; c'est à ce moment-là que nous avons placé Nginx Proxy Manager en frontal et attribué à chaque boutique un nom d'hôte comme ps8-dev.mypresta.rocks. Faites-le dès le premier jour si vous comptez dépasser une poignée de conteneurs.
Séparez toujours les bases de données. Le schéma diverge entre versions majeures ; les migrations se corrompraient mutuellement.
Avertissement : docker network connect / disconnect sur un conteneur en cours d'exécution réécrit le mappage de ports. Nous avons vu cette commande tuer silencieusement le port 443 de notre conteneur NPM, faisant tomber tous les sites d'un coup. Définissez le réseau dans le compose et recréez le conteneur s'il faut le modifier.
Flux de développement de modules
Montez votre répertoire de module en bind-mount. Chaque modification est immédiatement active. C'est le plus grand atout que Docker apporte au travail sur les modules :
volumes:
- ps8-data:/var/www/html
- /home/user/modules/my_module:/var/www/html/modules/my_module
Pour les tests multi-versions, montez le même répertoire hôte dans chaque conteneur. Modifiez un seul fichier, actualisez trois onglets. Nous montons chaque ~/modules/mpr* dans tous les conteneurs ps178-dev, ps8-dev et ps9-dev précisément pour cela.
Permissions : le piège récurrent
Les fichiers de l'hôte vous appartiennent (UID 1000) ; Apache s'exécute sous www-data (UID 33). PrestaShop tente d'écrire dans var/cache, img et modules, et l'accès lui est refusé, c'est pourquoi les envois de modules échouent sur les installations toutes neuves.
# Session MySQL interactive
docker exec -it <your-shop>-db mysql -u root -p'root' prestashop
# Exécuter une seule requête
docker exec <your-shop>-db mysql -u root -p'root' -e "SELECT COUNT(*) FROM ps_product;" prestashop
Gardez un script fix-container-perms.sh sous la main. Nous lançons le nôtre plus souvent que nous le voudrions, surtout après avoir synchronisé des modules par rsync.
Cache
docker exec ps8-dev rm -rf /var/www/html/var/cache/*
Ou désactivez le cache des templates dans Paramètres avancés → Performances pendant que vous travaillez activement. Réactivez-le avant de considérer le travail terminé, les bugs liés au cache n'apparaissent qu'avec le cache activé. Si la production utilise Redis, ajoutez le même service en local ; Redis Dashboard & Key Manager est utile lorsque vous voulez que le câblage du cache côté PrestaShop corresponde à la production plutôt que de le simuler avec un cache sur le système de fichiers.
Gestion des bases de données
Gardez les bases de test suffisamment petites pour être faciles à déplacer. Avant d'exporter une boutique en production vers Docker, purgez les paniers obsolètes, les journaux et les données temporaires avec Database Cleanup ou une passe de nettoyage SQL équivalente, puis réalisez le dump.
phpmyadmin:
image: phpmyadmin:latest
ports: ["9090:80"]
environment:
- PMA_HOSTS=<your-db-176>,<your-db-8>,<your-db-9>
- PMA_USER=root
- PMA_PASSWORD=root
networks: [ps-network]
phpMyAdmin
Un seul conteneur dessert chaque base de données du réseau :
# Export
docker exec <your-shop>-db mysqldump -u root -p'root' prestashop > backup.sql
# Import
docker exec -i <your-shop>-db mysql -u root -p'root' prestashop < backup.sql
Import et export
mailpit:
image: axllent/mailpit
ports:
- "8025:8025" # Interface web
- "1025:1025" # SMTP
networks: [ps-network]
Deux pièges en production : passez par gunzip pour les dumps compressés, et passez toujours SET NAMES utf8mb4 au début de toute restauration via docker exec, sinon les noms de produits en UTF-8 arrivent doublement encodés et la correction est plus laborieuse que la prévention.
Persistant ou éphémère
Persistant (volumes nommés) : tout ce que vous seriez désolé de perdre. Éphémère : les tests d'installation. Nous gardons un conteneur PS 9.0 éphémère pour la question « ce module s'installe-t-il proprement sur une boutique vierge ? », recréé à chaque exécution.
Test des e-mails avec Mailpit
Mailpit capture chaque e-mail sortant et l'affiche dans une interface web :
FROM prestashop/prestashop:8.2
RUN pecl install xdebug && docker-php-ext-enable xdebug
COPY xdebug.ini /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
Back Office → Paramètres avancés → E-mail : SMTP mailpit, port 1025, sans chiffrement, sans authentification. Les e-mails capturés sont sur http://localhost:8025. Un seul Mailpit partagé dessert chaque boutique de développement de notre réseau.
Débogage avec Xdebug
L'image officielle ne fournit pas Xdebug. Construisez un fin wrapper :
[xdebug]
xdebug.mode=debug
xdebug.start_with_request=yes
xdebug.client_host=host.docker.internal
xdebug.client_port=9003
xdebug.idekey=VSCODE
{
"version": "0.2.0",
"configurations": [{
"name": "Listen for Xdebug (Docker)",
"type": "php",
"request": "launch",
"port": 9003,
"pathMappings": {
"/var/www/html/modules/my_module": "${workspaceFolder}"
}
}]
}
Sous Linux, host.docker.internal n'existe pas par défaut, ajoutez extra_hosts: ["host.docker.internal:host-gateway"]. Nous avons perdu une demi-heure à cause de ce détail.
VS Code
Installez PHP Debug et ajoutez à .vscode/launch.json :
docker exec <your-shop> chown -R www-data:www-data /var/www/html/var
docker exec <your-shop> chown -R www-data:www-data /var/www/html/img
docker exec <your-shop> chown -R www-data:www-data /var/www/html/modules
pathMappings est ce qui déclenche le point d'arrêt. Sans lui, VS Code ne fait silencieusement rien.
PHPStorm
Paramètres → PHP → Serveurs : localhost + port du conteneur, mappez /var/www/html vers le projet. Port Xdebug 9003 sous PHP → Debug, « Démarrer l'écoute ».
Commandes utiles
| Tâche | Commande |
|---|---|
| Démarrer tous les conteneurs | docker compose up -d |
| Arrêter tous les conteneurs | docker compose down |
| Arrêter et supprimer toutes les données | docker compose down -v |
| Consulter les journaux | docker compose logs -f |
| Vider le cache PS | docker exec CONTAINER rm -rf /var/www/html/var/cache/* |
| CLI MySQL | docker exec -it CONTAINER-db mysql -u root -p'PASS' prestashop |
| Exporter la base de données | docker exec CONTAINER-db mysqldump -u root -p'PASS' prestashop > backup.sql |
| Importer la base de données | docker exec -i CONTAINER-db mysql -u root -p'PASS' prestashop < backup.sql |
| Ouvrir un shell dans le conteneur | docker exec -it CONTAINER bash |
| Vérifier l'utilisation des ressources | docker stats --no-stream |
| Reconstruire après modification du Dockerfile | docker compose up -d --build |
| Lancer la console PrestaShop | docker exec CONTAINER php bin/console cache:clear --env=prod |
| Lancer Composer dans un module | docker exec -w /var/www/html/modules/my_module CONTAINER composer install |
Production : notre avis honnête
Pour la plupart des marchands, Docker est un outil de développement. La production tourne généralement mieux sur un hébergement traditionnel. Une stack LAMP unique est plus simple à superviser et à transmettre, les entrées/sorties fichier natives surpassent les volumes Docker (PrestaShop charge des milliers de fichiers PHP par requête), et la plupart des hébergeurs adaptés à PrestaShop vous donnent cPanel, pas un démon Docker.
Docker en production justifie son intérêt avec le CI/CD, les pics de capacité lors d'événements commerciaux, dix boutiques ou plus, ou les déploiements sans interruption de service.
Compose contre Kubernetes contre Swarm. Compose gère 20 à 30 conteneurs sur un seul hôte, c'est ce que nous utilisons, et c'est largement suffisant. Kubernetes ajoute la mise à l'échelle automatique et l'orchestration multi-nœuds, au prix d'une véritable équipe d'infrastructure ; pour PrestaShop, nous n'avons pas encore vu de cas où c'était le bon choix. Docker Swarm est un entre-deux maladroit que nous écarterions. La communauté est passée à autre chose. Et kompose (l'outil de « conversion de compose vers k8s ») semble formidable jusqu'à ce que vous l'essayiez et constatiez que le résultat demande autant de retouches manuelles que de l'écrire à neuf.
Deux réglages d'hôte qui valent le coup
live-restore: truedans/etc/docker/daemon.json. Les redémarrages du démon cessent de tuer les conteneurs en cours d'exécution.data-rootpersonnalisé sur un pool SSD rapide, pas sur le disque système. Les images et les volumes MySQL grossissent ; les disques système se remplissent en silence.
Ce qui peut mal tourner
« Impossible de se connecter à la base de données »
DB_SERVERne correspond pas au nom du service MySQL (identique, tirets compris).- MySQL n'a pas fini de démarrer. Utilisez un healthcheck et
depends_on: condition: service_healthy. - Les conteneurs sont sur des réseaux différents, placez-les tous les deux sur un même bridge nommé.
- MySQL 8.0 utilise par défaut
caching_sha2_password; le mysqli de PrestaShop a besoin demysql_native_password. Ajoutezcommand: --default-authentication-plugin=mysql_native_password.
Entrées/sorties lentes sous macOS
Les bind-mounts sous macOS étaient autrefois d'une lenteur glaciale (10 à 30 s par chargement de page). Trois remèdes : VirtioFS dans les réglages de Docker Desktop (le gain le plus important), monter moins (seulement le répertoire du module, le reste sur un volume nommé), Mutagen (synchronisation de fichiers bidirectionnelle qui contourne la couche de montage, solution radicale, mais qui fonctionne).
SSL en développement
Les modules de paiement et la connexion via les réseaux sociaux refusent le HTTP en clair. Nginx Proxy Manager termine le SSL pour chaque conteneur, c'est ce que nous utilisons, l'option la plus propre. mkcert pour des certificats approuvés localement. Traefik pour la découverte et le provisionnement automatiques.
MySQL qui dévore toute votre RAM
command: >
--innodb-buffer-pool-size=128M
--max-connections=50
Sur Docker Desktop, augmentez la limite de mémoire dans Paramètres → Ressources à au moins 6 Go une fois que vous avez plusieurs conteneurs. Arrêtez ceux que vous n'utilisez pas : docker stop ps178-dev.
Boucles de réinstallation
Si PrestaShop se réinstalle à chaque redémarrage, c'est que le volume /var/www/html ne persiste pas, ou que PS_FOLDER_INSTALL=disabled n'est pas pris en compte. Vérifiez que docker volume ls affiche un vrai volume (et non un volume anonyme).
Contenu mixte après un changement de port
docker exec <your-shop>-db mysql -u root -p'root' -e "
UPDATE ps_configuration SET value='localhost:8080'
WHERE name IN ('PS_SHOP_DOMAIN','PS_SHOP_DOMAIN_SSL');
UPDATE ps_shop_url SET domain='localhost:8080', domain_ssl='localhost:8080';
" prestashop
Un avertissement : n'exécutez jamais cette requête sur la boutique d'un client en production sans sauvegarde. Nous l'avons vue rendre inutilisable un frontend de production en plein après-midi.
À lire également
- Développement local PrestaShop : configuration avec XAMPP, WAMP, Docker et Linux : Docker face aux alternatives
- Outils indispensables pour le développement PrestaShop : ce que nous gardons aux côtés de Docker
- Comment créer un site de préproduction PrestaShop : étendre ces schémas à la préproduction
- Guide de résolution des incidents : quand le conteneur tourne mais que la boutique se comporte mal
- Optimisation des performances et Performance Revolution : l'étape suivante après « ça marche »
- Le dépôt Docker officiel de PrestaShop