Le 03/06/2016

Comment utiliser Docker avec Magento ?

Aujourd'hui on va parler de Docker, appliqué à Magento évidemment mais vous pourrez adapter ce tutoriel à n'importe quel domaine.

Tout a commencé pour moi il y a quelques mois, après avoir regardé une conférence sur les tests sur PHP et plus particulièrement sur les tests d'intégrations continue. J'ai commencé à me demander comment je pouvais intégrer les dernières technos à Magento pour assurer plus de qualité sur les projets e-commerce des équipes et comment être plus efficace ? Et un matin, je reçois un message de Thomas qui me dit "Salut Pierre, dis moi on a monté une offre d'hébergement et j'aimerai bien que tu travailles avec nous sur comment on pourrait intégrer ça correctement avec magento", alors ok j'en sais pas plus que ça mais faut qu'on se trouve un moment pour en parler. Quelques semaines plus tard, je rencontre Jacques, on a boire un verre et lui aussi me parle de Docker et Vagrant, je me dit "oue ca a l'air cool faudrait peu être que je m'y mette aussi"...De retour à Lille, je vois Thomas un soir et il me montre Docker.... J'ai donc pris du temps pour étudier la solution et la tester avec magento depuis cet été. J'avoue j'ai été un peu fainéant, rédiger cet article, faire les tests etc...a pris énormément de temps et je pensais à toujours faire plus, mais un moment il faut sortir l'article donc voici un premier jet. Sachez que depuis que j'ai fini mes tests, j'utilise Docker dans mon travail de tous les jours et même si je dois avouer qu'au début j'ai eu un peu de mal à le faire fonctionner maintenant que j'ai l'habitude je trouve cela vraiment très pratique. Je pense que cela vous plaira. Cet article est assez gros et pas forcément évident à lire, soyez indulgent avec moi je ne suis pas administrateur système à la base donc désolé si je n'explique pas tout ultra clairement. Je vous conseille vivement d'essayer de créer vos propres containers et de me faire vos retours d'expérience, cela m’intéresserai beaucoup de savoir ce que vous en avez pensé.

Ce premier article vous permettra de vous familiariser avec Docker et comprendre comment le mettre en place chez vous avec magento. Cet article est certainement un de celui sur lequel j'ai passé le plus de temps sur ce blog. Je vais essayer de faire simple et d'aller droit au but, j’espère qu'il vous plaira.

Qu'est ce que Docker ?

Tout d'abord docker est une plateforme pour les développeurs et les administrateurs qui vous permet de créer un "container", une sorte de machine virtuelle qui contient application et toutes ses dépendances. Vous pouvez envoyer ce "container" librement à quelqu'un qui pourra le faire tourner sur sa machine. Bref pour simplifier, un container docker c'est comme une machine virtuelle "light". C'est une machine virtuelle qui ne contient que ce qui est nécessaire pour faire tourner votre application.
Nous "développeurs magento", qu'est ce que cela nous apporte ?

Imaginez que vous travailler sur un projet et, vous créer un container docker qui contient tout ce qui faut pour travailler avec magento :
- apache2
- Php5 et ses librairies
- éventullement des librairies supplémentaires spécifique à votre projet...

Vous créez d'autres containers :
- un pour faire tourner elasticsearch
- un pour faire tourner varnish
- un pour faire tourner redis

Grâce a ces containers, vous avez toute une architecture serveur avec votre cache varnish, redis, la recherche sous elasticsearch et votre container magento qui fonctionne parfaitement ensemble.

Un nouveau développeur doit arriver sur le projet ? Il perd 1/2 journée à installer l'environnement sur sa machine et si il doit changer de projet ? avec les changements de ports redis etc...c'est le bordel.
Avec Docker, vous lui transmettez vos containers, il les lance...c'est fini ! 5min sont suffisantes.
Mais ce n'est pas tout, imaginez qu'au lieu de transmettre votre container à un collégue, vous le transmettiez directement à un hébergeur...fini les problèmes de "ça marche pas", ça a été testé en local, les containers fonctionnent ensemble. Chacun son travail, l'hébergeur gére la mémoire, le stockage, la sécurité de son coté, pour vous c'est transparent, vous gérez vos container...c'est tout.

