Tuto config XDEBUG pour votre container applicatif

Retrouvez tous les fichiers par ici :

UX & Webdesign
Publié le 03/04/2018
Auteurs
Victor A.
Tech Manager
Victor A.
Partager l’article

DOCKER C’EST BIEN…

Petite piqûre de rappel : Docker est un outil de « conteneurisation ». Un conteneur créé via Docker permet de recréer un environnement spécifique sur votre poste. L’intérêt est double, simuler l’environnement de production mais aussi de bénéficier de plusieurs environnements différents en fonction du projet. 

Et pour éviter ce genre de constat aussi :

ah mince, pour ce projet j’ai besoin de PHP 7.2 alors que sur l’autre j’étais encore en 5.6

Pour multiplier les environnements spécifiques sans avoir à créer 12 000 images différentes, Docker fonctionne par empilement successif d’images. Ces dernières sont réutilisables notamment en fonction de leur position dans la pile.


 

 

 

Tout en haut se trouve le dernier élément de votre environnement, il vient clore sa définiton. Si la plupart des couches peuvent être récupérées sur un Hub (par défaut) certaines pourront donc être amenées à être définies par vous, pour vos besoins.

Si vous utilisez « docker-compose » , vous configurez probablement votre projet en ciblant des images en provenance d’un hub (et si vous ne l’utilisez pas, je vous le recommande).

Lorsque le périmètre de l’image qui reçoit votre application ne suffit plus, il convient donc de créer votre propre image.

…UN DOCKER CUSTOM C’EST ENCORE MIEUX !

L’objectif

Avant de commencer, prenons un exemple de besoin spécifique : l’utilisation de xdebug, notamment via CLI.

Il s’agit là d’un exemple plutôt utile au développement (carrément nécessaire même) mais bien qu’il n’ait pas de rapport avec la prod’, il reste un exemple solide pour cet exercice.

Autre information, ce tuto fonctionne aussi si vous utilisez Docker for Mac

Le Tuto

La création d’un environnement custom repose sur la rédaction d’un Dockerfile.

Un Dockerfile commence par référencer l’image sur laquelle vous allez venir empiler votre surcouche, puis le nom de la personne qui crée cette configuration (en l’occurrence, vous).

L’important ici, c’est de partir d’une image sur laquelle PHP est installé.

La bavette étant bien taillée il est temps de s’attaquer à la rédaction des instructions nécessaires à enrichir votre future image.

Il faut savoir que chaque instruction (identifiée par une instruction Docker, par exemple :RUN) correspondra à la création d’une image (ou layer) ; de sorte que si vous vous trompez dans la rédaction d’une ligne et que la création de l’image échoue en cours de route, les premières étapes pourront ne pas être ré exécutées.

Pour continuer, on liste ensuite toutes les instructions nécessaires à l’installation, comme vous pourriez procéder sur votre propre poste.

3 COMMANDES DOCKER SONT UTILISÉES : 

  • RUN : exécute les commandes CLI sur le container
  • COPY : copie un fichier depuis le host (votre machine) vers le container
  • CMD : exécute une instruction au lancement du container
RUN apt-get update \
    && apt-get install -y dnsutils

RUN yes | pecl install xdebug \
    && echo "zend_extension=$(find /usr/local/lib/php/extensions/ -name xdebug.so)" > $PHP_INI_DIR/conf.d/xdebug.ini \
    && echo "xdebug.remote_enable=On" >> $PHP_INI_DIR/conf.d/xdebug.ini \
    && echo "xdebug.remote_autostart=On" >> $PHP_INI_DIR/conf.d/xdebug.ini \
    && echo "xdebug.remote_connect_back=On" >> $PHP_INI_DIR/conf.d/xdebug.ini \
    && echo "xdebug.idekey=PHPSTORM" >> $PHP_INI_DIR/conf.d/xdebug.ini

COPY start.sh /usr/local/bin/
RUN chmod ug+x /usr/local/bin/start.sh \
    && mkdir /home/www-data \
    && usermod -d /home/www-data www-data \
    && chown www-data /home/www-data

COPY init.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/init.sh
RUN cat /usr/local/bin/init.sh >> /etc/bash.bashrc
RUN chmod ugo+w /etc/passwd # allow to modify users name by every users

CMD ["/usr/local/bin/start.sh"]

Les instructions ci-dessus permettent donc, entre autre, d’activer l’extension xdebug pour PHP.

Décorticons un peu tout ça :

  • La première instruction permet de mettre à jour la liste des paquets d’installation disponibles. L’utilitaire qu’on installe, dnsutils, permettra plus tard de récupérer l’adresse IP du container dans lequel on lancera le script, en particulier lorsqu’on fait fonctionner le container via Docker for Mac.
  • La longue série suivante permet d’installer l’extension xdebug pour PHP.
  • Les deux suivantes préparent le script bash qui sera lancé au démarrage du container (on précisera son contenu plus tard).
  • Les 4 qui viennent après exécutent un script qui sera lancé lorsqu’on ouvre un bash sur le container.
  • Et enfin la dernière instruction consiste à préciser qu’il faut lancer le script précédemment copié dans l’image lorsqu’on démarre le container.

