J’avais pensé intituler cette note LAMP is dead, long life Docker! mais le LAMP n’est pas vraiment mort. Il se transforme sous l’impulsion de Docker.

Introduction

Nous allons voir ici comment conteneuriser avec Docker une application existante de type LAMP. Pour information, cette application est réelle, tourne en production et se compose :

  • D’un serveur MySQL v5.5.35 administré via phpMyAdmin
  • D’un serveur Apache 2.2.22 hébergeant une application web PHP v5.4.4-14

Création des conteneurs

La base de données MySQL

Le démarrage du conteneur MySQL est assez simple :

docker run --name mysite-db -e MYSQL_ROOT_PASSWORD=secret-pwd -v /mnt/data/mysite/mysql:/var/lib/mysql -d mysql:5.5

Vous remarquez que les données sont persistées dans un volume sur la machine host dans /mnt/data/mysite/mysql.

Il est possible de se connecter à cette base via un conteneur également :

docker run -it --rm --link mysite-db:mysql mysql:5.5 sh -c 'exec mysql -h"$MYSQL_PORT_3306_TCP_ADDR" -P"$MYSQL_PORT_3306_TCP_PORT" -uroot -p"secret-pwd"'

Maintenant, nous devons restaurer les données récupérées de l’environnement de production. Pour cela, il faut créer la database mysite puis exécuter le script dump.sql :

echo "create database mysite;" > /mnt/data/mysite/scripts/init.sql
docker run -it --rm --link mysite-db:mysql -v /mnt/data/mysite/scripts:/scripts mysql:5.5 sh -c 'exec mysql -h"$MYSQL_PORT_3306_TCP_ADDR" -P"$MYSQL_PORT_3306_TCP_PORT" -uroot -p"secret-pwd" < /scripts/init.sql'
docker run -it --rm --link mysite-db:mysql -v /mnt/data/mysite/dumps:/scripts mysql:5.5 sh -c 'exec mysql -h"$MYSQL_PORT_3306_TCP_ADDR" -P"$MYSQL_PORT_3306_TCP_PORT" -p mysite -uroot -p"secret-pwd" < /scripts/dump.sql'

Après avoir démarré notre serveur MySQL dans un conteneur Docker puis créé la base et enfin inséré les données, nous allons démarrer un conteneur phpMyAdmin :

docker run -d --link mysite-db:mysql -e MYSQL_USERNAME=root --name mysite-pma -p 8080:80 corbinu/docker-phpmyadmin

L’application phpMyAdmin est maintenant accessible sur la machine host avec le port 8080 et donc à l’URL suivante : http://localhost:8080. Vous avez sûrement deviné que le mot de passe est “secret-pwd”.

Notre première étape est terminée et s’est révélée assez simple. Passons donc à l’application web en PHP.

Application web en PHP

En général, il faut privilégier les images Docker officielles. Cependant, cette application n’utilisant pas le driver PDO pour la connexion à MySQL, nous avons rencontré quelques difficultés avec l’image officielle. Nous allons donc utiliser une image alternative : d11wtq/php.
De plus, l’application nécessite l’installation d’ImageMagick.

Ne souhaitant pas créer de nouvelle image dans un premier temps, nous allons personnaliser le container directement à son lancement :

docker run -d --name mysite-www -p 80:8080 --link mysite-db:mysql -v /mnt/data/mysite/www:/www/htdocs -v /mnt/data/mysite/apache/conf.d:/www/httpd.conf.d d11wtq/php bash -c "sudo apt-get update && sudo apt-get -y install ImageMagick && apachectl -d /usr/local -f /www/httpd.conf -DFOREGROUND"

Que permet cette commande ?

  • Démarrage du conteneur à partir de l’image d11wtq/php
  • Exposition du port 8080 d’Apache sur le port 80 de la machine host
  • Utilisation du conteneur MySQL “mysite-db” comme base de données “mysql”
  • Montage des volumes /www/htdocs pour les scripts PHP (et autres ressources web) et /www/http.conf.d pour la configuration Apache
  • Installation de ImageMagick

L’application phpMyAdmin est maintenant accessible sur la machine host avec le port 80 et donc à l’URL suivante : http://localhost.

Cette méthode n’est pas très élégante, ni performante car à chaque démarrage du conteneur, APT va mettre à jour ses indexes et installer la dernière version d’ImageMagick. Le temps de démarrage ne sera donc pas immédiat.

Il faut donc créer une image personnalisée à partir du Dockerfile suivant :

FROM d11wtq/php
RUN apt-get update \
	&& apt-get install -y --no-install-recommends ImageMagick \
	&& rm -rf /var/lib/apt/lists/* \
	&& apt-get clean
EXPOSE 8080
CMD ["apachectl", "-d", "/usr/local", "-f", "/www/httpd.conf", "-D", "FOREGROUND"]

Ensuite, créer notre image personnalisée avec Docker :

docker build -t mycompany/php .

Et enfin démarrer le conteneur de notre application web :

docker run -d --name mysite-www -p 80:8080 --link mysite-db:mysql -v /mnt/data/mysite/www:/www/htdocs -v /mnt/data/mysite/apache/conf.d:/www/httpd.conf.d mycompany/php

Démarrage rapide

Maintenant que tous les conteneurs ont été créés, leur démarrage est extrêmement simplifié :

docker start mysite-db mysite-www mysite-pma

Conclusion

Nous avons vu comment créer assez simplement et très rapidement quelques conteneurs pour faire tourner un LAMP et l’administrer. Vous êtes maintenant en possession d’une architecture LAMP multi-tenante et capable de déployer à l’infini votre solution pour vos clients.

De plus, vous allez pouvoir tester de façon assez simple la migration des applicatifs que vous utilisez (Apache, PHP, MySQL, phpMyAdmin, etc…) en jouant sur les versions des images. Le retour arrière étant quasi instantané.

Aller plus loin ?

  • Utilisation de docker-compose pour lier tous ces conteneurs automatiquement.
  • Mise en place d’un container Apache reverse proxy pour n’avoir qu’un port d’écoute sur la machine host.
  • Utilisation d’un conteneur de données pour la persistance de MySQL

En attendant de vous proposer la conteneurisation d’une architecture un peu plus complexe, qu’allez-vous conteneuriser maintenant ?