Installer Docker et comment ça marche ?

Premièrement commençons par installer Docker sur notre machine :

sudo apt-get install docker.io

Ensuite il faut comprendre comment cela fonctionne.
Un container va être construit ("build") puis à partir ce cet objet construit qu'on appellera une "image", on va pouvoir créer des instances en les démarrant avec la commande "run". Dans notre projet, on aura un container "Mysql" qui sera notre serveur de base de donnée et un container "magento" sur lequel tournera notre magento (avec apache.php). Le container "magento" se connectera au container "Mysql" sur lequel il aura sa base de donnée.

On va commencer par créer un fichier "Dockerfile" qui va décrire notre container:
- Il tournera sur Ubuntu
- On installe dessus Apache2
- On installe également php5 et les extensions nécessaires pour faire tourner magento (curl, mcrypt,..)
- on installe ce qui faut pour se connecter à une base de donnée.

On crée également un container "Mysql", sous ubuntu qui contiendra "mysql-server", d’ailleurs on va commencer par celui ci car après magento l'utilisera.

Créer son container Mysql

Le Dockerfile

Le DockerFile c'est le fichier dans lequel vous allez décrire l'installation de votre machine, installation des programmes, créations des volumes de stockages, transmission de fichier depuis votre pc, ouvertures des ports de la machine..

Commençons par créer un dossier "mysql" avec dedans un fichier "Dockerfile" qui contiendra :

from ubuntu 

run apt-get update
run DEBIAN_FRONTEND=noninteractive apt-get -y dist-upgrade 

run DEBIAN_FRONTEND=noninteractive apt-get install -y mysql-server
#run DEBIAN_FRONTEND=noninteractive apt-get install -y mysql-client

run sed -i -e"s/^bind-address\s*=\s*127.0.0.1/bind-address = 0.0.0.0/" /etc/mysql/my.cnf

ADD ./startup.sh /opt/startup.sh

VOLUME ["/var/lib/mysql"]

expose 3306

CMD ["/bin/bash","/opt/startup.sh"]

Dans ce fichier, je lui dit :
- de se baser sur une distribution ubuntu
- de mettre à jour ses paquets
- d'installer mysql-server et mysql-client
- de remplacer le bind-adress 127.0.0.1 par 0.0.0.0 pour pouvoir se connecter depuis l'extérieur
- d'ajouter le fichier startup.sh (qu'on va créer apres) dans le répertoire /opt/ de notre container
- de mettre d'avoir un dossier /var/lib/mysql qui sera stocké sur le pc qui lance mon container
- d'ouvrir le port 3306
- de lancer mon script /opt/startup.sh (qu'on vient d'ajouter juste avant) à la fin de ces traitements

Le script de démarrage

Ensuite je créez un fichier startup.sh qui contiendra :

#/bin/bash
echo "--debut du startup--"
if [ ! -f /var/lib/mysql/libdata1 ]; then
    mysql_install_db

    /usr/bin/mysqld_safe &
    sleep 10s

    echo "GRANT ALL ON *.* TO pfay@'%' IDENTIFIED BY 'pfay123' WITH GRANT OPTION; FLUSH PRIVILEGES" | mysql

    tail -f /var/log/mysql.log
else
/usr/bin/mysqld_safe

fi
echo "--fin du startup--"

Ce script teste si le fichier /var/lib/mysql/libdata1 existe. C'est le fichier de stockage de la base de donnée.
Si il existe, on lancera alors mysql_safe.
Si il n'existe pas, on va le créer et on va créer un utilisateur "pfay" avec le mot de passe "pfay123".
On termine par afficher les dernières entrées des logs mysql.

Faire le Build et Démarrer mon container

Il faut créer l'image de ma machine pour pouvoir ensuite l'utiliser pour créer l'instance.
Pour simplifier les choses j'ai créé un script build.sh mais vous pouvez très bien taper les commandes directement. Le script build.sh a le contenu suivant :

#!/bin/bash
docker build -t pfay/mysql .

Exécuté dans le dossier ou se trouve le Dockerfile, le script va prendre le fichier Dockerfile et créer l'image "pfay/mysql".
Une fois le build terminé, l'image se trouve sur votre pc, vous pouvez alors démarrer un container depuis cette image.
Pour cela j'ai crée un script run-server.sh qui à le contenu suivant :

