Un cliente che utilizza ancora RHEL 4 ci ha chiesto di predisporre il server web per ospitare, oltre all’applicazione attuale, anche una nuova applicazione basata su Drupal 7.x e quindi PHP 5.3.
La necessità di supportare contemporaneamente PHP 4.3 (utilizzato dalla web application attuale) e 5.3 (per Drupal) ci ha imposto delle notevoli restrizioni: non era possibile installare i pacchetti dai repository legacy esistenti perché avrebbero sovrascritto le precedenti versioni, quindi le possibilità erano due: ricompilare Apache e PHP, oppure estrarre il contenuto dei pacchetti esistenti e creare un’installazione parallela che sfruttasse quanto più possibile il sistema già installato, divergendo solo ove necessario. Abbiamo optato per questa seconda soluzione.
Non disponendo il cliente di un ambiente di test, la prima mossa è stata creare una virtual machine CentOS 4 i386 su cui effettuare tutte le prove del caso. Abbiamo installato un sistema minimale ed aggiunto i pacchetti php, php-gd e php-mysql che sapevamo presenti in staging e produzione.
A questo punto abbiamo scaricato sulla nostra VM il repo file di un repository che disponeva dei pacchetti PHP 5.3 per RHEL 4 e l’abbiamo utilizzato per ottenere la lista degli rpm da scaricare:

# wget http://rpms.famillecollet.com/enterprise/remi.repo
# mv remi.repo /etc/yum.repos.d/
# wget rpms.famillecollet.com/RPM-GPG-KEY-remi
# rpm --import RPM-GPG-KEY-remi
# yum --enablerepo=remi install php php-gd php-mysql php-pdo
[...]

Abbiamo preso nota dei pacchetti che venivano installati dal repository e li abbiamo scaricati in una directory per estrarne i contenuti:

# mkdir php5-rpms
# cd php5-rpms
# wget http://repo.famillecollet.com/enterprise/4 [...]
# mkdir contents
# cd contents
# for file in ../*.rpm ; do rpm2cpio $file | cpio -id ; done
[...]
# ls
etc/  lib/  usr/

Disponevamo dei binari e dei file di configurazione base necessari, che altro ci serviva?

  • Uno script di init per la seconda istanza di Apache e relativo file di configurazione in /etc/sysconfig/
  • Una ServerRoot separata per la seconda istanza di Apache in cui mettere tutti i file di configurazione
  • Un php.ini e una directory php.d separate per la configurazione di PHP
  • Una directory separata per le estensioni PHP in modo che non sovrascrivessero le vecchie

Partiamo impostando un riferimento alla directory in cui abbiamo estratto gli RPM, poi facciamo delle copie dei file attuali ed aggiorniamo la ServerRoot di Apache con i file estratti e ci assicuriamo che la directory dei log sia diversa da quella dell’istanza di default:

# FILES_REPO=/root/php5-rpms/contents
# cp /etc/init.d/httpd /etc/init.d/httpd-php53
# cp /etc/sysconfig/httpd /etc/sysconfig/httpd-php53
# cp -a /etc/httpd /etc/httpd-php53
# cp -a ${FILES_REPO}/etc/httpd/* /etc/httpd-php53/
# mkdir -p /var/log/httpd-php53
# chmod 700 /var/log/httpd-php53
# cd /etc/httpd-php53
# rm logs
# ln -s ../../var/log/httpd-php53 logs

Poi è la volta di PHP. Copiamo il modulo Apache, i relativi file di configurazione (in una nuova directory creata ad-hoc) ed estensioni (anch’esse in una nuova directory) e qualche binario che non dovrebbe sovrascrivere quanto abbiamo già installato:

# cp ${FILES_REPO}/usr/lib/httpd/modules/libphp5.so /usr/lib/httpd/modules/
# mkdir -p /etc/php5
# cp -a ${FILES_REPO}/etc/php.ini ${FILES_REPO}/etc/php.d /etc/php5/
# cp -a ${FILES_REPO}/usr/lib/php /usr/lib/php5
# cp -i ${FILES_REPO}/usr/bin/phar* /usr/bin/
# cp -i ${FILES_REPO}/usr/bin/php-cgi ${FILES_REPO}/usr/bin/phpize /usr/bin/

Manca poco, dobbiamo aggiungere un paio di librerie necessarie ai moduli.

# cp ${FILES_REPO}/usr/lib/libedit.so.0.0.27 /usr/lib/
# cd /usr/lib
# ln -s libedit.so.0.0.27 libedit.so.0

# cp -i ${FILES_REPO}/usr/lib/mysql/libmysqlclient.so.18.0.0 /usr/lib/mysql/
# cd /usr/lib/mysql
# ln -s libmysqlclient.so.18.0.0 libmysqlclient.so.18

# ldconfig

Gli ingredienti ci sono tutti, dobbiamo solo farli “parlare” tra loro. La prima cosa che modificheremo è lo script di init (riporto solo le parti in cui è stato modificato rispetto al default):

if [ -f /etc/sysconfig/httpd ]; then
        . /etc/sysconfig/httpd-php53
fi
[...]
prog=httpd-php53
pidfile=${PIDFILE-/var/run/httpd-php53.pid}
lockfile=${LOCKFILE-/var/lock/subsys/httpd-php53}
[...]
start() {
        echo -n $"Starting $prog: "
        check13 || exit 1
        LANG=$HTTPD_LANG PHP_INI_SCAN_DIR=/etc/php5/php.d daemon $httpd $OPTIONS
[...]

Come vedete le righe modificate sono veramente poche. Abbiamo cambiato il nome del file di configurazione da includere, fatto in modo di creare nomi univoci per il pidfile ed il lockfile e poi abbiamo modificato la linea di comando per includere una variabile che specifica a PHP dove reperire i file .ini relativi alle estensioni.

Nel file di configurazione /etc/sysconfig/httpd-php53 abbiamo cambiato solo le opzioni in modo da specificare una ServerRoot diversa:

OPTIONS="-d /etc/httpd-php53"

A questo punto siamo passati a configurare Apache, prima il file /etc/httpd-php53/conf/httpd.conf cambiando solo ServerRoot e PidFile in modo coerente con quanto avevamo fatto nello script di init e nel sysconfig:

ServerRoot "/etc/httpd-php53"
[...]
PidFile run/httpd-php53.pid

Poi siamo passati a fare un ritocco alla configurazione di PHP in /etc/httpd-php53/conf.d/php.conf, aggiungendo la direttiva PHPINIDir che specifica dove reperire il php.ini:

LoadModule php5_module modules/libphp5.so
PHPINIDir /etc/php5/

Il passo successivo riguarda proprio il php.ini (quello nuovo che abbiamo copiato in /etc/php5/php.ini), in cui dovremo cambiare la direttiva extension_dir:

extension_dir = "/usr/lib/php5/modules/"

A questo punto creiamo uno script php di test e riavviamo il servizio per verificare che tutto sia a posto:

# echo '<?php phpinfo() ?>' > /var/www/html/stardata-test-php53.php
# service httpd-php53 restart
# curl http://localhost/stardata-test-php53.php
[...]

Nell’output dovreste vedere che la versione di PHP è la 5.3 e le estensioni vengono caricate da /usr/lib/php5