A ce stade, on peut déjà préciser un point : une partie de ces instructions vise à rendre le tout fonctionnel pour un user qui pourrait correspondre à celui de votre application (ici www-data). Etre « root » c’est pratique, mais si vous développez dans des conditions similaires à la prod, on va partir du principe qu’un user dédié sera utilisé pour faire fonctionner votre app.

Restent encore quelques instructions à découvrir dans les scripts bash qui complètent la définition de notre image.

Les voici : start.sh

#!/bin/bash

if [ -z "${PHP_IDE_CONFIG}" ]; then
  # Enable Xdebug by env variables :
  ipPhpstorm=$(ip addr | grep eth0 | grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}' | head -n 1)".1";
  #For mac users, phpstorm IP is docker.for.mac.localhost see https://docs.docker.com/docker-for-mac/networking/#use-cases-and-workarounds

  if [ "$(dig docker.for.mac.localhost | grep 'ANSWER SECTION' | wc -l)" -eq 1 ]; then
    ipPhpstorm="docker.for.mac.localhost"

  fi
  export PHP_IDE_CONFIG="serverName=$SERVER_NAME";
  export XDEBUG_CONFIG="remote_enable=1 remote_mode=req remote_port=9000 remote_host=${ipPhpstorm} remote_connect_back=0 idekey=PHPSTORM";
  export XDEBUG_REMOTE_HOST="${ipPhpstorm}";
  # Display env var available
  echo "PHP_IDE_CONFIG='$PHP_IDE_CONFIG'";
  echo "XDEBUG_CONFIG='$XDEBUG_CONFIG'";
  echo "XDEBUG_REMOTE_HOST='$XDEBUG_REMOTE_HOST'";
fi

Celui-ci n’est exécuté qu’une seule fois, au démarrage du container. Il permet essentiellement de faire en sorte que le user www-data corresponde à votre user local et ainsi bénéficier des permissions adéquates ; pour cela il faut exporter les variables $USER_UID et $USER_GROUP qui contiendront votre « uid » et votre « gid ». Ce script permet aussi de lancer PHP fpm. L’option -nodaemonize permet quant à elle de lancer php en premier plan (i.e. tjs actif par défaut) et ainsi conserver votre container ouvert ; par défaut un container se stop lorsqu’il n’est pas actif.

Une ligne s’est glissée dans ce script : c’est l’appel au second script init.sh qui sera également exécuté lorsque vous ouvrirez un bash sur votre container : init.sh

#!/bin/bash

if [ -z "${PHP_IDE_CONFIG}" ]; then
  # Enable Xdebug by env variables :
  ipPhpstorm=$(ip addr | grep eth0 | grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}' | head -n 1)".1";
  #For mac users, phpstorm IP is docker.for.mac.localhost see https://docs.docker.com/docker-for-mac/networking/#use-cases-and-workarounds

  if [ "$(dig docker.for.mac.localhost | grep 'ANSWER SECTION' | wc -l)" -eq 1 ]; then
    ipPhpstorm="docker.for.mac.localhost"

  fi
  export PHP_IDE_CONFIG="serverName=$SERVER_NAME";
  export XDEBUG_CONFIG="remote_enable=1 remote_mode=req remote_port=9000 remote_host=${ipPhpstorm} remote_connect_back=0 idekey=PHPSTORM";
  export XDEBUG_REMOTE_HOST="${ipPhpstorm}";
  # Display env var available
  echo "PHP_IDE_CONFIG='$PHP_IDE_CONFIG'";
  echo "XDEBUG_CONFIG='$XDEBUG_CONFIG'";
  echo "XDEBUG_REMOTE_HOST='$XDEBUG_REMOTE_HOST'";
fi

Ce script mérite peut être un peu plus d’explications (malgré ses commentaires).

 

Pour fonctionner en CLI, xdebug nécessite 3 variables d’environnement :

  • PHP_IDE_CONFIG : servira à faire le lien entre votre IDE (rappelons à toutes fins utiles que c’est lui qui permettra l’éxécution pas à pas) et le script exécuté. L’IDE étant plutôt habitué à écouter des instructions en provenance d’un host, la variable $SERVER_NAME contiendra une valeur permettant de faire le lien entre votre container et l’IDE (là où habituellement, cette variable correspond au nom de domaine de votre site).
  • XDEBUG_CONFIG : une configuration de xdebug, indépendante de votre environnement.
  • XDEBUG_REMOTE_HOST : les informations réseau qui permettront de faire le lien entre votre container et votre IDE : autrement dit, une IP, et la petite clé de configuration de votre IDE (ici, PHPSTORM).

 

Une fois toutes ces étapes réalisées, vous devriez être en mesure de faire du pas à pas dans vos scripts : et ça, ça n’a pas de prix ! Il ne vous reste donc plus qu’à lancer un bash sur votre container (docker exec --user=www-data -it nom-du-container bash) et lancer votre script.

Happy debugging ! 

 


NB : 

Ce script est également l’occasion de redécouvrir pourquoi la configuration de la remote host doit nécessairement se terminer par 1 (cf regex du script), et l’explication se trouve ici. Autrement dit, il s’agit d’un relicat d’une configuration faite pour vagrant. Cela fonctionne ainsi, mais il semblerait que Docker puisse s’en passer : à vous de nous le dire ?