Drupal & Docker

Simon Morvan

https://www.drupal.org/u/garphy
@simonmorvan




http://www.icilalune.com/

Drupal

c'est...

...du code PHP, une base SQL,
et des fichiers

Docker

Déploiement et exécution d'applications

  • Isolation
  • Distribution

Containers

Linux CGroups

  • Isole un groupe de processus
  • Système de fichier (~chroot)
  • Réseau
  • ...

Sur une même machine, en partageant le même noyau.

Images Docker

Permettent de regrouper dans un seul ensemble :

  • Bibliothèques de base ("OS")
  • Dépendances de l'application
  • Code de l'application

et le distribuer en lui donnant un nom :

group/name:tag

Cycle complet

  1. build
  2. push
  3. pull
  4. run

Dev / CI   |   Run        

⌨ docker run

root@debian-jessie:~# docker run -ti centos:7 /bin/bash
[root@90d24805dacb /]# ps ax
  PID TTY      STAT   TIME COMMAND
    1 ?        Ss     0:00 /bin/bash
   13 ?        R+     0:00 ps ax
root@debian-jessie:~# ps afx
  PID TTY      STAT   TIME COMMAND
    1 ?        Ss     0:00 /sbin/init
(...)
  429 ?        Ssl    0:03 /usr/bin/docker daemon -H fd://
  474 ?        Ssl    0:00  \_ docker-containerd -l /var/run/docker/libcontainerd/docker-c
 1263 ?        Sl     0:00      \_ docker-containerd-shim 90d24805dacb0a389f163f9811e2df20
 1275 pts/2    Ss+    0:00          \_ /bin/bash

Drupal+Docker

Pourquoi ?

  • Parité
    «ça marche chez moi !»
  • Conflits de version
    PHP 5.x ou PHP7
  • Sécurité et densité
    Isolation sur un même serveur
  • Pré-requis minimes
    Station développeur et/ou Hébergeur

Drupal + Docker

Fabrication d'une image

Contenu de l'image docker

  • Le système de base ("L'OS")
  • Apache, PHP, les modules PHP
  • Drush, Composer & co
  • Le code du projet Drupal
  • MySQL

MySQL: service externe

comme memcached, Solr, Varnish, ...

Debian + Apache + PHP 5.6

There's an image for that

library/php:5.6-apache

Dockerfile

La recette de cuisine de l'image

Similaire à un script shell

Dockerfile : les commandes

  • FROM [image]
  • RUN [cmd]
  • ADD ou COPY [source] [destination]
FROM php:5.6-apache

ADD docker/docker-php-pecl-install /usr/local/bin/

RUN apt-get update && apt-get install -y \
        git \
        imagemagick \
        libcurl4-openssl-dev \
        libfreetype6-dev \
        libjpeg-turbo-progs \
        libjpeg62-turbo-dev \
        libmcrypt-dev \
        libpng12-dev \
        libxml2-dev \
        mysql-client \
        pngquant \
        ssmtp \
        sudo \
        unzip \
        wget \
        zlib1g-dev \
    && docker-php-ext-install \
        bcmath \
        curl \
        exif \
        mbstring \
        mcrypt \
        mysql \
        mysqli \
        opcache \
        pcntl \
        pdo_mysql \
        soap \
        zip \
    && docker-php-ext-configure gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ \
    && docker-php-ext-install gd \
    && docker-php-pecl-install \
        memcache \
        uploadprogress \
    && apt-get clean

RUN echo "memory_limit = 256M" > /usr/local/etc/php/conf.d/custom.ini \
    && echo "date.timezone='Europe/Paris'" >> /usr/local/etc/php/conf.d/custom.ini

RUN cd /usr/local \
    && curl -sS https://getcomposer.org/installer | php \
    && chmod +x /usr/local/composer.phar \
    && ln -s /usr/local/composer.phar /usr/local/bin/composer

RUN cd /usr/local \
    && git clone http://github.com/drush-ops/drush.git --branch master \
    && cd /usr/local/drush \
    && composer install \
    && ln -s /usr/local/drush/drush /usr/bin/drush

RUN a2enmod deflate \
    && a2enmod expires \
    && a2enmod headers \
    && a2enmod mime \
    && a2enmod rewrite

ADD . /var/www/html/

RUN chown -R www-data:www-data sites/default

⌨ docker build

Orchestration

docker-compose

docker-compose.yml