#!/bin/sh
docker stop mysql
docker rm mysql
docker run -d -p 3306:3306 -v /data/mysql:/var/lib/mysql --name mysql pfay/mysql

Vous pouvez tout aussi bien lancer ces commandes manuellement mais je trouve cela plus pratique.

Que fais ce script :
- il arrête et supprime l'instance "mysql" si elle existe.
- il lance ensuite avec la commande run le container qu'il appellera "mysql" à partir de l'image "pfay/mysql" buildé précédemment.
- il précise que le port 3306 du container est "branché" sur le port 3306 de ma machine.
- il précise également que le dossier /var/lib/mysql du container sera "branché" avec le fichier /data/mysql de ma machine.
Retrouver les fichiers de cette partie sur github : https://github.com/pierrefay/docker/tree/master/mysql

Comment le mettre en place avec Magento ?

Passons maintenant au container Magento. Pour ça c'est le même principe (et cela le sera toujours pour vos container docker), on a un fichier Dockerfile, on fait un build pour créer l'image. A partir de l'image, on lance une instance.

Le fichier Dockerfile :

from ubuntu
RUN apt-get update
RUN DEBIAN_FRONTEND=noninteractive apt-get -y dist-upgrade
RUN DEBIAN_FRONTEND=noninteractive apt-get install -y php5 php5-cli php5-mysql php5-curl php5-gd php5-mcrypt vim mysql-client
RUN php5enmod mcrypt
RUN a2enmod rewrite
ADD ./000-default.conf /etc/apache2/sites-available/000-default.conf
ADD ./magento /var/www/html
ADD ./config_magento.sh /usr/local/bin/config_magento.sh
ADD ./startup.sh /usr/local/bin/startup.sh
RUN chmod +x /usr/local/bin/startup.sh
expose 80
expose 3306
CMD ["/bin/bash","/usr/local/bin/startup.sh"]

