Monter un environnement autour de Drupal avec Docker

Créé le 09/08/2016

Dernière mise à jour le 10/06/2018

Étiquettes

Voici un retour d'expérience sur ma première utilisation réelle de Docker où je l'ai utilisé pour monter facilement un environnement de développement pour la refonte sous Drupal 8 du site drupal.fr ainsi que le socle Drupalcamp.

Étant un utilisateur récent de Docker, n'hésitez pas à me contacter ou à poster un commentaire pour me corriger en cas de besoin.

L'environnement comprendra :

  • un serveur Apache avec PHP 7

  • un serveur MySQL

  • un serveur Redis

  • un serveur SolR (drupal.fr uniquement)

  • un serveur Varnish

  • un mail catcher

Qu'est ce que Docker ?

Docker est une solution de virtualisation basée sur les Linux Containers (LXC) (EDIT : Docker utilise désormais https://runc.io à la place de LXC, merci pour vos remarques :) ). Il permet d'exécuter des applications dans des conteneurs isolés.

Les conteneurs ne contiennent pas de système d'exploitation. Ils s'appuient sur le noyau Linux installé sur la machine hôte, d'où le fait qu'il n'est pas possible d'émuler un système Windows ou Mac dans un conteneur Docker.

Pour fabriquer un conteneur, il suffit d'écrire les étapes de fabrication dans un fichier Dockerfile puis de construire une image Docker à partir de ce fichier Dockerfile.

À chaque étape, Docker enregistre le résultat de l'étape dans un binaire avec un checksum, ainsi que l'identifiant de l'étape précédente afin de lier les binaires entres eux. Les étapes porte le terme de "Layers". Cela permet d'éviter de reconstruire des étapes si elles sont restées inchangées dans le fichier Dockerfile. Une image Docker s'appuie sur une autre image contenant déjà une bonne partie de ce qu'il vous faut. Sinon, il est toujours possible de partir de l'image scratch qui est une image vide à partir de laquelle sont issues les images des différentes distributions Linux par exemple. Tout dépend de le rapport contrôle / temps de préparation que vous avez envie de consacrer à la fabrication de vos images.

Une fois l'image prête, il est possible de l'exécuter. Tout ce qui sera fait dans ce conteneur sera perdu lors de sa destruction.

Il est ensuite possible de pousser ces images Docker sur le hub docker https://hub.docker.com ou sur un registre Docker installé localement. Ou vous pouvez très bien les conserver uniquement sur votre machine.

Docker Compose

Docker Compose est une surcouche à Docker. Elle permet de facilement orchestrer un ensemble de conteneurs entre eux.

Par exemple, avec Docker uniquement, la commande pour lancer plusieurs conteneurs avec toutes les options qui vont bien, les lier entre eux, etc. fait plusieurs lignes et est assez illisible.

Il est toujours possible de la mettre dans un script versionné. Mais avec Docker Compose, il est possible de mettre toutes ces instructions dans un fichier docker-compose.yml (facilement surchargeable) qui est plus simple à lire et de simplement lancer la commande "docker-compose up".

De plus Docker Compose va :

  • créer un sous-réseau pour chaque fichier docker-compose.yml (ou pour chaque projet si on compte un fichier docker-compose.yml par projet),

  • placer les conteneurs dans ce sous-réseau et leur donner des alias dans ce sous-réseau,

  • nommer les conteneurs pour être facilement accessible (sinon Docker donne un nom aléatoire au conteneur si aucun nom n'est précisé)

  • si un conteneur existe déjà, Docker Compose sait s'il doit le détruire et en reconstruire un autre si l'image a changé ou s'il peut redémarrer le conteneur existant.

Installation sur Debian

Instructions d'installation du Docker Engine : https://docs.docker.com/engine/installation/linux/debian

Instructions d'installation de Docker Compose : https://docs.docker.com/compose/install

Le fichier docker-compose.yml

version: "2"

services:
  web:
    image: florenttorregrosa/docker-drupal-dev:php7
    depends_on:
      - mysql
      - redis
      - mail
      - solr
    volumes:
      - .:/project
    networks:
      default:
        ipv4_address: 172.18.0.2

  varnish:
    image: florenttorregrosa/docker-varnish:latest
    depends_on:
      - web
    environment:
      VCL_CONFIG: /varnish-drupal/varnish.vcl
    volumes:
      - ./conf/varnish:/varnish-drupal
    networks:
      default:
        ipv4_address: 172.18.0.3

  mysql:
    image: mysql:5.6
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_USER: drupal
      MYSQL_PASSWORD: drupal
      MYSQL_DATABASE: drupal
    volumes:
      - ./data/db:/var/lib/mysql
    networks:
      default:
        ipv4_address: 172.18.0.4

  solr:
    image: solr:6.1.0-alpine
    volumes:
      - ./conf/solr:/solr-drupal/conf
    entrypoint:
      - docker-entrypoint.sh
      - solr-precreate
      - drupal
      - /solr-drupal
    networks:
      default:
        ipv4_address: 172.18.0.5

  ​redis:
    image: redis:3.2.1-alpine
    networks:
      default:
        ipv4_address: 172.18.0.6

  mail:
    image: djfarrelly/maildev
    networks:
      default:
        ipv4_address: 172.18.0.7

networks:
  default:
    driver: bridge
    ipam:
      driver: default
      config:
        - subnet: 172.18.0.0/16
          gateway: 172.18.0.1

Customisation des IPs

Il n'est pas obligatoire de fixer le sous-réseau ainsi que les adresses IP des conteneurs. Ce qui se fait en général (de ce que j'ai pu voir), ce sont des redirections de ports.

Personnellement, je préfère éviter les redirections de ports afin de pouvoir faire facilement tourner plusieurs environnements avec une configuration identique mais sur des sous-réseaux différents (socle Drupalcamp et drupal.fr).

En effet, Docker vient avec un sous-réseau par défaut accessible sur 172.17.0.1 et si vous faites une redirection de port, vous pourrez accéder au port de votre conteneur sur 172.17.0.1:port_redirigé. Sauf que les redirections de port, ce n'est pas trop mon délire, surtout si derrière je veux pouvoir utiliser XDebug facilement.

J'ai donc fixé le sous-réseau ainsi que les adresses IP afin d'éviter d'avoir à inspecter les sous-réseaux pour savoir sur quelle IP accéder au site. Car l'ordre de démarrage des conteneurs dans votre docker-compose.yml n'est pas fixe, même si Docker Compose démarre les conteneurs dans le bon ordre en fonction de leur dépendances indiquées.

Conteneur Web

Image initiale afin d'avoir PHP 7 et Apache : https://hub.docker.com/_/php

Image afin d'avoir un environnement avec Drush, Composer et des libraries PHP nécessaires : hub.docker.com/r/florenttorregrosa/docker-drupal

Image pour avoir un environnement avec des outils de développements comme Xdebug, Coder et la Drupal Console : hub.docker.com/r/florenttorregrosa/docker-drupal-dev

Images forkées de https://github.com/icilalune puis que j'ai légèrement modifiées.

On monte un volume sur le dossier du projet. Et on s'attend à ce que le site soit dans un sous-dossier www par rapport au dossier du projet.

Monter un volume signifie que le dossier sur la machine hôte sera accessible dans le conteneur. Exemple :

volumes :
  - .:/project

Signifie que le dossier courant va être monté dans le dossier /project dans le conteneur.

Monter un volume sur les sources permet de faire facilement des modifications dans les sources et que ces modifications soient prises en compte dans le conteneur sans avoir à le reconstruire.

Pour des conteneurs destinés à la production, les sources peuvent être ajoutées dans le conteneur et seul le dossier files peut être monté sur un volume par exemple.

Conteneur Mysql

https://hub.docker.com/_/mysql

Afin de conserver les données de la base de données, on monte un volume. Et on définit des variables d'environnement.

Ce serait bien d'avoir une version avec Alpine qui est une distribution Linux ultra légère.

Conteneur Redis

https://hub.docker.com/_/redis

Utilisation du module Redis. Modification du fichier settings.php afin d'utiliser ce backend de cache.

Il a fallu compiler PhpRedis dans le conteneur web, car pour l'instant PhpRedis n'est pas dans les paquets pour PHP 7. Une alternative à PhpRedis est la librairie predis mais la version Drupal 8 du module Redis ne la supporte pas encore.

J'ai également regardé du côté MemCached mais niveau Drupal 8, les modules pour la prise en charge sont encore en phase de développement et il aurait également fallu compilé ou faire des détours pour avoir PHP memcache avec PHP 7. De plus, le conteneur officiel Redis étant plus utilisé que celui de Memcached, j'ai préféré partir sur Redis.

Conteneur SolR

https://hub.docker.com/_/solr

On monte un volume afin de rendre accessible dans le conteneur la configuration SolR utilisée. Pour obtenir la configuration SolR, j'ai récupéré la configuration par défaut et ajouté celle fournie par le module Search API Solr Search.

Afin de créer un "core" SolR, on exécute la commande solr-precreate fournie dans l'image SolR en lui précisant le nom du core à créer, ici drupal, et l'emplacement des fichiers de configuration.

J'aurai aimé monté un volume afin de conserver les données de l'index comme pour le conteneur MySQL, mais, je ne sais pas si c'était dû à mes tests, cela posait des problèmes de droits et le core ne se créait pas bien.

Conteneur Varnish

hub.docker.com/r/florenttorregrosa/docker-varnish

Mix entre https://github.com/million12/docker-varnish que je trouve bien niveau points d'entrées pour interagir avec le Varnish et https://github.com/nlhkh/docker-varnish pour voir comment installer Varnish sur Alpine.

On monte un volume afin d'ajouter sa propre conf Varnish dans le conteneur et on indique dans les variables d'environnement du conteneur le chemin vers le fichier de conf Varnish.

J'ai utilisé la configuration Varnish indiquée sur le module Varnish Purge où la chose à changer est l'hôte où il suffit d'indiquer "web".

Au niveau du site Drupal, le module Varnish n'étant pas encore prêt pour Drupal 8, j'ai utilisé les modules Purge et Varnish Purge (qui s'appelle en réalité varnish_purger attention).

Mais je pense avoir soit mal configuré les modules, soit mal configuré le Varnish car les caches Varnish n'étaient pas vidés par Drupal. En tout cas dans les headers HTTP j'avais constamment un "Purge-Cache-Tags" à MISS. Il faudra que je reprenne ça.

Conteneur Mail

https://hub.docker.com/r/djfarrelly/maildev

RAS. Interface très agréable pour visualiser les mails interceptés. En TODO, peut être voir les options de manière à avoir un relay de paramétré et faire reprendre aux mails leurs envoi initial.

Prochaines étapes

Je trouve les images pour le serveur web un peu grosses (entre 800 et 900 Mo). J'aimerai bien voir l'utilisation d'Alpine afin de réduire cette taille.

De plus, j'aimerai séparer le PHP d'Apache afin d'avoir des conteneurs différents pour PHP et le serveur Web. Le serveur Web pourrait alors être changé plus facilement pour utiliser Nginx par exemple.

Pour une utilisation en production, je jetterai un œil du côté de Swarm ou Traefik.

Documentation :

Remerciements :

Merci à garphy et Anaethelion pour leur introduction de Docker et Docker Compose au Drupalcamp Nantes 2016, avec une conférence le samedi et l'atelier Docker le dimanche. Ce qui m'a permis d'avoir une base de ficher docker-compose.yml

 

Note 10/06/2018 : Il y a eu réorganisation de mes images Docker. Cette réorganisation est détaillée dans l'article Réorganisation de mes images Docker et mise en place builds automatisés. Les liens de cet article pointant vers des dépôts Git ou Docker supprimés ont été retirés.

Commentaires

Soumis par Anaethelion (non vérifié) le mer, 08/10/2016 - 11:01 - Permalien

Ah ça fait tellement plaisir de voir cet article sortir. :)Deux points :

- Docker est basé sur les cgroups, LXC est aussi basé sur les cgroups, ce dernier peut être utilisé comme backend de Docker. En utilisation classique Docker utilise dorénavant runc (https://runc.io/)
- Dans le but d'alléger encore un peu le tout j'utiliserai MailHog (https://hub.docker.com/r/diyan/mailhog/tags/ par ex.) qui a une image Docker d'un poids ridicule.

L'incompressible sera Solr, passer à Elasticsearch réduira de moitié le poids du container mais ce n'est à priori pas prêt pour Drupal 8...

Si tu veux en discuter surtout n'hésite pas ! \o/
Si

Merci de ton commentaire :)

  • En effet je n'ai pas parlé des cgroups et de comment fonctionne Docker exactement car je ne suis pas familier avec, merci de la précision.
  • Merci de la recommandation, je jetterai un oeil à Mailhog, c'est vrai que l'image est 2 fois plus petite que Maildev, même si ça va, c'est déjà petit :) (6 Mo vs 12 Mo). De plus, Mailhog est utilisé dans https://www.drupalvm.com. Il y aussi le http://pimpmylog.com de Drupalvm que j'ai envie de récupérer, mais je ne sais pas trop si c'est bien utile et si ça s'utilise bien et facilement avec Docker.
  • En effet, le Solr qui fait presque 200 Mo alors qu'il est sous Alpine ça fait drôle. En effet ElasticSearch sous Drupal 8 je n'ai pas encore testé mais déjà quand on voit qu'il y a 2 modules avec intégration pour Search API, déjà on se demande lequel choisir... Search API Elasticsearch et Elasticsearch Connector.
  • Faudra que je vois aussi pour versionner la conf apache et faire un petit volume pour ou l'ajouter dans le build de l'image.

Ça fait à peine plus de 2 mois que je me sers de Docker, pour l'instant je découvre. D'ici le prochain camp je pense que ça aura mûri et ce sera avec plaisir d'avoir des discussions sur Docker. :)

Soumis par Tibar (non vérifié) le mer, 08/31/2016 - 17:30 - Permalien

Merci Flter pour cet article !Tout n'est pas encore clair pour moi, notamment au niveau des volumes, mais bon sachant que j'ai passé en tout et pour tout une toute petite heure sur docker pour le moment on va dire que c'est normal.

Juste pour info, même si tu le sais sans doute déjà, il y a des images officielles drupal pour docker, qui pour petit projet peuvent convenir je pense.

https://hub.docker.com/_/drupal/

A bientôt ;-) !

Merci pour ton commentaire :)

