Menu
Menu

Nous contacter

01 82 83 51 70 infos@globalis-ms.com

6B rue Auguste Vitu

75015 Paris

Tribune Glob'codeur

Le 2 avril 2016 par Armel Fauveau

Apache 2.4 et multiples versions de PHP en mode FPM

« Retour
Ce billet explique comment déployer Apache 2.4 et de multiples versions de PHP en mode FPM (Fast Process Manager). L’idée est de tirer profit des dernières évolutions d’Apache, mais surtout, de pouvoir faire cohabiter les différentes versions de PHP simultanément, tout en profitant des performances remarquables de la SAPI FPM. Cette procédure a été testée et approuvée sur la distribution Slackware (13.37.0). J’utilise cette distribution depuis 1993. Donc, ne pas s’attendre à l’utilisation de commandes apt-get et autres yum. On va partir des sources d’Apache et de PHP, compiler et configurer l’ensemble, écrire des fichiers rc, etc.

Installation d’Apache 2.4

Pour débuter, commençons par télécharger et compiler Apache. $ wget http://wwwftp.ciril.fr/pub/apache//httpd/httpd-2.4.18.tar.gz $ tar xvfz httpd-2.4.18.tar.gz $ cd httpd-2.4.18 # => Téléchargement des sources d'Apache, unarchivage et déplacement dans le répertoire source $ cd srclib $ wget http://wwwftp.ciril.fr/pub/apache//apr/apr-1.5.2.tar.gz $ tar xvfz apr-1.5.2.tar.gz $ mv apr-1.5.2 apr $ wget http://wwwftp.ciril.fr/pub/apache//apr/apr-util-1.5.4.tar.gz $ tar xvfz apr-util-1.5.4.tar.gz $ mv apr-util-1.5.4 apr-util # => Ajout de APR et APR util $ cd .. $ './configure' '--prefix=/usr/local/apache' '--enable-module=so' '--enable-rewrite' '--enable-deflate' '--enable-expires' '--enable-logio' '--with-included-apr' '--with-mpm=worker' $ make # => Compilation d'Apache en mode mpm_worker Apache propose plusieurs Modules Multi-Processus (MPM). Ici, j’ai choisi worker, mais il est possible d’opter pour prefork ou event. $ './configure' '--prefix=/usr/local/apache' '--enable-module=so' '--enable-rewrite' '--enable-deflate' '--enable-expires' '--enable-logio' '--with-included-apr' '--with-mpm=prefork' $ make # => Compilation d'Apache en mode mpm_prefork $ './configure' '--prefix=/usr/local/apache' '--enable-module=so' '--enable-rewrite' '--enable-deflate' '--enable-expires' '--enable-logio' '--with-included-apr' '--with-mpm=event' $ make # => Compilation d'Apache en mode mpm_event On peut maintenant installer Apache via la commande make install. Il reste alors à éditer le ficher httpd.conf et veiller à activer LoadModule proxy_module modules/mod_proxy.so et LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so. Ces modules seront essentiels pour utiliser PHP en mode FPM. En fonction des besoins, on peut aussi en profiter pour éditer les directives DirectoryIndex, ServerName, Listen, la prise en comptes des fichiers .htaccess, etc. On peut alors démarrer Apache. $ /usr/local/apache/bin/apachectl start # => Démarrage d'Apache

Installation de PHP

