Développer en PHP avec docker

Développer en PHP avec docker

2019-03-14 0 By Sauleil

Introduction

J’ai commencé à développer en PHP quand j’étais encore sur les bancs universitaires. J’ai personnellement toujours détesté ce langage (originalement non typé, fonctions non cohérentes dans leur API, parfois difficile à débugger, Juste assez similaire à JS pour se tromper souvent entre les 2, etc). Mais bon, plusieurs fournisseurs de serveurs utilisent cette technologie parce qu’elle a plusieurs avantages niveau serveurs et maintenance. La preuve que WordPress ou Drupal utilise cette technologie prouve qu’elle n’est pas si mal après tout.

Outre mes préjugés et mes aversions envers ce langage, j’aime quand même travailler avec (love-hate relashionship), sauf pour ce qui a attrait au setup de la machine de développement. Combien de journée j’ai perdu à essayer de configurer Apache, PHP ou MySQL pour qu’il fonctionne bien dans Windows et ayant les bonnes versions qui “fit” avec celle de mon host.

Avec les années, des “PHP manager” tel qu’EasyPHP, XAMPP ou WAMP sont apparues pour nous “simplifier” la vie. Mais était-ce vraiment le cas? Personnellement, j’ai toujours eu pleins de problèmes lors de l’installation (gestions de ports, de DB, de version de PHP, etc.). Mais un jour j’ai découvert “Docker“. Ce concept changea ma relation avec le développement web/PHP. Il y a plusieurs façons de travailler avec et ici je vais donner une version que je trouve très pratique pour de petits projets simples.

Requis

Je prends pour acquis que vous serez sur Windows, mais ça fonctionne aussi bien sur OSX ou Linux.

Donc, vous aurez besoin de Docker. C’est tout! Ça va installer l’engine de docker, l’outil docker-compose. Je ne passerai pas trop de temps à expliquer Docker, mais si je voulais résumer ça en 1 phrase: il s’agit de “mini machine virtuelle” qui exécute un seul “process” à la fois dans un environnement fermé (docker host) qui coexiste d’autres “process“.

Ensuite, n’oubliez pas d’aller dans les settings et de partager le “drive” sur lequel vous ferez du développement. C’est pour des questions de sécurité si vous vous posez la question pourquoi ce n’est pas partagé par défaut.

Un autre outil que je trouve vraiment pratique, c’est PHPStorm de JetBrains. Mais si vous préférez VS Code ou Notepad++, faites comme vous voulez. Cependant, je vais utiliser PHPStorm comme éditeur.

Configuration

Il y a quelques années, j’ai découverts le site phpdocker.io. C’est vraiment pratique pour partir un nouveau projet PHP sans avoir trop de connaissance avec Docker. En utilisant le générateur, on peut avoir une première ébauche fonctionnelle en quelques secondes.

Pour notre exemple, sélectionnons les options suivantes:

Project Name: honosoft
Base Port: 9090
PHP Version: 7.2.X
Extensions: MySQL & XDebug Enable 
MySQL: Let's use 5.7 for this example and fill the user/pass info

Cliquez sur le bouton “Generate Project” et téléchargez l’archive. Donc, vous retrouverez cette liste de fichier que je vous conseille de mettre à la racine de votre projet.

docker-compose.yml
phpdocker\README.html
phpdocker\README.md
nginx\nginx.conf
php-fpm\Dockerfile
php-fpm\php-ini-overrides.ini

Je vais faire un tour rapide des fichiers pour vous donner quelques explications avant de se lancer dans les commandes:

docker-compose.yml

C’est l’équivalent d’un “makefile“. Ce fichier contient la configuration de chacune de vos images. En ouvrant le fichier, on voit qu’il y a 3 services de configurer: “mysql“, “webserver” et “php-fpm“. vous remarquerez qu’il y a 2 types de services: un qui vient d’une “image” et l’autre qui est de type “build”. Le service de type “build” comme son nom l’indique va construire l’image basé sur un fichier de configuration. On verra en détail dans la section du service.

Donc, les trucs importants, si vous ne voulez pas vous taper la doc:

  • volume: C’est pour faire un “mount” du “working dir” sur votre machine locale. C’est pourquoi je vous ai indiqué auparavant de “share” votre drive de dev. La syntaxe est assez simple: <host path>:<docker path>.
  • ports: C’est pour “mapper” votre port de machine à celui de l’image docker. Donc, si vous voulez vous connecter sur votre process, juste assigner le bon port: <host port>:<docker port>.
  • environnement: Ce sont les variables d’environnement qui seront passé à votre process.

