Symfony Docker
Docker avec les commandes composer, symfony et bin/console
Pour pouvoir exécuter des commandes composer, symfony et bin/console depuis votre machine locale tout en les faisant affecter le conteneur Docker, voici une approche optimale basée sur des volumes montés et des alias pratiques.
1. Montage des volumes pour synchroniser les fichiers
L’idée est de monter votre code local dans le conteneur pour que les modifications soient immédiatement visibles des deux côtés.
Solution 1 : Utilisation de docker-compose.yml (recommandé)
version: '3.8'
services:
app:
build: .
volumes:
- ./:/var/www/html # Monte le projet Symfony (y compris vendor/)
- ~/.composer:/tmp/composer # Cache Composer (optionnel)
working_dir: /var/www/html
ports:
- "8000:8000" # Symfony CLI ou PHP-FPM
tty: true
stdin_open: true
Explications :
./:/var/www/html: Synchronise le code local avec le conteneur (y comprisvendor/).~/.composer:/tmp/composer: Cache Composer pour éviter de retélécharger les dépendances.working_dir: S’assure que les commandes s’exécutent dans/var/www/html.
2. Exécuter des commandes dans le conteneur depuis l’hôte
Méthode 1 : docker-compose exec (pour les commandes ponctuelles)
# Commande Composer (ex: ajouter un bundle)
docker-compose exec app composer require mon/bundle-local
# Commande Symfony CLI (ex: lancer le serveur)
docker-compose exec app symfony serve -d
# Commande Console (ex: migrer la base)
docker-compose exec app php bin/console make:migration
Méthode 2 : Alias shell pour simplifier (dans ~/.bashrc ou ~/.zshrc)
# Alias pour Composer
alias dc-composer="docker-compose exec app composer"
# Alias pour Symfony CLI
alias dc-symfony="docker-compose exec app symfony"
# Alias pour la Console Symfony
alias dc-console="docker-compose exec app php bin/console"
Utilisation :
dc-composer require mon/bundle-local
dc-console make:migration
dc-symfony serve -d
3. Cas particulier : Développement d’un bundle local
Si vous développez un bundle en local et qu’il est lié via composer.json en "type": "path", assurez-vous que :
1. Le chemin est correct dans composer.json :
{
"require": {
"mon/bundle-local": "*",
"symfony/framework-bundle": "^6.0"
},
"repositories": [
{
"type": "path",
"url": "./packages/mon-bundle-local"
}
]
}
2. Le volume est bien monté dans docker-compose.yml :
volumes:
- ./:/var/www/html
- ./packages/mon-bundle-local:/var/www/html/packages/mon-bundle-local
# Si le bundle est dans un sous-dossier
3. Reconstruire l’autoload après modification du bundle :
bash docker-compose exec app composer dump-autoload
4. Optimisation pour le dev : Xdebug + volumes
Si vous utilisez Xdebug ou souhaitez un rechargement automatique :
# docker-compose.yml (extrait)
services:
app:
environment:
XDEBUG_MODE: "develop,debug"
volumes:
- ./:/var/www/html
- ~/.composer:/tmp/composer
Récapitulatif des bonnes pratiques
| Besoin | Solution |
|---|---|
Exécuter composer
|
docker-compose exec app composer require mon/bundle
|
Lancer bin/console
|
docker-compose exec app php bin/console make:migration
|
| Utiliser Symfony CLI | docker-compose exec app symfony serve -d
|
| Développer un bundle local | Monter le dossier du bundle + composer dump-autoload après modification
|
| Optimiser l’expérience dev | Alias shell + volumes montés + Xdebug |
Conclusion
- ✅ Pour les commandes
composer/symfony/console: Utilisezdocker-compose exec. - ✅ Pour le dev de bundles locaux : Montez le dossier et utilisez
composer dump-autoload. - ✅ Pour simplifier les commandes : Créez des alias (
dc-composer,dc-console).
Cette approche permet un développement fluide sans avoir à reconstruire l’image à chaque modification. 🚀
composer dump-autoload
La commande composer dump-autoload est une commande essentielle dans l’écosystème PHP/Composer. Elle régénère le fichier d’autoloading (chargement automatique des classes) sans réinstaller les dépendances. Voici ce qu’elle fait en détail :
À quoi sert composer dump-autoload ?
- Reconstruit l’autoloader de Composer
- Met à jour le fichier
vendor/autoload.phpqui gère le chargement automatique des classes PHP. - Utile quand vous ajoutez/modifiez des classes sans passer par
composer install/update.
- Met à jour le fichier
- Optimise les performances (si utilisé avec
-o)Avec l’option
--optimize(-o), Composer génère une version optimisée de l’autoloader (classe map statique), ce qui accélère le chargement des classes en production :composer dump-autoload --optimize
- Prend en compte les classes dans
autoloadouautoload-devSi vous avez des classes définies dans
composer.jsonsous :"autoload": { "psr-4": { "MonApp\\": "src/" } }
La commande les intègre dans l’autoloader.
Quand l’utiliser ?
| Cas d’usage | Commande recommandée |
|---|---|
| Après avoir ajouté une nouvelle classe manuellement (sans Composer). | composer dump-autoload
|
| En production pour optimiser les performances. | composer dump-autoload --optimize
|
Après avoir modifié composer.json (sans vouloir réinstaller les dépendances).
|
composer dump-autoload
|
| Pour vérifier les espaces de noms (PSR-4). | composer dump-autoload
|
Différence avec composer install et composer update
composer install:
Installe les dépendances ET régénère l’autoloader.
composer update:
Met à jour les dépendances ET régénère l’autoloader.
composer dump-autoload:
Ne touche pas aux dépendances – ne fait que mettre à jour l’autoloader.
Exemple concret dans un projet Symfony
- Vous ajoutez une nouvelle entité
src/Entity/Product.php:Symfony utilise l’autoloading PSR-4, donc la classe sera automatiquement détectée.
Si elle n’est pas reconnue, exécutez :
composer dump-autoload
- Vous développez un bundle local (lié via
"type": "path"danscomposer.json) :Après avoir modifié le bundle, pour que Symfony reconnaisse les nouvelles classes :
composer dump-autoload
Bonnes pratiques
En développement :
Utilisezcomposer dump-autoloadaprès avoir ajouté des classes manuellement.
En production :
Utilisezcomposer dump-autoload --optimizepour des performances optimales.
Avec Docker :
Si vous montez un volume (./:/var/www/html), exécutez la commande dans le conteneur :docker-compose exec app composer dump-autoload
Résumé
composer dump-autoload est un outil léger pour rafraîchir l’autoloader sans toucher aux dépendances. Indispensable pour :
- Le développement de bundles locaux.
- L’ajout manuel de classes.
- L’optimisation en production.
Utilisez-la dès que vous rencontrez des erreurs du type :
> “Class ‘MonApp\Entity\Product’ not found”
🚀 Astuce : Combinez-la avec --optimize en prod pour un boost de performances !
Symfony cache et composer cache avec Docker :
1. Rôle du dossier /var/cache dans Symfony
Symfony utilise ce dossier pour : - Le cache applicatif (ex : compilation des templates Twig, cache des routes, annotations) - Le cache système (ex : fichiers de configuration compilés comme srcApp_KernelDevDebugContainer.php)
Problème avec Docker :
Par défaut, ce cache est régénéré à chaque démarrage du conteneur → ralentissements (surtout en dev).
2. Stratégies pour optimiser le cache avec Docker
A. Monter /var/cache en volume (pour le dev)
# docker-compose.yml
services:
php:
volumes:
- ./var/cache:/var/www/html/var/cache # Monte le cache Symfony
Avantages : - Le cache persiste entre les redémarrages du conteneur. - Meilleures performances en développement.
Inconvénients : - Peut causer des problèmes de permissions (solved avec chmod ou entrypoint.sh).
B. Utiliser un volume Docker nommé (prod + dev)
volumes:
symfony_cache: # Volume dédié pour le cache
services:
php:
volumes:
- symfony_cache:/var/www/html/var/cache
Bonus : Ajoutez un entrypoint.sh pour fixer les permissions :
#!/bin/bash
set -e
# Fixe les permissions du cache
chown -R www-data:www-data /var/www/html/var
exec "$@"
C. Cache warming en production
Dans votre Dockerfile :
FROM composer AS builder
WORKDIR /app
COPY . .
RUN composer install --no-dev --optimize-autoloader
FROM php:8.2-fpm
COPY --from=builder /app /var/www/html
RUN php bin/console cache:warmup # ⚡ Pré-chauffe le cache
3. Gestion des environnements
| Environnement | Recommandation |
|---|---|
| Développement | Volume monté (./var/cache:/...) + chmod
|
| Production | Volume nommé + cache warming dans l’image |
| CI/CD | Cache éphémère (pas de montage) |
4. Exemple complet (docker-compose.yml)
version: '3.8'
volumes:
symfony_cache: # Pour le cache
composer_cache: # Pour Composer
services:
app:
build: .
volumes:
- ./:/var/www/html
- symfony_cache:/var/www/html/var/cache
- composer_cache:/tmp/composer
environment:
APP_ENV: dev
COMPOSER_CACHE_DIR: /tmp/composer
5. Bonnes pratiques
En dev : Montez
var/cachepour éviter de tout recompiler.En prod : Utilisez
cache:warmupdans l’image + volume nommé.Permissions : Résolvez-les via
entrypoint.shoudocker-compose:user: "${UID:-1000}:${GID:-1000}"
Différence avec Composer Cache
Composer (~/.composer)
|
Symfony (/var/cache)
| |
|---|---|---|
| Type | Cache de dépendances | Cache applicatif |
| Montage | Toujours utile | Surtout en dev |
| Prod | Volume nommé recommandé | Warming dans l’image + volume |
Résumé
- Oui, on peut appliquer le même principe de volume monté pour
/var/cache.
- Mais : Symfony a besoin d’une gestion plus active (warming, permissions).
- Optimisez :
- Dev → Volume monté + permissions
- Dev → Volume monté + permissions
- Prod → Cache warming + volumes nommés
Cela garantit des performances optimales dans tous les cas ! 🚀
Configuration Docker pour un projet Symfony 6 / PHP FPM / avec des bundles locaux
Voici une méthode complète pour configurer votre environnement Docker avec Symfony 6, PHP 8.2, Apache, PostgreSQL et la gestion des bundles locaux.
1. Structure recommandée
~/debian/projet/ ├── app/ # Votre projet Symfony principal │ ├── src/ │ ├── vendor/ │ └── ... ├── Bundles/ # Vos bundles locaux │ ├── bundlea/ # Bundle A │ └── bundleb/ # Bundle B ├── docker/ │ ├── apache/ │ │ └── vhost.conf # Configuration Apache │ ├── php/ │ │ └── php.ini # Configuration PHP │ └── entrypoint.sh # Script d'initialisation ├── Dockerfile # Fichier de build └── docker-compose.yml # Configuration des services
2. Dockerfile
# Dockerfile
FROM php:8.2-fpm
# Install system dependencies
RUN apt-get update && apt-get install -y \
git \
curl \
libpng-dev \
libonig-dev \
libxml2-dev \
libzip-dev \
libpq-dev \
unzip \
libevent-dev \
&& rm -rf /var/lib/apt/lists/*
# Install PHP extensions
RUN docker-php-ext-install \
pdo \
pdo_pgsql \
pgsql \
mbstring \
exif \
pcntl \
bcmath \
gd \
zip \
sockets
# Install event extension
RUN pecl install event && docker-php-ext-enable event
# Install Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
# Set working directory
WORKDIR /var/www
# Copy entrypoint
COPY docker/entrypoint.sh /usr/local/bin/entrypoint
RUN chmod +x /usr/local/bin/entrypoint
ENTRYPOINT ["entrypoint"]
3. docker-compose.yml
version: '3.8'
services:
php:
build: .
volumes:
- ./app:/var/www
- ./Bundles:/var/www/bundles
environment:
- DATABASE_URL=postgresql://symfony:ChangeMe@postgres:5432/app?serverVersion=15&charset=utf8
depends_on:
- postgres
apache:
image: httpd:2.4
ports:
- "8080:80"
volumes:
- ./app/public:/var/www/html
- ./docker/apache/vhost.conf:/usr/local/apache2/conf/extra/httpd-vhosts.conf
command: ["httpd-foreground"]
depends_on:
- php
postgres:
image: postgres:15
environment:
POSTGRES_USER: symfony
POSTGRES_PASSWORD: ChangeMe
POSTGRES_DB: app
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:
3 bis. docker-compose.yml (option dans compose.yml)
Voir Composer optionnel.
# Optionnel: Composer en tant que service
composer:
image: composer:latest
volumes:
- ./app:/var/www
- ./Bundles:/var/www/bundles
working_dir: /var/www
entrypoint: ['composer']
4. Configuration Apache (docker/apache/vhost.conf)
<VirtualHost *:80>
ServerName localhost
DocumentRoot /var/www/html
<Directory /var/www/html>
AllowOverride All
Require all granted
</Directory>
ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://php:9000/var/www/public/$1
</VirtualHost>
5. Script entrypoint.sh
#!/bin/bash
set -e
# Installer les dépendances si le vendor n'existe pas
if [ ! -d "/var/www/vendor" ]; then
cd /var/www
composer install
fi
# Lancer PHP-FPM
exec docker-php-entrypoint "$@"
6. Configuration Composer dans votre projet Symfony
Dans votre app/composer.json, assurez-vous d’avoir:
{
"repositories": [
{
"type": "path",
"url": "../Bundles/bundlea",
"options": {
"symlink": true
}
},
{
"type": "path",
"url": "../Bundles/bundleb",
"options": {
"symlink": true
}
}
]
}
7. Workflow recommandé
Initialisation:
docker-compose build docker-compose up -d
Pour utiliser Composer:
Soit via le service Composer:
docker-compose run --rm composer install docker-compose run --rm composer update
Soit en entrant dans le container PHP:
docker-compose exec php bash composer install
Configuration PHPStorm:
- Configurer l’interpréteur PHP dans Settings > PHP
- Ajouter les mappings de chemins:
/var/www→./app/var/www/bundles→./Bundles
- Configurer le serveur Apache dans Settings > PHP > Servers
- Nom: Docker Apache
- Host: localhost
- Port: 8080
- Debugger: Xdebug
- Path mappings comme ci-dessus
8. Avantages de cette configuration
- Développement simultané:
- Vos bundles locaux sont accessibles dans le container via
/var/www/bundles - Les modifications sont immédiatement visibles dans les deux sens
- Vos bundles locaux sont accessibles dans le container via
- Performance:
- Les dépendances sont installées dans le container
- Les symlinks Composer fonctionnent correctement
- Flexibilité:
- Vous pouvez utiliser Composer de plusieurs manières
- Configuration facilement extensible
Cette configuration vous permettra de travailler efficacement avec PHPStorm tout en bénéficiant d’un environnement Docker isolé et reproductible.
Cette ligne est assez importante dans le contexte d’un Dockerfile et d’un script d’entrée (entrypoint). Je vais vous l’expliquer en détail :
Explication de exec docker-php-entrypoint "$@"
exec:- En shell, la commande
execremplace le processus courant (le script entrypoint.sh) par le nouveau processus spécifié - Cela signifie que le processus PID 1 du container devient
docker-php-entrypointau lieu deentrypoint.sh - Avantages :
- Évite d’avoir un processus shell inutile qui reste en vie
- Permet de recevoir correctement les signaux système (comme SIGTERM)
- En shell, la commande
docker-php-entrypoint:- C’est le script d’entrée par défaut de l’image officielle PHP
- Il est fourni par les mainteneurs de l’image Docker PHP
- Son rôle principal est de :
- Configurer certaines variables d’environnement
- Préparer le runtime PHP
- Finalement lancer PHP-FPM
"$@":- C’est une notation spéciale en shell qui signifie “tous les arguments passés au script”
- Si vous lancez le container avec
docker run votre-image php -v, alors"$@"contiendraphp -v - Cela permet de transmettre tous les arguments au processus suivant
Pourquoi c’est important dans votre cas ?
Dans votre entrypoint.sh, vous faites d’abord :
# Vérifie si vendor existe, sinon installe les dépendances
if [ ! -d "/var/www/vendor" ]; then
cd /var/www
composer install
fi
Puis vous terminez avec :
# Passe le relais au entrypoint officiel PHP
exec docker-php-entrypoint "$@"
Cela signifie : 1. Votre script fait d’abord son travail personnalisé (vérifier/vendor et installer les dépendances si besoin) 2. Ensuite, il “passe la main” au processus PHP-FPM officiel, devenant ainsi le processus principal du container
Alternative sans exec
Si vous écriviez simplement :
docker-php-entrypoint "$@"
Au lieu de :
exec docker-php-entrypoint "$@"
Alors : - Le shell du script entrypoint.sh resterait en vie inutilement - Les signaux système ne seraient pas correctement transmis à PHP-FPM - Vous auriez un processus superflu dans votre container
En résumé
Cette ligne est une bonne pratique Docker qui permet : 1. D’exécuter votre logique personnalisée avant le démarrage 2. De transférer proprement l’exécution au processus principal 3. De garantir une gestion propre des processus et des signaux
C’est particulièrement important pour des services comme PHP-FPM qui doivent être le processus principal du container pour fonctionner correctement.
composer:latest (optionnel)
Ce service Composer optionnel pour vous donner une alternative plus propre et isolée pour exécuter les commandes Composer, plutôt que de les exécuter directement dans le container PHP-FPM. Voici les raisons détaillées :
1. Séparation des responsabilités
- Problème sans ce service :
Si vous utilisez composer install/update directement dans le container PHP (via docker-compose exec php composer ...), vous mélangez deux rôles :
- Le service PHP-FPM (qui doit rester dédié à l’exécution PHP)
- La gestion des dépendances (qui est un besoin ponctuel lors du développement)
- Solution :
Un service dédié à Composer est éphémère (run-and-die) et ne pollue pas votre environnement PHP-FPM.
2. Avantages concrets
a) Gestion propre des permissions
- Les fichiers générés par Composer (vendor/, composer.lock) auront les mêmes permissions que votre utilisateur local (car le container Composer hérite des permissions du volume monté).
- Évite les problèmes classiques de permissions quand on utilise
composer installdans le container PHP.
b) Isolation des dépendances
- Le container PHP n’a pas besoin d’avoir Composer installé en permanence (même si mon Dockerfile l’inclut pour la flexibilité).
- Réduction de l’image finale en production (vous pouvez créer une image sans Composer).
c) Compatibilité avec les bundles locaux
- Comme vous utilisez des bundles locaux (via
"type": "path"), le service Composer monte à la fois./appet./Bundles, garantissant que les symlinks fonctionnent correctement.
3. Comment l’utiliser ?
Exemples d’utilisation :
# Installation des dépendances
docker-compose run --rm composer install
# Mise à jour d'un bundle local
docker-compose run --rm composer update vendor/bundlea
# Ajout d'une nouvelle dépendance
docker-compose run --rm composer require symfony/package
--rm: Détruit le container après l’exécution (pour éviter l’accumulation de containers stoppés).- Le
working_dir: /var/wwwfait que les commandes s’exécutent directement dans le dossier du projet.
4. Alternative : Composer dans le container PHP
Si vous préférez ne pas utiliser ce service optionnel, vous pouvez : 1. Utiliser le Composer inclus dans le container PHP :
bash docker-compose exec php composer install 2. Ou via le script entrypoint.sh (qui vérifie déjà si vendor/ existe).
5. Pourquoi “optionnel” ?
- Beaucoup de développeurs préfèrent exécuter Composer en dehors de Docker (sur leur machine host) pour des raisons de performance (cache Composer partagé, pas de overhead Docker).
- Mais dans votre cas, avec des bundles locaux et une configuration spécifique, avoir un service dédié est plus fiable.
En résumé :
| Approche | Avantages | Inconvénients |
|---|---|---|
| Service Composer dédié | Propre, isolé, permissions cohérentes | Un peu plus verbeux à taper |
| Composer dans le container PHP | Rapide à exécuter | Pollue le container PHP |
| Composer sur la machine host | Meilleures performances | Peut causer des problèmes de permissions |
Le choix dépend de votre workflow, d’où le caractère optionnel !
version complète optimisée avec un service Composer dédié
Voici une version complète optimisée avec un service Composer dédié, tout en gardant la configuration pour vos bundles locaux et l’intégration avec PHPStorm.
Structure finale recommandée
~/debian/projet/ ├── app/ # Projet Symfony principal │ ├── src/ │ ├── vendor/ │ ├── public/ │ └── composer.json ├── Bundles/ # Bundles locaux │ ├── bundlea/ # Bundle A │ └── bundleb/ # Bundle B ├── docker/ │ ├── apache/ │ │ └── vhost.conf # Config Apache │ ├── php/ │ │ └── php.ini # Config PHP │ └── entrypoint.sh # Script d'initialisation ├── .env # Variables d'environnement ├── Dockerfile # Build PHP-FPM └── docker-compose.yml # Configuration Docker
1. Fichier .env (nouveau)
# PostgreSQL
POSTGRES_USER=symfony
POSTGRES_PASSWORD=ChangeMe
POSTGRES_DB=app
# Symfony
APP_ENV=dev
DATABASE_URL="postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}?serverVersion=15&charset=utf8"
2. Dockerfile (optimisé)
FROM php:8.2-fpm
# Dependencies + Extensions PHP
RUN apt-get update && apt-get install -y \
git \
libpq-dev \
libzip-dev \
libevent-dev \
&& docker-php-ext-install pdo pdo_pgsql zip \
&& pecl install event \
&& docker-php-ext-enable event
# Script d'entrée
COPY docker/entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/entrypoint.sh
WORKDIR /var/www
ENTRYPOINT ["entrypoint.sh"]
3. docker-compose.yml (complet)
version: '3.8'
services:
php:
build: .
volumes:
- ./app:/var/www
- ./Bundles:/var/www/bundles
env_file:
- .env
depends_on:
- postgres
apache:
image: httpd:2.4
ports:
- "8080:80"
volumes:
- ./app/public:/var/www/html
- ./docker/apache/vhost.conf:/usr/local/apache2/conf/extra/httpd-vhosts.conf
depends_on:
- php
postgres:
image: postgres:15
env_file:
- .env
volumes:
- postgres_data:/var/lib/postgresql/data
composer:
image: composer:2
volumes:
- ./app:/var/www
- ./Bundles:/var/www/bundles
- composer_cache:/tmp
working_dir: /var/www
environment:
- COMPOSER_CACHE_DIR=/tmp
entrypoint: ["composer"]
volumes:
postgres_data:
composer_cache:
4. docker/apache/vhost.conf
<VirtualHost *:80>
DocumentRoot /var/www/html
ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://php:9000/var/www/public/$1
<Directory "/var/www/html">
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
5. docker/entrypoint.sh (optimisé)
#!/bin/bash
set -e
# Attendre que PostgreSQL soit prêt
while ! nc -z postgres 5432; do
sleep 1
done
# Lancer PHP-FPM
exec php-fpm
6. Configuration Composer (app/composer.json)
{
"repositories": [
{
"type": "path",
"url": "../Bundles/bundlea",
"options": {
"symlink": true
}
},
{
"type": "path",
"url": "../Bundles/bundleb",
"options": {
"symlink": true
}
}
]
}
🔧 Workflow recommandé
Initialisation :
docker-compose build docker-compose up -d
Installer les dépendances (via le service Composer) :
docker-compose run --rm composer install
Mettre à jour un bundle local :
docker-compose run --rm composer update vendor/bundlea
Accéder aux logs :
docker-compose logs -f php
Arrêter l’environnement :
docker-compose down
🛠 Intégration PHPStorm
- Configurer les mappings :
/var/www→./app/var/www/bundles→./Bundles
- Interpréteur PHP :
- Utiliser le PHP du container (Settings > PHP)
- Server Configuration :
- Nom : Docker Apache
- Host : localhost
- Port : 8080
- Path mappings comme ci-dessus
✅ Points clés de cette configuration
- Service Composer isolé avec cache persistant (
composer_cache) - Symlinks des bundles locaux fonctionnels grâce au volume partagé
- Environnement reproductible avec PostgreSQL intégré
- Optimisé pour PHPStorm avec les bons mappings de chemins
- Entrypoint minimaliste qui attend juste que la DB soit prête
Cette solution offre un équilibre parfait entre isolation des services et facilité de développement avec les bundles locaux.