Oui, la première fois que j'ai voulu utiliser Docker, j'ai cherché "Docker Drupal" et j'étais tombé sur cette image et sur des articles de blog qui s'en servaient ou en avaient fait des dérivés.

Sauf qu'à mes premières heures de Docker, je ne comprenais pas grand chose (normal :D ) et surtout j'avais vu que l'image officielle Docker Drupal est plutôt faite pour tester rapidement un module (ou Drupal) par exemple ou pour faire une démo plus que pour du gros développement.

Pour les autres images officielles du type wordpress, joomla, odoo, etc., je pense que c'est pareil et qu'il vaut mieux s'en servir également pour des tests. Si on doit travailler sur ces applis et y apporter une valeur ajoutée, là je pense qu'il vaut mieux faire sa propre image avec le code en dehors par exemple.

D'où la distinction entre :

les images Docker où on a peu de "valeur ajoutée" et à utiliser telles quelles. Par exemple, Varnish ou Solr, une fois qu'on a trouvé comment faire pour leur faire utiliser la configuration que l'on veut, les images officielles conviennent très bien, pas la peine de reprendre la manière dont l'outil est installé.

Et les images où on va vraiment travailler, dans l'image officielle Drupal quand on regarde le Dockerfile, on voit qu'il y a le minimum d'installé, il n'y a pas Drush par exemple.

