Profiler une application PHP avec xhgui et xhprof sous docker
29 Mar 2018Introduction
Dans le monde des applications PHP, il existe plusieurs outils qui permettent d’analyser le temps d’exécution du code et de cibler quelles instructions ralentissent le rendu des pages HTML. Le plus connue est sans doute Blackfire par Sensio que j’ai eu l’occasion d’essayer et de proposer à mon équipe alors que je travaillais à CommonLedger.
Même si Blackfire est relativement facile à mettre en place, il ne répondait pas à toutes nos attentes étant donné que nous ne travaillions pas sur des projets open-source. En effet si Blackfire reste gratuit pour les projets open-source, il est en revanche payant pour les projets propriétaires. Si mes souvenirs sont bons, le fait que les données analysées soient envoyés sur un serveur distant a également provoqué quelques grimaces…
Apres quelques recherches il s’est avéré que Xhprof consitutait une alternative qui ne posait pas ces problèmes. Étant donné que notre environnement de développement fonctionnait intégralement sur docker, je me suis attelé à dockerizer Xhprof, ainsi que l’interface web Xhgui.
Voici un schéma représentant l’architecture que ce tutoriel va mettre en place.
Si vous êtes pressé, tous les fichiers créés dans ce tuto sont disponibles sur ce repository github avec des instructions pour tout installer en accéléré.
Mise à jour: Une configuration docker-compose officielle a vu le jour depuis que cet article a été rédigé. Jetez-y un coup d’œil : https://github.com/perftools/xhgui/blob/master/docker-compose.yml
Installer l’application PHP avec docker
Un prérequis à ce tutoriel est d’avoir une application PHP servie par un conteneur.
Il est tout à fait envisageable d’avoir certains composants conteneurisés et d’autres non. Pour simplifier ce tutoriel au niveau réseau, tous les composants fonctionneront sous docker.
J’ai déjà écris un article avec des fichiers initiaux identiques. Plutôt que de faire un copié-collé suivez la première partie de ce tutoriel puis revenez sur cette page. Si vous avez déjà une application PHP fonctionnant sous docker c’est encore mieux! Il vous suffira d’adapter ce qui suit à votre environnement.
À partir d’ici, vous devriez avoir un dossier contenant les 5 fichiers comme suit:
- docker-compose.yml
- Dockerfile-php-app
- php.ini
- app.conf
- index.php
Installation des conteneurs xhgui et xhprof
Mettons à jour le fichier docker-compose.yml
en ajoutant 3 nouveaux services.
services:
...
php_xhgui:
build:
context: .
dockerfile: Dockerfile-php-xhgui
nginx_xhgui:
build:
context: .
dockerfile: Dockerfile-nginx-xhgui
ports:
- 8081:80
volumes:
- ./xhgui.conf:/etc/nginx/conf.d/default.conf:ro
depends_on:
- php_xhgui
mongo:
image: mongo:3.7.9
Comme vous vous en doutez, il nous faut créér les 3 nouveaux fichiers référencés dans le fichier docker-compose.yml.
- Dockerfile-php-xhgui
Le Dockerfile de l’image PHP xhgui s’occupe d’installer l’extension mongo pour récupérer et stocker les données profilées, ainsi que l’application PHP xhgui.
FROM php:7.1-fpm-alpine
RUN apk add --no-cache git
RUN apk add --no-cache autoconf alpine-sdk zlib-dev
RUN pecl install mongodb && docker-php-ext-enable mongodb
RUN docker-php-ext-install zip # useful for composer
RUN git clone https://github.com/perftools/xhgui.git /var/xhgui
RUN cd /var/*xhgui && php install.php
COPY xhgui_config.php /var/xhgui/config/config.php
- Dockerfile-nginx-xhgui
Le Dockerfile de l’image nginx xhgui copy simplement les fichiers de l’application xhgui. Cela permettra à nginx de servir les fichiers statiques (css, js, images, etc.).
FROM nginx:1.12.2
RUN apt-get update
RUN apt-get install -y git
RUN git clone https://github.com/perftools/xhgui.git /var/xhgui
RUN chmod -R 0777 /var/xhgui/cache
- xhgui.conf
Voici le fichier de configuration nginx concernant xhgui. En ce qui concerne la configuration spécifique à xhgui:
- Le répertoire de base de xhgui est /var/xhgui/webroot/.
- fastcgi_pass correspond au nom de service docker-compose (php_xhgui). Ce nom de domaine sera résolu par le DNS interne de docker avec l’IP du conteneur xhgui php.
Le reste est standard dans le cas d’une application PHP.
server {
listen 80 default_server;
root /var/xhgui/webroot/;
index index.php;
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
location ~ \.php$ {
try_files $uri =404;
include fastcgi_params;
fastcgi_pass php_xhgui:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
- Vous avez sans doute remarqué un fichier nommé xhgui_config.php qui est copié dans le Dockerfile Dockerfile-php-xhgui.
Ce fichier est nécessaire pour configurer la connexion entre mongo et le conteneur PHP. Créez ce fichier avec le contenu suivant :
<?php
return array(
'save.handler' => 'mongodb',
'db.host' => 'mongodb://mongo:27017',
'db.db' => 'xhprof',
'db.options' => array(),
'profiler.enable' => function() {
return true;
},
'profiler.simple_url' => null,
'profiler.options' => array(),
'date.format' => 'M jS H:i:s',
'detail.count' => 6,
'page.limit' => 25,
);
Vous pouvez modifier cette configuration comme vous le souhaitez en vous référant à la documentation par défaut sur github.
Enfin nous devons mettre à jour l’image docker PHP pour inclure l’extension qui effectuera le profiling. Ajoutez ces lignes au fichier Dockerfile-php-app
# installe l'extension xhprof pour le profilage du code PHP
RUN curl "https://github.com/tideways/php-xhprof-extension/archive/v4.1.7.tar.gz" -fsL -o ./php-xhprof-extension.tar.gz && \
tar xf ./php-xhprof-extension.tar.gz && \
cd php-xhprof-extension-4.1.7 && \
apk add --update --no-cache build-base autoconf && \
phpize && \
./configure && \
make && \
make install
RUN rm -rf ./php-xhprof-extension.tar.gz ./php-xhprof-extension-4.1.7
RUN docker-php-ext-enable tideways
# installe l'extension mongodb. Le paquet xhgui-collector enverra les données xprof à mongo
RUN apk add --no-cache autoconf alpine-sdk
RUN pecl install mongodb && docker-php-ext-enable mongodb
# installw xhgui
# en théorie nous avons seulement besoin du paquet perftools/xhgui-collector mais l'installation est plus simple en récupérant le repository entier
RUN git clone https://github.com/perftools/xhgui.git /var/xhgui
RUN cd /var/xhgui && php install.php
COPY xhgui_config.php /var/xhgui/config/config.php
Ces instructions n’ont été testées que pour PHP 7
Exécutez la comande docker-compose build
pour créer une nouvelle version des images PHP, suivi de docker-compose up -d
. Vous pourrez accéder à l’interface xhgui à l’adresse http://localhost:8081/
Profilage des requêtes
Au démarrage de l’application PHP dont on souhaite mesurer les performances, ajouter le code suivant:
define('XHGUI_CONFIG_DIR', '/var/xhgui/config/');
require_once '/var/xhgui/vendor/perftools/xhgui-collector/external/header.php';
Dans notre exemple, il s’agit simplement de mettre à jour le fichier index.php.
<p>Let's do some math.</p>
<ul>
<?php
define('XHGUI_CONFIG_DIR', '/var/xhgui/config/');
require_once '/var/xhgui/vendor/perftools/xhgui-collector/external/header.php';
for ($i = 0; $i < 10; $i++) {
echo sprintf("<li>%s * 5 = %s</li>", $i, $i*5);
}
?>
</ul>
Allez sur la page http://localhost:8080/ puis rafraîchissez http://localhost:8081/. Vous devriez voir les premières mesures.
Si cet article vous a rendu service, n’hésitez pas à starrer ce repo en guise de remerciement ! ⭐
Bonne continuation!