Docker et PHP, c'est une histoire d'amour compliquée. Des Dockerfiles de 200 lignes, des problèmes de permissions, des performances catastrophiques sur macOS. Si tu as déjà perdu une demi-journée à debugger un container PHP-FPM, cet article est pour toi. On va monter un setup complet et testé pour le développement Symfony.
Le docker-compose.yml complet
Voici le fichier docker-compose qui fonctionne en production chez nos clients. Il couvre les quatre services essentiels : PostgreSQL, Redis, PHP-FPM et Nginx.
version: '3.8'
services:
php:
build:
context: .
dockerfile: docker/php/Dockerfile
target: dev
volumes:
- .:/app:cached
- php_socket:/var/run/php
environment:
APP_ENV: dev
DATABASE_URL: postgresql://app:secret@postgres:5432/app
REDIS_URL: redis://redis:6379
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
nginx:
image: nginx:1.25-alpine
ports:
- "8080:80"
volumes:
- ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
- ./public:/app/public:ro
- php_socket:/var/run/php
depends_on:
- php
postgres:
image: postgres:16-alpine
environment:
POSTGRES_DB: app
POSTGRES_USER: app
POSTGRES_PASSWORD: secret
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U app"]
interval: 10s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
- redis_data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
volumes:
postgres_data:
redis_data:
php_socket:Le Dockerfile multi-stage : dev vs prod
Un seul Dockerfile avec deux targets. Le stage dev inclut Xdebug et Composer. Le stage prod est optimisé pour la performance avec OPcache.
# docker/php/Dockerfile
FROM php:8.3-fpm-alpine AS base
RUN apk add --no-cache \
icu-dev \
libpq-dev \
linux-headers \
&& docker-php-ext-install \
intl \
pdo_pgsql \
opcache
RUN apk add --no-cache libzip-dev \
&& docker-php-ext-install zip
WORKDIR /app
# ── Stage dev ──
FROM base AS dev
RUN apk add --no-cache $PHPIZE_DEPS \
&& pecl install xdebug redis \
&& docker-php-ext-enable xdebug redis
COPY docker/php/conf.d/xdebug.ini /usr/local/etc/php/conf.d/xdebug.ini
COPY docker/php/conf.d/php-dev.ini /usr/local/etc/php/conf.d/php.ini
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
# ── Stage prod ──
FROM base AS prod
RUN apk add --no-cache $PHPIZE_DEPS \
&& pecl install redis \
&& docker-php-ext-enable redis \
&& apk del $PHPIZE_DEPS
COPY docker/php/conf.d/php-prod.ini /usr/local/etc/php/conf.d/php.ini
COPY composer.json composer.lock ./
RUN composer install --no-dev --optimize-autoloader --no-scripts
COPY . .
RUN composer dump-autoload --optimize --classmap-authoritativeLa configuration Nginx pour PHP-FPM
# docker/nginx/default.conf
server {
listen 80;
server_name localhost;
root /app/public;
location / {
try_files $uri /index.php$is_args$args;
}
location ~ ^/index\.php(/|$) {
fastcgi_pass unix:/var/run/php/php-fpm.sock;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $realpath_root;
internal;
}
location ~ \.php$ {
return 404;
}
}Les pièges courants et leurs solutions
Envie d'aller plus loin ?
Discutons de votre projet et voyons comment je peux vous aider.
Après avoir mis en place Docker sur des dizaines de projets Symfony, voici les trois problèmes les plus fréquents.
1. Permissions fichiers — Le classique : les fichiers créés par le container appartiennent à root. La solution : ajouter un utilisateur non-root dans le Dockerfile avec le même UID que ton utilisateur local. ARG UID=1000 puis RUN adduser -D -u $UID appuser.
2. Performance sur macOS — Les volumes montés sont lents sur macOS à cause de la couche de virtualisation. Deux solutions : utiliser le flag :cached sur les volumes (déjà dans notre compose) ou exclure vendor/ du montage et l'installer directement dans le container.
3. Configuration Xdebug — Xdebug doit contacter ton IDE, pas l'inverse. La configuration critique :
; docker/php/conf.d/xdebug.ini
[xdebug]
xdebug.mode=debug
xdebug.client_host=host.docker.internal
xdebug.client_port=9003
xdebug.start_with_request=trigger
xdebug.idekey=PHPSTORMLes commandes du quotidien
# Démarrer l'environnement
docker compose up -d
# Exécuter les commandes Symfony
docker compose exec php bin/console cache:clear
docker compose exec php bin/console doctrine:migrations:migrate
# Lancer les tests
docker compose exec php vendor/bin/phpunit
# Lancer PHPStan
docker compose exec php vendor/bin/phpstan analyse --level=max
# Installer les dépendances
docker compose exec php composer install
# Arrêter et nettoyer
docker compose down -vCe setup couvre 90 % des besoins d'un projet Symfony. Pour les cas plus avancés — Elasticsearch, RabbitMQ, workers Messenger — il suffit d'ajouter les services dans le compose. Si tu cherches un accompagnement complet, notre offre Bear MVP inclut la configuration Docker dans chaque livraison de MVP.

Écrit par
Flavien Métivier
Expert PHP/Symfony indépendant depuis 2014, ancien CTO de Kartable et d'Extrabat. Plus de 80 projets menés, de l'audit à la migration.
Mon parcours