mysql

Comme c’est basé sur une image, il n’y a pas beaucoup à dire, puisque c’est déjà configuré correctement. Le seul hic est que la base de données est vide. Donc, si jamais vous voulez initialiser un schéma ou même avec des données initiales, voici le truc: Ajoutez dans les volumes la ligne suivante:

- ./config/mysql/init:/docker-entrypoint-initdb.d/:ro

Le process MySQL, quand il va partir, va aller lire en ordre alphabétique tous les scripts *.sql et les exécuter. Très pratique pour le développement comme on ne veut pas nécessairement créer à la main le data à chaque nouvelle initialisation.

webserver

Celui-là aussi est relativement simple comme c’est basé uniquement sur une image existante. Ce qu’il y a de pratique, c’est qu’il y a déjà un volume en “mount” qui pointe sur un fichier en local: “./phpdocker/nginx/nginx.conf“.

Donc, si vous ouvrez le fichier de configuration, vous verrez qu’il est déjà configuré par défaut pour faire un “rewrite” vers “index.php“. Très pratique si vous utilisez des framework tel que Slim ou des CMS.

Aussi, vous remarquerez que le “root” du projet pointe vers “/public“, ce qui veut dire que vous allez devoir vous créer un dossier “public” avec un fichier “index.php dedans.

Et si jamais vous voulez voir les logs facilement en local, vous avez juste à ajouter un volume qui pointe vers: “/var/log/nginx/application.access.log“. Mais personnellement, je ne trouve pas ça super utile comme les logs apparaissent déjà dans la console qui roule le “docker-compose“.

php-fpm

Pour celui-ci, c’est un peu plus complexe, puisque c’est c’est basé sur un “Dockerfile“. Vous verrez que comme dans le docker-compose, l’image est basé sur une existante. Après, on exécute des commandes Linux pour initialiser le container. Dans ce cas-ci, on voit qu’on ajoute les “packages” “php7.2-mysql php-xdebug” à l’image.

Ensuite, le “docker-compose” pointe sur le fichier de configuration “php-ini-overrides.ini“. Donc, si vous voulez modifier des variables de PHP, c’est dans ce fichier que vous pouvez le faire.

Exécution

Voici la partie intéressante. Normalement, si vous avez déjà un fichier “index.php” dans un dossier “./public/index.php“, ça devrait fonctionner. Donc, sans plus attendre, voici les commandes utiles. Si vous en voulez d’autres, google est bien sûr là pour vous aider.

Je vous conseille d’utiliser “power shell” pour faire les commandes. Aussi, dans les fichiers que vous avez téléchargés, vous pouvez vous référer au “README.md” qui contient plusieurs commandes intéressantes qui pourront vous aider.

Start

C’est la commande qui va initialiser le tout et lancer les instances:

> docker-compose up

Après cela, vous avez seulement à aller à l’adesse http://localhost:9090 sur votre “Web Browser” préféré (En ce moment, le mien est Brave).

Build

Si jamais vous faites des changements sur un fichier “Dockerfile“, utilisez cette commande pour refaire l’image:

> docker-compose build

Débugging

Maintenant que votre setup fonctionne, comme tout bon développeur, vous voudrez tester si les “breakpoints” fonctionnent. On a mis “XDEBUG” dans les flags pour l’image de PHP, mais ce ne sera malheureusement pas suffisant. Il faut ajouter quelques “configs“,

Tout d’abord, vous devrez configurer votre fichier “php-ini-overrides.ini” avec les valeurs appropriées:

; Instead of hardcoding the machine IP, we use this hostname.
xdebug.remote_host=host.docker.internal
xdebug.remote_port=9001
xdebug.remote_enable=1
xdebug.remote_autostart=0
; Very important for Docker to be set to off or else the debug won't work
xdebug.remote_connect_back=0
xdebug.remote_mode=req
xdebug.idekey=PHPSTORM
xdebug.remote_log=/tmp/xdebug.log

Ça m’a pris malheureusement plusieurs jours faire fonctionner ça comme je désirais. Tout d’abord, je ne voulais pas “hard-coded” l’IP de ma machine, parce que si d’autres personnes prenaient le projet, ils devraient toujours faire une modification. Très pratique, depuis quelques temps, docker (18.03) a ajouter la variable “host.docker.internal”.

