Docker pour les développeurs PHP
24 février 2017
Un retour d'expérience et un guide de mise en place de Docker pour les développeurs PHP mais pas que…
TL;DR: Pour les plus pressés les configurations complètes sont disponibles dans le dépôt github le-phare/docker-php-dev-env.
Retour en 2015
Un peu de contexte pour ceux qui le souhaitent sinon vous pouvez directement passer à la partie technique.
Je suis développeur PHP/Symfony à l'agence Le Phare depuis 2010.
En 2015, notre équipe se compose de huit développeurs et deux intégrateurs. Nous travaillons sur plusieurs nouveaux projets client simultanément et assurons la maintenance évolutive et corrective des projets terminés.
A cette période, nous avions une vingtaine de projets actifs en maintenance et une petite dizaine de projets en cours de réalisation. Environ une trentaine de projets actifs. Chaque développeur garde la charge des projets dont il est le lead developer. Dans les semaines les plus chargées, on peut donc intervenir sur 5 ou 6 projets dans la semaine de travail.
Les projets sont développés avec Symfony et notre couche Faros avec des prérequis techniques évoluant selon les versions stables de PHP, MySQL et autres services. Parmi la trentaine de projets réalisés avec Symfony, nous avons plusieurs architectures techniques différentes.
- Debian 7, PHP 5.4, Apache 2.2, Mysql 5.5
- Debian 8, PHP 5.6, Apache 2.4, Mysql 5.5
- Debian 8, PHP 5.6, Apache 2.4, Postgresql 9.4
- Debian 8, PHP 5.6, Apache 2.4, Postgresql 9.5
Jusqu'à présent, l'installation, la configuration et la maintenance des postes de dev étaient laissées à la charge des développeurs. Nous avions alors toutes sortes d'installations et d'architectures. Des MAMP, apache/mod-php, apache/php-fpm, des serveurs PHP et même des geeks compilant leur propre PHP !
Evidemment avec une telle organisation nous avons connu quelques plantages en production simplement pour avoir utilisé des fonctionnalités apparues avec PHP 5.5 alors que le serveur de production était en 5.4… Pour éviter ces problèmes nous avons cherché un moyen pour développer dans un environnement le plus proche des serveurs de production pour chaque projet. Mais comment faire pour installer plusieurs versions de PHP, plusieurs serveurs web et plusieurs bases de données sur la même machine ?
Après avoir essayé Vagrant puis PuPHPet nous avons finalement choisi d'utiliser Docker. Voici un petit guide de survie de Docker en environnement de dev.
Découvrir Docker
Je ne vais pas me lancer dans une longue présentation de Docker. D'autres ont déjà fait ça très bien. Vous trouverez plusieurs articles très intéressant (et bien d'autres choses) sur le dépôt veggiemonk/awesome-docker.
Installer les outils
Premièrement, il faut installer Docker. Je vous renvoie pour cela sur la documentation du projet, qui explique très bien cette partie. Ensuite vous aurez besoin de docker-compose
. Là encore, la documentation fait l'affaire.
Une stack générique et des containers projets
Nous avons mis au point une architecture qui s'articule autour d'une stack générique qui fournit les containers de base de données, un proxy HTTP nginx, un serveur memcached et des outils pratiques comme adminer et maildev. Cette stack est nécessaire pour travailler sur n'importe quel projet.
Ensuite chaque projet fournit ses propres containers, Apache et PHP au minimum, mais éventuellement d'autres services comme MongoDB ou ElasticSearch. Ces containers projets vont communiquer avec les containers génériques et fournir un environnement parfaitement fonctionnel.
La stack générique
Nous utilisons la version 2 des fichiers YAML de docker-compose (disponible à partir de docker 1.8 et docker-compose 1.5). Voici un extrait de la stack générique.
version: '2'
services:
proxy:
image: jwilder/nginx-proxy
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ./conf/ssl/certs:/etc/nginx/certs:ro
- ./conf/proxy/default.conf:/etc/nginx/proxy.conf
networks:
- web
ports:
- '80:80'
- '443:443'
adminer:
image: dehy/adminer
environment:
VIRTUAL_HOST: adminer.docker
networks:
- web
- database
pgsql_95:
image: postgres:9.5
networks:
- database
volumes:
- pgsql_95_data:/var/lib/postgres/data
environment:
PGDATA: /var/lib/postgres/data
maildev:
image: djfarrelly/maildev
networks:
- web
- mail
environment:
VIRTUAL_HOST: maildev.docker
networks:
web:
driver: bridge
mail:
driver: bridge
database:
driver: bridge
volumes:
pgsql_95_data:
driver: local
Je n'ai mis qu'un seul container de base de données pour simplifier l'exemple.
Les containers
jwilder/nginx-proxy
Ce container est le seul qui écoute sur les ports 80 et 443 de la machine hôte. Il reçoit toutes les requêtes et les transmet au container projet (apache) en fonction de la variable d'environnement VIRTUAL_HOST
(voir stack projet).
Dans notre configuration nous avons également un certificat SSL auto-signé qui nous permet de configurer n'importe quel projet en HTTPS (voir stack projet).
dehy/adminer
Adminer est une interface web pour la gestion des bases de données. Une sorte de phpMyAdmin compatible avec plusieurs SGBD (Postgresql, Mysql, ElasticSearch, MongoDB).
L'image dehy/adminer
est la plus légère que nous ayons trouvée sur docker. Elle est basée sur Alpine Linux.
postgres
Nos containers de base de données Postgres basés sur les images officielles.
djfarrelly/maildev
Maildev est un serveur SMTP qui affiche les mails envoyés dans une interface web à la gmail. Il peut être configuré pour autoriser le relai vers un autre SMTP.
Les réseaux
La stack générique définit quatre réseaux docker. Tous les containers du même réseau sont capables de communiquer entre eux.
Le réseau web expose tous les containers qui exposent une interface web.
Le réseau database expose tous les containers de base de données.
Le réseau mail expose le serveur SMTP.
La stack projet
Voici un exemple de stack projet. Le plus simple est de stocker le fichier docker-compose.yml
à la racine de vos projets.
version: '2'
services:
php:
image: lephare/php:7.0
networks:
- default
- database
- mail
volumes:
- .:/var/www/symfony
web:
image: lephare/apache:2.4
networks:
- default
- web
volumes_from:
- php
volumes:
- ./var/logs/apache:/var/log/apache2
environment:
VIRTUAL_HOST: example.docker
CERT_NAME: generic
HTTPS_METHOD: noredirect
networks:
web:
external:
name: dev_web
database:
external:
name: dev_database
mail:
external:
name: dev_mail
Les images utilisées
lephare/php
Une image php basée sur les images php-fpm officielles et pré-paramétrée pour notre configuration. Le container monte le répertoire du docker-compose.yml
du projet en tant que volume dans /var/www/symfony
.
lephare/apache
Une image docker basée sur les images Apache officielles, pré-paramétrée pour notre configuration. Ce container utilise les volumes définis par le container php puis ajoute un volume pour le stockage des logs Apache.
Les variables d'environnements :
VIRTUAL_HOST
permet de donner la liste des domaines qui pointent sur ce container.CERT_NAME
permet d'indiquer le nom du certificat SSL à utiliser. Le certificatgeneric
est stocké dans la stack générique.HTTPS_METHOD
permet de définir le comportement pour les redirections HTTPS. Par défaut le proxy va rediriger automatiquement le HTTP vers HTTPS.noredirect
permet de désactiver ce comportement pour s'assurer d'avoir prévu la redirection dans le.htaccess
.
Les réseaux
Les containers doivent rejoindre les réseaux définis dans la stack générique. Pour cela nous utilisons des réseaux de type external. Docker-compose préfixe les noms de réseaux et de container avec le nom du répertoire du docker-compose.yml
. Dans notre cas la stack générique est contenue dans un dossier dev
car nous avons également d'autres stacks pour d'autres usages.
Le réseau default sert à faire communiquer les containers php et Apache, il ne contient que ce projet.
Conclusion
Docker permet une isolation complète des composants d'une application web. Les concepts peuvent paraître complexes au premier coup d'oeil (et ils le sont) mais cela vaut le coup de persévérer et de maîtriser l'outil. Deux ans après nos premiers pas, il n'a jamais été aussi facile de monter un environnement de développement au Phare qui soit aussi proche des conditions de production.
Et après ?
L'utilisation de docker résout un problème majeur mais comme toute solution informatique qui se respècte elle vient accompagnée de son lot de problèmes : comment utiliser les outils en ligne de commande d'un projet ? Composer, Symfony et Gulp par exemple. Comment profiler avec Blackfire ?
Docker apporte aussi son lot de nouveaux défis. Pourquoi ne pas utiliser cette architecture en production ? Comment configurer une platforme de CI ?
La version 1.12 apporte un nouveau système de stack, peut être que nous pourrons directement mettre nos stacks dans un registre public et simplifier encore notre système.
Bavardage
17 août 2017
Bonjour,
J'ai essayé votre solution, ça marche très bien , J'ai ajouté un docker dans le composer de dossier generic , c'est bon , mais ma question , pourquoi au niveau connexion phpmyadmin m'affiche un message d'erreur.
Unknown MySQL server host 'db' (-2)
Merci Beaucoup.
Bonne journée
17 août 2017
Bonjour @jjab2020
Le hostname a utiliser est le nom du container dans la stack générique, pgsql_95
dans mon exemple.
17 août 2017
oui, merci, mais je parle au niveau phpmyadmin, finalement ça fonctionne voici mon code que je pense sera utile
phpmyadmin:
image: phpmyadmin/phpmyadmin:latest
networks:
- web
- database
ports:
- 8009:80
environment:
VIRTUAL_HOST: "domaine"
VIRTUAL_PORT: "8009"
PMA_HOST : mysql_57
Il faut définir PMA_HOST dans Environnement.
Autre chose est ce que vous avez réussir a faire fonctionner symfony en virtual host.
pour moi symfony fonctionne uniquement en spécifiant le port c'est un peu étrange
Merci Beaucoup pour ce magnifique travail.
17 août 2017
Bonsoir encore une fois oui maintenant j'arrive a faire fonctionner symfony , merci beaucoup mon ami.
Si vous voulez je partages mon travail
Salutations
14 septembre 2017
Merci, retour intéressant. Utilisant Docker également pour calquer mes environnements de prod, j'avais essayé d'aller plus loin en utilisant non plus des environnements portables mais des espaces de travail portables avec la techno Eclipse Che(installé en local ou remote) mais sans grand succès et avoir de temps pour cela. Avez-vous un retour sur les workspaces portables ?
14 septembre 2017
@pierreboissinot Je n'ai jamais été tenté par ce genre de workspace alors je n'ai pas vraiment de retour d'expérience à faire... Comme je travail sur un portable que j'emmène partout je n'ai pas vraiment le besoin.
14 août 2017
Bonjour, je vous remercie pour cet article, il est très utile.
J'ai une question, si vous voulez bien m'aider bien sur la génération de self-signed certificate pour chaque domaine. quelle la commande a utiliser pour générer un certificat pour chaque domaine .
je ne sais pas peut être a l'aide d'open SSl
Merci bien
Bonne journée