Nous allons maintenant installer différentes versions de PHP que nous ferons cohabiter ensemble. $ wget http://fr2.php.net/get/php-7.0.5.tar.gz/from/this/mirror $ tar xvfz php-7.0.5.tar.gz $ cd php-7.0.5 # => Téléchargement des sources de PHP, unarchivage et déplacement dans le répertoire source $ './configure' '--enable-fpm' '--with-fpm-user=daemon' '--with-fpm-group=daemon' '--prefix=/usr/local/php-70' '--with-config-file-path=/usr/local/php-70' '--with-mysqli=mysqlnd' '--enable-pdo' '--with-pdo-mysql=mysqlnd' '--with-openssl' '--enable-bcmath' '--with-bz2' '--with-pic' '--enable-calendar' '--enable-ctype' '--enable-ftp' '--with-gd' '--with-freetype-dir' '--with-png-dir' '--with-jpeg-dir=/usr' '--with-gmp' '--enable-sockets' '--enable-sysvsem' '--enable-sysvshm' '--disable-debug' '--with-zlib=/usr' '--with-pear' '--enable-simplexml' '--enable-mbstring=all' '--with-pspell' '--with-curl' '--with-xsl' '--with-mcrypt' '--enable-soap' '--enable-zip' '--enable-pcntl' '--with-readline' '--enable-opcache' '--without-pear' '--with-libdir=lib64' $ make # => Compilation de PHP en mode FPM PHP est compilé ici en mode FPM. À noter les paramétrages --prefix et --with-config-file-path. Ils sont importants et vont permettre de parfaitement isoler les différentes versions de PHP entre elles. On peut maintenant installer PHP via la commande make install. Il reste encore quelques opérations de post-installation à effectuer. $ mv /usr/local/php-70/sbin/php-fpm /usr/local/php-70/sbin/php-fpm-70 # => Renommage du binaire php-fpm $ mkdir /usr/local/php-70/extensions # => Création d'un répertoire pour accueillir les extensions dans le répertoire d'installation $ cp modules/opcache.so /usr/local/php-70/extensions/ # => Copie du module opcache.so $ cp php.ini-development /usr/local/php-70/php.ini # => Copie du fichier php.ini-development dans le répertoire d'installation On peut maintenant éditer le fichier php.ini placé dans le répertoire d’installation afin d’initialiser correctement quelques directives comme extension_dir = /usr/local/php-70/extensions, date.timezone = Europe/Paris ou encore charger le cache d’opcode en ajoutant zend_extension = opcache.so. Il reste à dérouler la même procédure avec les différentes version de PHP que l’on désire faire cohabiter: PHP 5.5, PHP 5.6, etc. Il faut juste bien penser à isoler les différentes versions entre elles en jouant avec les paramétrages --prefix et --with-config-file-path lors de la compilation de PHP et bien cibler le bon répertoire d’installation dans la suite des opérations.

Configuration et lancement de PHP en mode FPM

La configuration et le lancement des pools FPM passent par la mise en place de 2 fichiers. Par exemple pour PHP 7.0, un premier fichier que nous appelerons /etc/php-fpm-70.conf, servira à la configuration. [global] pid = /var/run/php-fpm-70.pid error_log = /var/log/php-fpm-70.log [www] user = daemon group = daemon listen = 127.0.0.1:9070 pm = dynamic pm.max_children = 40 pm.start_servers = 10 pm.min_spare_servers = 10 pm.max_spare_servers = 20 pm.max_requests = 1000 chdir = / Bien noter encore ici le soin particulier apporté à l’isolation dans les chemins pid et error_log, mais aussi au niveau listen dans le choix du port réseau à écouter. Il conviendra d’adapter et affiner les autres paramétres en fonction de vos besoins. Un second fichier, que nous appellerons /etc/rc.d/rc.php-fpm-70, servira à lancer le pool. #! /bin/sh ### BEGIN INIT INFO # Provides:          php-fpm # Required-Start:    $remote_fs $network # Required-Stop:     $remote_fs $network # Default-Start:     2 3 4 5 # Default-Stop:      0 1 6 # Short-Description: starts php-fpm # Description:       starts the PHP FastCGI Process Manager daemon ### END INIT INFO prefix=/usr/local/php-70 exec_prefix=${prefix} php_fpm_BIN=${exec_prefix}/sbin/php-fpm-70 php_fpm_CONF=/etc/php-fpm-70.conf php_fpm_PID=/var/run/php-fpm-70.pid php_opts="--fpm-config $php_fpm_CONF" wait_for_pid () {     try=0     while test $try -lt 35 ; do         case "$1" in             'created')             if [ -f "$2" ] ; then                 try=''                 break             fi             ;;             'removed')             if [ ! -f "$2" ] ; then                 try=''                 break             fi             ;;         esac         echo -n .         try=`expr $try + 1`         sleep 1     done } case "$1" in     start)         echo -n "Starting php-fpm "         $php_fpm_BIN $php_opts         if [ "$?" != 0 ] ; then             echo " failed"             exit 1         fi         wait_for_pid created $php_fpm_PID         if [ -n "$try" ] ; then             echo " failed"             exit 1         else             echo " done"         fi     ;;     stop)         echo -n "Gracefully shutting down php-fpm "         if [ ! -r $php_fpm_PID ] ; then             echo "warning, no pid file found - php-fpm is not running ?"             exit 1         fi         kill -QUIT `cat $php_fpm_PID`         wait_for_pid removed $php_fpm_PID         if [ -n "$try" ] ; then             echo " failed. Use force-quit"             exit 1         else             echo " done"         fi     ;;     force-quit)         echo -n "Terminating php-fpm "         if [ ! -r $php_fpm_PID ] ; then             echo "warning, no pid file found - php-fpm is not running ?"             exit 1         fi         kill -TERM `cat $php_fpm_PID`         wait_for_pid removed $php_fpm_PID         if [ -n "$try" ] ; then             echo " failed"             exit 1         else             echo " done"         fi     ;;     restart)         $0 stop         $0 start     ;;     reload)         echo -n "Reload service php-fpm "         if [ ! -r $php_fpm_PID ] ; then             echo "warning, no pid file found - php-fpm is not running ?"             exit 1         fi         kill -USR2 `cat $php_fpm_PID`         echo " done"     ;;     *)         echo "Usage: $0 {start|stop|force-quit|restart|reload}"         exit 1     ;; esac Et voilà. On peut alors lancer notre pool de parseurs PHP 7.0. $ /etc/rc.d/rc.php-fpm-70 start # => Lancement du pool FPM de parseurs PHP 7.0 Comme précédemment, dérouler la même procédure avec les différentes version de PHP que l’on désire faire cohabiter. Voici ce que doit produire la commande pstree avec les versions PHP 5.4, 5.5, 5.6 et 7.0 $ pstree | grep php |-php-fpm-54---10*[php-fpm-54] |-php-fpm-55---10*[php-fpm-55] |-php-fpm-56---10*[php-fpm-56] |-php-fpm-70---10*[php-fpm-70] # => Exécution de la commande pstree permettant de visualiser les pools