De plus, la variable “remote_connect_back” est à “1” par défaut et à cause de l’environnement Docker, ça cause un problème de conflit de port. J’ai ajouté aussi un log file, qui peut vous aider si jamais vous éprouvez des difficultés avec le “xdebug“.

Ensuite vous devez aller devoir configurer PHPStorm pour qu’il “match” vos “settings” que vous avez mis dans le fichier “php.ini“. Normalement, tout devrait être correct:

  1. Aller dans les Settings (ctrl + alt + S)
  2. Allez à la page: Languages and Frameworks -> PHP -> Debug
    • Debug Port = 9000
    • Can accept Remote Connection: checked

Vous devrez ensuite créer une nouvelle configuration:

  1. Cliquez “Add Configuration”
  2. Des “templates“, choisissez “PHP Remote Debug“.

Vous n’avez pas besoin de faire de setup avec la “IDE key” comme c’est en local.

Ensuite, partez en “debug” dans PHPStorm et ça devrait fonctionner comme par magie.

Note:
J’ai eu des problèmes avec la configuration de PHP 7.3 à un certain moment. Pour une raison que j’ignore, le fichier de config php n’était pas lu correctement. On dirait que ce n’était pas le bon répertoire. J’avais dû ajouter un volume pour que ça pointe dans le dossier “cli”:

- ./phpdocker/php-fpm/php-ini-overrides.ini:/etc/php/7.3/cli/conf.d/99-overrides.ini

Si jamais ça peut vous aider. C’était l’une des raisons où j’avais perdu beaucoup de temps.

MySQL

Je ne m’étendrai pas sur le sujet, mais c’était seulement pour faire une remarque quand vous allez l’utiliser dans le code PHP. Si vous voulez vous connecter, vous avez juste à utiliser le nom du host “honosoft-mysql” que vous avez spécifié dans votre fichier “docker-compose.yml“.

Package Manager

Quand on fait du web aujourd’hui, on ne peut pas travailler sans utiliser de “Package Manager”. Pour PHP par exemple, on utilise Composer. Donc, quoi faire pour ne pas avoir à installer Composer sur sa machine? Très simple, il suffit d’ajouter un service qui fera le travail pour nous. Donc dans le “docker-compose.yml”, ajoutez un nouveau service:

composer:
  restart: 'no'
  image: composer/composer
  container_name: sunebook-composer
  working_dir: /composer
  command: install
  volumes:
    - .:/composer

Après le “docker-compose up“, vous n’aurez qu’à exécuter la commande suivante:

> docker-compose run composer install

ou bien par exemple

> docker-compose run composer require package/name

Si vous allez sur dockerhub, vous trouverez pleins de containers déjà existants que vous pourrez configurer de la même manière (Node, Bower, etc). Vous pouvez aussi y aller avec une image qui a tout déjà, même avec un Webpack. Mais pour ce tutoriel, je n’entrarai pas dans les détails.

Déploiement

Une fois terminé, il y a bien sûr le déploiement à prévoir. Il y a plusieurs manières de procéder. Si vous avez un host qui supporte Docker, c’est merveilleux, avez quelques modifications, vous pourrer facilement avoir un environnement “production ready“.

Si vous avez un host “static“, avoir un build script avec Gulp ou Webpack pour créer un “package” est probablement une bonne idée. Après il s’agit que d’uploader vos fichiers finaux vers votre serveur web.

WebPack

Si vous utilisez webpack servi par un docker, vous verrez qu’avec le “hot reloading” que c’est très lent. C’est dommage, parce que pour faire un environnement de dev “instantané”, c’est vraiment super. La raison est que le “file system” de Windows et celui de Linux ne sont pas compatible à 100%. Et quand on “mount” un volume sur windows, faire des “watch” sur tous les fichiers cause énormément “d’overhead“. C’est encore pire sur Mac.

Donc les solutions possibles que je connaisse sont soit d’utiliser une vraie VM de linux et travailler dans Virtual Box par exemple ou bien directement sur linux. Ici vous avez une page qui donne des pistes de solution en attendant: https://docs.docker.com/docker-for-mac/osxfs-caching/

Conclusion

Ce fut un article beaucoup plus long que je pensais, mais voici le code source de l’article:

https://bitbucket.org/honosoft/php-docker/