Wordpress en mode Docker
J’ai eu à installer un blog Wordpress il y a quelques temps pour une connaissance. N’étant pas emballé par la traditionnelle installation, je me suis dit qu’il serait bon de voir comment avait évolué Docker et ce que je serais capable d’en faire plus d’un an après mes premiers essais.
Installation de Docker
Je procède à l’installation de Docker sur une Ubuntu 14.04 pour ne pas changer, l’essentiel étant d’avoir un noyau d’une version supérieure à la 3.10
. La procédure d’installation elle-même est très simple et la documentation complète. Rien de plus à ajouter !
Dockerisation de Wordpress
La façon la plus simple d’obtenir un Wordpress fonctionnel et dockerisé est certainement de partir d’une image officielle disponible sur le Hub Docker.
Malheureusement, aucune de ces images ne me convient. La plupart d’entre elles embarquent allégrement toute la pile (Wordpress, MySQL, PHP) dans un seul conteneur, ce qui est contraire à l’esprit Docker où il est prévu qu’un conteneur ne doit faire tourner qu’un seul processus.
De plus, l’image officielle de Wordpress, qui se rapproche le plus de ce que je veux, ne comprend pas les extensions PHP nécessaires à l’installation que j’ai en tête.
Voulant respecter le principe d’un processus par conteneur et voulant quelques options non disponibles dans les images officielles, je me suis donc tourner vers Docker Compose, qui permet de définir une application par l’ensemble des conteneurs la composant.
Docker Compose fait partie avec Swarm et Machine entre autres de qui s’appelle désormais la Docker Toolbox. Mais ne nous écartons pas de notre sujet principal !
Wordpress avec Docker Compose
Essayons de rentrer dans la logique qui va permettre de composer mon application en décrivant ce dont j’ai besoin pour motoriser un blog Wordpress.
Les options dépendent des goûts de chacun mais en ce qui me concerne, mon setup de référence pour Wordpress reste :
- Un serveur MySQL
- Un serveur Memcache
- Un serveur PHP-FPM, qui contient les sources de Wordpress
- Un serveur Nginx
soit quatre processus et donc quatre conteneurs !
Installation de Docker Compose
L’installation de Docker Compose est simple
curl -L https://github.com/docker/compose/releases/download/VERSION_NUM/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
il est temps de traduire en instructions, directives Docker Compose la description applicative faite préalablement.
Docker Compose utilise un fichier au format YAML nommé par défaut docker-compose.yml
. Il contient la déclaration des briques composant l’application à dockeriser. Nous allons construire progressivement ce fichier en commentant chacune des directives.
Un serveur MySQL
Chez moi, MySQL c’est MariaDB ! Il fonctionne sans souci avec les dernières versions de Wordpress.
mysql:
image: mariadb
restart: always
volumes:
- ./var/mysql:/var/lib/mysql
environment:
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: password
MYSQL_ROOT_PASSWORD: password
mysql
est le nom du service fourni à l’application.image
permet de spécifier l’image qui va être utilisé pour construire le conteneur.restart
permet comme son nom l’indique de démarrer automatiquement le conteneur lors d’un reboot du serveur Docker par exemple.volumes
permet de définir un point de montage dans le conteneur qui pointe vers un dossier du serveur Docker.environment
permet de passer n’importe quelle variable en variable d’environnement au moment de l’exécution du conteneur.
Pas de quoi se faire mal à la tête il me semble, tout est plutôt explicite en fait ! Et vous pouvez même utiliser un éditeur en ligne pour vous aider dans l’écriture de ce fichier.
Un serveur Memcache
Rien de bien compliqué non plus côté Memcache
memcached:
image: memcached
restart: always
Ben oui, c’est tout !
Un serveur PHP
L’image officielle Wordpress contient plusieurs variantes qui permettent au choix une utilisation avec Apache ou PHP-FPM et qui permettent de spécifier une version particulière de PHP. Mais aucune ne contient les extensions PHP dont j’ai besoin comme par exemple memcache. Il faut donc construire une image spécifique à partir de celle qui est la plus proche de celle souhaitée.
Je passe donc par un Dockerfile
qui va contenir l’ensemble des commandes qui dérivent de l’image officielle.
FROM wordpress:fpm
RUN apt-get update && apt-get install -y libmemcached-dev tidy csstidy
RUN curl -o memcached.tgz -SL http://pecl.php.net/get/memcached-2.2.0.tgz \\
&& tar -xf memcached.tgz -C /usr/src/php/ext/ \\
&& rm memcached.tgz \\
&& mv /usr/src/php/ext/memcached-2.2.0 /usr/src/php/ext/memcached
RUN curl -o memcache.tgz -SL http://pecl.php.net/get/memcache-3.0.8.tgz \\
&& tar -xf memcache.tgz -C /usr/src/php/ext/ \\
&& rm memcache.tgz \\
&& mv /usr/src/php/ext/memcache-3.0.8 /usr/src/php/ext/memcache
RUN curl -o zip.tgz -SL http://pecl.php.net/get/zip-1.13.1.tgz \\
&& tar -xf zip.tgz -C /usr/src/php/ext/ \\
&& rm zip.tgz \\
&& mv /usr/src/php/ext/zip-1.13.1 /usr/src/php/ext/zip
RUN docker-php-ext-install memcached
RUN docker-php-ext-install memcache
RUN docker-php-ext-install zip
Rien de bien méchant, je me contente d’ajouter quelques modules PHP dont j’aurais besoin avec le plugin de cache que j’utilise avec Wordpress. C’est fait à la sauce Docker avec l’instruction docker-php-ext-install
.
Ensuite, dans mon service, je remplace l’instruction image
par build
et je pointe vers le répertoire qui contient le Dockerfile
, ici wordpress
.
wordpress:
build: wordpress
restart: always
links:
- mysql
- memcached
environment:
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: password
WORDPRESS_DB_NAME: wordpress
Une nouvelle instruction est apparue et elle est d’une puissance redoutable.
links
permet en effet de raccorder deux conteneurs entre eux. Ainsi, le service wordpress
va donc être lié au service mysql
et memcached
. plus besoin de connaître l’adresse IP du serveur Memcache ou MySQL, et ça tombe bien puisque ces adresses sont assignées dynamiquement par Docker au démarrage d’un conteneur.
Un serveur Nginx
Rien de bien nouveau avec le serveur Nginx si ce n’est l’instruction ports
, qui comme son nom l’indique permet d’exposer un ou plusieurs ports d’un conteneur vers le vaste monde. Sans ce type d’instruction, le serveur Nginx ne serait pas joignable depuis Internet.
nginx:
image: nginx
restart: always
ports:
- 80:80
- 443:443
links:
- wordpress
volumes_from:
- wordpress:ro
volumes:
- ./etc/nginx/conf.d:/etc/nginx/conf.d:ro
- ./var/log/nginx:/var/log/nginx
Et le monitoring alors ?
Docker apporte son lot de changements au niveau supervision. Il devient difficile d’embarquer un agent dans un conteneur puisqu’il faudra du coup dériver toutes les images depuis celles du Hub pour leur ajouter au niveau Dockerfile
les instructions nécessaires au provisionnement de l’agent dans le conteneur. Et cela fera un processus de trop !
Heureusement, quelques projets sortent pour permettre de faire ça proprement et notamment Cadvisor de Google.
Le plus beau, c’est que nous allons faire tourner Cadvisor dans un conteneur et qu’il va permettre la supervision de l’ensemble de ceux-ci.
Il faut donc ajouter un nouveau service au fichier docker-compose.yml
cadvisor:
image: google/cadvisor
ports:
- 8080:8080
restart: always
volumes:
- /:/rootfs:ro
- /var/run:/var/run:rw
- /sys:/sys:ro
- /var/lib/docker/:/var/lib/docker:ro
Le résultat est immédiat et plutôt flatteur.
Voilà une supervision temps réel de base des conteneurs à peu de frais. Je vois d’un seul coup d’œil la consommation CPU, mémoire, réseau, disque de chacun des conteneurs démarrés, le tout dans une interface plutôt agréable. De plus, il est possible d’envoyer l’ensemble des métriques dans InfluxDB. On se garde ça sous le coude pour une autre fois ?
Mais cela ne suffit pas. Ce n’est pas parce que tout roule côté serveur que le site est accessible. J’ajoute donc naturellement ce nouveau Wordpress dockerisé sur Check my Website, histoire de vérifier qu’il est bien disponible depuis l’extérieur.
Et parce que c’est une fonctionnalité dificile à avoir sur une solution de supervision classique et que l’application ainsi dockerisé le vaut bien, une topologie complète applicative et mise à jour en temps réel obtenue grâce à Weave Scope.
Le résultat final
le résultat final est ce fichier docker-compose.yml qui contient la déclaration de l’ensemble des briques nécessaires à Wordpress.
nginx:
image: nginx
restart: always
ports:
- 80:80
- 443:443
links:
- wordpress
volumes_from:
- wordpress:ro
volumes:
- ./etc/nginx/conf.d:/etc/nginx/conf.d:ro
- ./var/log/nginx:/var/log/nginx
wordpress:
build: wordpress
restart: always
links:
- mysql
- memcached
environment:
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: password
WORDPRESS_DB_NAME: wordpress
mysql:
image: mariadb
restart: always
volumes:
- ./var/mysql:/var/lib/mysql
environment:
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: password
MYSQL_ROOT_PASSWORD: password
memcached:
image: memcached
restart: always
cadvisor:
image: google/cadvisor
ports:
- 8080:8080
restart: always
volumes:
- /:/rootfs:ro
- /var/run:/var/run:rw
- /sys:/sys:ro
- /var/lib/docker/:/var/lib/docker:ro
Gestion du cycle de vie
Pour démarrer l’ensemble de la pile applicative ainsi déclarée, il suffit d’un
docker-compose up
ou
docker-compose start
pour le même résultat mais en arrière plan.
Vous êtes sûrs que je vous donne la commande pour arrêter l’application ? j’ai envie de dire stop
à la facilité !
Mettre à jour tout ce petit monde est d’une simplicité redoutable et c’est certainement un des gros avantages de Docker.
docker-compose pull
docker-compose build
docker-compose up -d
Tout est mis à jour sans interruption de services, la classe !
Enfin, le jour ou vous en aurez marre de votre Wordpress, un simple
docker-compose rm
supprimera les conteneurs et avec l’option -v
associée, supprimera les volumes associés.
Il est bien sûr toujours possible d’améliorer ce setup. L’intérêt dans le contexte docker est qu’on ne repart pas à zéro comme trop souvent. Ce qui est décrit permet de capitaliser pour la suite.
Par exemple, comme indiqué au niveau bonnes pratiques dans la documentation de Docker, il serait possible de créer un conteneur uniquement destiné au stockage des données Wordpress et qui seraient monté avec l’instruction volumes_from
depuis les services en ayant besoin soit wordpress
et nginx
.
Sentiment final
L’éco-système Docker a beaucoup évolué en un et demi, c’est le moindre que l’on puisse dire. L’outil est désormais beaucoup plus mature et simple à prendre en main.
J’aime beaucoup le format du fichier docker-compose ou il y a finalement assez peu de choses à déclarer pour avoir une description plutôt complète d’une application.
Une fois que l’on a goûté au workflow proposé par Docker, c’est difficile de s’en passer !
Edit: 17/05/2016
Pour illustrer cet article nous avons mis à disposition l’ensemble de l’arborescence sur un Git.