Compilation d’une extension PHP

Lorsque l’on compile une extension PHP, le binaire produit dépend de la version de PHP (du Zend Engine). C’est pour cela que le binaire d’une extension compilée pour PHP 5.4 ne fonctionnera pas avec PHP 5.5 ou 5.6, le moteur interne de PHP ayant changé. C’est aussi pour cela que nous avons compilé PHP avec les paramétrages --prefix et --with-config-file-path. Cela va simplifier la compilation de nouvelles extensions. Voici la marche à suivre avec, par exemple, la compilation de xDebug pour PHP 7.0. $ wget https://xdebug.org/files/xdebug-2.4.0.tgz $ tar xvfz xdebug-2.4.0.tgz $ cd xdebug-2.4.0 # => Téléchargement des sources de xDebug, unarchivage et déplacement dans le répertoire source $ /usr/local/php-70/bin/phpize $ ./configure --with-php-config=/usr/local/php-70/bin/php-config $ make # => Compilation de xDebug $ cp modules/xdebug.so /usr/local/php-70/extensions/ # => Copie de l'extension dans le répertoire d'extensions Et voilà, une fois encore, dérouler la même procédure avec les différentes version de PHP en prenant soin de pointer vers les bonnes versions de phpize et php-config.

Un dernier mot sur la mise en oeuvre et la performance

Afin d’activer le parseur de telle ou telle version de PHP, il suffit d’utiliser un simple fichier .htaccess. Par exemple, pour activer le parseur de PHP 7.0. <FilesMatch .php$> SetHandler "proxy:fcgi://127.0.0.1:9070" </FilesMatch> On peut aussi ajouter ces précédentes lignes directement dans le httpd.conf, en global ou au niveau de tel ou tel virtualhost. Rappelons que l’utilisation de PHP en mode FPM implique d’avoir recours à un fichier .user.ini si l’on désire affiner les paramétrages de PHP dans tel ou tel répertoire. En terme de performance, à serveur constant, l’utilisation d’Apache 2.4 et de la SAPI FPM se montre de loin la combinaison la plus performante, comparativement à PHP en module ou en CGI. Cette combinaison fait également globalement jeu égal avec Nginx d’après mes observations et tests de montée en charge.
Article précédent Article suivant