version: "2"
services:
  # Image drupal
  drupal:
    image: mydrupal
    ports:
      - 9000:80
    restart: "always"

  # MySQL server
  mysql:
    image: mysql:5.6
    environment:
      MYSQL_USER: drupal
      MYSQL_PASSWORD: s3cur3
      MYSQL_DATABASE: drupal
      MYSQL_ROOT_PASSWORD: r34llys3cur3

# docker-compose up

Stockage

(durable)

Situations qui amènent à recréer un container

  • Mise à jour (nouvelle image)
  • Déplacement vers un autre host docker
  • Changement de configuration

A retenir : un container est éphémère

Petite question...

Qu'arrive t'il à site/default/files ?

Réponse : ils est perdu !

Solution : les volumes Docker

Dossier ou fichier,
déclaré dans le Dockerfile,
ou à l'exécution du container.

Montage vers un stockage externe au container.

Commande Dockerfile

VOLUME [path]

Déclare le chemin du container dont le stockage doit être externe

VOLUME /var/www/html/sites/default/files

docker-compose.yml

version: "2"
services:
  # Image drupal
  drupal:
    image: mydrupal
    ports:
      - 9000:80
    restart: "always"
    volumes:
      - ./site-files:/var/www/html/sites/default/files

  # MySQL server
  mysql:
    image: mysql:5.6
    environment:
      MYSQL_USER: drupal
      MYSQL_PASSWORD: s3cur3
      MYSQL_DATABASE: drupal
      MYSQL_ROOT_PASSWORD: r34llys3cur3

Configuration

À la mode des 12 facteurs

settings.php fait partie du code.

Variations par environnement ?

«Store config in the environment»

The Twelve-factor app — III. Config
http://12factor.net/config

# MySQL server
mysql:
  image: mysql:5.6
  environment:
    MYSQL_USER: drupal
    MYSQL_PASSWORD: s3cur3
    MYSQL_DATABASE: drupal

settings.php statique

<?php
$databases = array (
  'default' =>
  array (
    'default' =>
    array (
      'database' => 'drupal',
      'username' => 'drupal',
      'password' => 's3cur3,
      'host' => 'mysql',
      'port' => '',
      'driver' => 'mysql',
      'prefix' => '',
    ),
  ),
);

settings.php dynamique

<?php
$databases = array (
  'default' =>
  array (
    'default' =>
    array (
      'database' => getenv('MYSQL_DATABASE'),
      'username' => getenv('MYSQL_USER'),
      'password' => getenv('MYSQL_PASSWORD'),
      'host' => getenv('MYSQL_HOST'),
      'port' => '',
      'driver' => 'mysql',
      'prefix' => '',
    ),
  ),
);

docker-compose.yml

# Image drupal
drupal:
  image: mydrupal:1
  environment:
    DRUPAL_URI: 'http://localhost:9000'
    MYSQL_USER: drupal
    MYSQL_PASSWORD: s3cur3
    MYSQL_DATABASE: drupal
    MYSQL_HOST: mysql
  ports:
    - 9000:80
  restart: "always"
  volumes:
    - ./site-files:/var/www/html/sites/default/files
# MySQL server
mysql:
  image: mysql:5.6
  environment:
    MYSQL_USER: drupal
    MYSQL_PASSWORD: s3cur3
    MYSQL_DATABASE: drupal

Développement

Pourquoi ?

  • Rien à installer
  • Docker
  • Docker-compose
  • Git

C'est tout !

docker pull dev-drupal

PHP, Drush, Composer, Xdebug, ...

Ctrl+S, Ctrl+R, ↻

Le docker build systématique devient fastidieux

Les volumes à la rescousse

pour "monter" les sources dans le container

docker-compose.yml

Developpement local

version: "2"
services:
  web:
    image: lune/dev-drupal
    ports:
      - 3012:80
    environment:
      DRUPAL_URI: 'http://172.17.0.1:3012/'
      MYSQL_ENV_MYSQL_USER: drupal
      MYSQL_ENV_MYSQL_PASSWORD: drup4l
      MYSQL_ENV_MYSQL_DATABASE: drupal
    volumes:
      - ./www:/var/www/html
  mysql:
    image: mysql:5.6
    environment:
      MYSQL_ROOT_PASSWORD: jobs-at-icilalune.com
      MYSQL_USER: drupal
      MYSQL_PASSWORD: drup4l
      MYSQL_DATABASE: drupal
https://hub.docker.com/r/lune/dev-drupal/

En bref

Simplification :

  • du déploiement ;
  • du développment.

Docker en 4 étape faciles

  • docker build
  • docker push
  • docker pull
  • docker-compose up

Merci !

Des questions ?

Ici la Lune recrute