À bientôt :) !

Soumis par mad53 (non vérifié) le mar, 03/06/2018 - 17:31 - Permalien

Pourrais-je en savoir plus sur comment compiler phpredis concrétement comme tu l'indique, quelle config faut-il mettre exactement dans settings.php ?Et pour varnish pourrais-je savoir comment modifié le vcl de varnish ?

Depuis l'écriture de l'article, j'ai créé un dépôt https://github.com/FlorentTorregrosa/docker-drupal-project pour servir de base de projet.

Je vous invite à regarder sa structure.

Pour la compilation PhpRedis, voir ce fichier : https://github.com/FlorentTorregrosa/docker-drupal-project/blob/8.x/doc…

Pour le settings.php : https://github.com/FlorentTorregrosa/docker-drupal-project/blob/8.x/con…

Pour Varnish, c'est indiqué dans l'article par rapport au fichier docker-compose.yml : 

On monte un volume afin d'ajouter sa propre conf Varnish dans le conteneur et on indique dans les variables d'environnement du conteneur le chemin vers le fichier de conf Varnish.

En réponse à par Panoplie (non vérifié)

Soumis par ftorregrosa le dim, 05/20/2018 - 17:51 - Permalien

Bonjour,

La Drupal console n'est pas ajoutée lors de la construction de l'image. Elle est ajoutée en dépendance de développement dans le fichier composer.json (https://github.com/FlorentTorregrosa/docker-drupal-project/blob/8.x/com…)

"require-dev": {
...
  "drupal/console": "1.*",
...
},
  1. Une fois connecté au conteneur Docker : docker-compose exec web /bin/bash
  2. Il faut se placer par exemple à la racine du projet : cd /project
  3. Lancer la Drupal console : ./vendor/bin/drupal

Par rapport à l'organisation de vos conteneurs, qui m'est inconnue, peut être que cela ne fonctionnera pas. En tout cas, voici comment je procède avec mon installation.

Ajouter un commentaire