En gros avec le dockerfile voilà ce qu'on fait :
- On se base sur une distribution ubuntu.
- On met à jour les packets
- On installe php5 et les extensions utiles pour faire tourner magento.
- En Option: On installe mysql-client pour pouvoir tester la bdd en ligne de commande depuis le container.
- En Option: On installe vim pour pouvoir éditer un fichier plus facilement quand on se connectera sur le container.
- On active mcrypt et l'url rewriting
- On ajoute remplace le vhost par défaut par le notre (on a rajouté quelques lignes pour l'url rewriting, voir le fichier)
- On ajoutes le répertoire magento (contenu dans le dossier courant, comment le Dockerfile) dans le dossier /var/ww/html de notre container.
- On ajoute le script config_magento.sh et startup.sh
- On modifie les droits du script startup
- On créer 2 Volumes /var/www/html/var et /var/www/html/media, qu'on pourra lié à notre pc lors du lancement de l'image
- On ouvre le port 80 (http) et le port 3306 (mysql) de notre VM
- On lance le script stratup.sh

Le script startup.sh contient:

#!/bin/bash
echo '----debut du startup'
chown www-data:www-data -R /var/www/html/var /var/www/html/media
chown www-data:www-data -R /var/www/html/app/etc
/usr/sbin/service apache2 start
rm -f /var/www/html/index.html
/usr/local/bin/config_magento.sh
echo '--fin du startup--'
tail -f /var/log/apache2/access.log

Ce script :
- Modifie les droits du dossier /var, /media et /etc
- Démarre Apache2
- Supprime le fichier index.html mis par défaut à l'installation d'apache
- Lance le script config_magento.sh
- Affiche les logs d'acces apache.

Le fichier config_magento.sh contient le script qui permet d'installer magento, on y défini les variables pour se connecter à la base de donnée et toutes les infos nécessaires pour réaliser l'installation de magento.
L'ip du serveur de base de donnée est contenu dans la variable $MYSQL_PORT_3306_TCP_ADDR qui est crée automatiquement au lancement du container.

#!/bin/bash
clear
CURRENTIP=$(ifconfig | grep -v 'eth0:' | grep -A 1 'eth0' | tail -1 | cut -d ':' -f 2 | cut -d ' ' -f 1)
SEPARATION="
----------------------------
"
echo "
-----------------------------------------------
----------- CREATION OF LOCAL.XML -----------
-----------------------------------------------"
BDD_HOST=$MYSQL_PORT_3306_TCP_ADDR;
BDD_NAME="magentodemo"
BDD_USER="pfay"
BDD_PASSWORD="pfay123"
SITE_URL=$CURRENTIP
ADMIN_USERNAME="admin"
ADMIN_PASSWORD="admin123"
ADMIN_FIRSTNAME="admin"
ADMIN_LASTNAME="admin"
ADMIN_EMAIL="admin@localhost.fr"
LOCALE="fr_FR"
TIMEZONE="Europe/Paris"
DEFAULT_CURRENCY="EUR"
USE_SECURE="no"
SECURE_BASE_URL=$CURRENTIP
URL_REWRITE="yes"
SKIP_URL_VALIDATION="yes"
USE_SECURE_ADMIN="no"
echo $SEPARATION
echo "DROP DATABASE IF EXISTS $BDD_NAME ;" | mysql -h $BDD_HOST -u pfay -ppfay123
echo "CREATE DATABASE $BDD_NAME" | mysql -h $BDD_HOST -u pfay -ppfay123
echo "Database creation..."
echo $SEPARATION
echo "MySql User and Permissions creation..."
echo "GRANT ALL PRIVILEGES ON $BDD_NAME.* TO '$BDD_USER'@'%' IDENTIFIED BY '$BDD_PASSWORD';" | mysql -h $BDD_HOST -u pfay -ppfay123
echo "OK"
echo $SEPARATION
rm -rf /var/www/html/var/cache
rm -rf /var/www/html/var/session
rm -rf /var/www/html/app/etc/local.xml
echo "Magento Installation..."
php -f /var/www/html/install.php -- \
--license_agreement_accepted "yes" \
--locale $LOCALE \
--timezone $TIMEZONE \
--default_currency $DEFAULT_CURRENCY \
--db_host $BDD_HOST \
--db_name $BDD_NAME \
--db_user $BDD_USER \
--db_pass $BDD_PASSWORD \
--url $SITE_URL \
--use_rewrites $URL_REWRITE \
--skip_url_validation $SKIP_URL_VALIDATION \
--use_secure $USE_SECURE \
--secure_base_url $SECURE_BASE_URL \
--use_secure_admin $USE_SECURE_ADMIN \
--admin_firstname $ADMIN_FIRSTNAME \
--admin_lastname $ADMIN_LASTNAME \
--admin_email $ADMIN_EMAIL \
--admin_username $ADMIN_USERNAME \
--admin_password $ADMIN_PASSWORD
echo "OK"
echo $SEPARATION
echo "Installation Complete !"
echo $SEPARATION

On va ensuite lancer notre container via la commande run, je crée encore un script run-server.sh:

#!/bin/sh
docker stop magento
docker rm magento
docker run -p 80:80 --link mysql:mysql --name magento pfay/magento

Le détails de la commande vous le retrouverez ci dessus avec le container mysql. Vous remarquerez les options :
- "-p" qui permet de mapper le port 80 de mon container avec le port 80 de mon pc.
- "--link" qui permet de lier mon container magento avec le container mysql lancé précédemment.
- "-v" qui permet de monter les volumes crées précédemment dans le Dockerfile avec les dossier de mon pc mais on ne l'utilisera pas ici.

Voilà si vous lancer le script run-server.sh de votre container magento alors votre fichier vm est lancé et il est connecté avec votre container mysql.
Pour y accéder, tapez l'ip de votre VM dans votre navigateur. Pour retrouver l'ip d'une vm, vous pouvez utiliser ce script getIp.sh :

#!/bin/sh
TAG="magento"
CONTAINER_ID=$(docker ps | grep "$TAG "| awk '{print $1}')
echo "CONTAINER ID : $CONTAINER_ID"
IP=$(docker inspect --format '{{ .NetworkSettings.IPAddress }}' $CONTAINER_ID)
echo "Ip de $TAG: $IP"

De la façon suivante :

./getIp.sh magento

Retrouver les fichiers de cette partie sur github : https://github.com/pierrefay/docker/tree/master/magento

Créer son container Magento pour travailler en équipe

Ok vous allez me dire, c'est chouette, j'ai un magento qui va parfaitement fonctionner pour faire une démo mais souvent je vais l'utiliser sur un projet déjà existant, je ne vais pas repartir de zéro et vous avez raison !
Vous devez alors créer une base de donnée sur votre container mysql, en vous connectant via mysql-client depuis votre pc par exemple, puis importez une base de donnée.

Le Dockerfile sera différent car plus question d'utiliser config_magento.sh pour notre machine de développement, on va plutot partager le répertoire magento qui contient notre code dans un volume qu'on montera sur notre container.
vous pourrez trouver un exemple de Docker utilisé pour développer sur github à l'adresse suivante : https://github.com/pierrefay/docker/tree/master/dev

Bien sur il faut l'adapter pour vos besoins.

Se connecter comme en SSH sur son container docker

Vous pouvez vous connecter via nsenter sur votre container, cela vous permet de vous connecter "comme en ssh" pour pouvoir par exemple réindexer magento.
Installez nsenter :

cd /tmp
curl https://www.kernel.org/pub/linux/utils/util-linux/v2.24/util-linux-2.24.tar.gz | tar -zxf-
cd util-linux-2.24
./configure --without-ncurses
make nsenter
cp nsenter /usr/local/bin

puis vous pouvez utiliser ce script nsenter.sh:

#!/bin/sh
PID=$(docker inspect --format {{.State.Pid}} $1)
nsenter --target $PID --mount --uts --ipc --net --pid

vous pourrez alors "rentrer" dans votre container en tapant :

 ./nsenter.sh nom_du_container
     

Et apres que faire ?

Ce tutoriel est le premier sur docker, dans le prochain tutoriel nous verrons comment docker peu etre utilisé pour déployer sur un serveur facilement avec un hébergeur spécialisé et nous essaierons de répondre à toutes les questions que vous pourriez vous poser sur cet article.
Merci à tous d'avoir lu cet article jusqu'au bout, en attendant la suite, n'hésitez pas à faire vos propre tests et à partager votre ressenti sur docker en dessous dans les commentaires sur cet article, je serai ravis de discuter avec vous, n'hésitez pas à poser vos questions, en fonction de vos questions j'essaierai de compléter cet article pour qu'il soit le plus complet possible.
Vous aussi soutenez ce blog en partageant cet article sur twitter. Si vous avez aimé cet article, suivez moi sur twitter ou sur la page facebook du blog.
Les livres qui peuvent vous aider :
  • Livre Magento Developer's Guide by Alan Mc Gregor
  • Livre Magento Performance Optimization
  • Livre Grokking Magento Vinai
Commentaires sur cet article
Philippe , 677 days ago :

bonjour Pierre, comment faire pour installer des plugins Magento dans Docker svp ? le but est de travailler avec Magento sur une machine de developpement, modifier/parametrer le Magento puis enregistrer les modifications. Le tout dans un container Docker pour pouvoir le réutiliser sur un serveur de production. Est ce possible svp et si oui comment ? D'avance merci

676 days ago :

Bonjour Philippe, c'est comme d'habitude Docker c'est juste ton serveur web. Ensuite il faut utiliser un Volume pour stocker le dossier qui contiendra le répertoire de magento et un autre pour contenir le dossier contenant ta base de donnée.

fred_i , 629 days ago :

Bonjour Pierre, merci pour cet article! Je sais que faire tourner magento 2 sur windows est une assez mauvaise idée... j'ai tout de même essayé de monter un environnement avec Docker et la devbox de magento 2 et le résultat est très partagé ! Les performances sont horrible, penses-tu qu'avec ton tuto l'installation serait plus stable/fiable ? ou Magento 2 + Windows sont totalement incompatible ? Merci

2542 days ago :

Bonjour Fred_i, Effectivement faire tourner docker sous Windows c'est déjà super long et magento2 en développement c'est un peu une horreur pour le moment. A par passer sous linux pour que ce soit un peu mieux, j'ai pas trop de solution...magento2 installé sur un Wamp tu vas voir ca va te faire...m2 est long en dev :)

Vous devez être connecté pour commenter un article.