Contexte

Il est courant d'avoir un PC/Mac dédié par développeur, ce développeur intervenant sur de nombreux projets, permettant d'avoir un environnement de travail productif et personnalisé. Cependant chaque projet a ses exigences techniques et nécessite des outils différents. Comment éviter les interactions entre les outils de différents projets et s'assurer qu'il n'y ait pas d'effet de bord ?

Prenons un exemple : 2 projets Java pour 2 clients différents utilisant Maven. Par défaut le repository local est dans ~/.m2. Par conséquent des librairies seront communes et utilisables. Heureusement Maven propose de personnaliser le path de son repository local. Continuons un peu cet exemple : ces 2 projets Java nécessitent des instances Tomcat dédiées (version et configuration différentes). La version paquet (Windows : installer via .exe, Linux rpm | deb) n'est pas adaptée, il faut utiliser la version zippée. Il faut configurer les paths (catalina_home, jvm..), configurer les ports pour ne pas être en conflit…

On constate bien via cet exemple qu'il est nécessaire de faire de nombreuses actions afin de préserver ses outils suffisamment hermétiques. De plus il est nécessaire d'avoir une très bonne maîtrise de l'administration de ses outils pour identifier l'ensemble des configurations nécessaires.

Heureusement, il existe des moyens d'éviter cela :

  • créer un profil utilisateur dédié : cela permet d'avoir un path utilisateur dédié. De plus, les outils peuvent fonctionner en mode “utilisateur”. Cependant, cette option comporte de nombreux défauts :
    • contre-productif : difficile de travailler sur 2 projets en parallèle,
    • ne résout pas tous les problèmes : les ports peuvent être en conflit,
    • tous les outils ne fonctionnent pas en mode par utilisateur,
    • environnement difficilement partageable ;
  • créer une VM par projet : cette solution permet de gérer cette problématique mais apporte de nouveaux problèmes :
    • performance : une VM est moins performante qu'un système natif et nécessite plus de RAM,
    • volumétrie : une VM représente souvent plusieurs Go de données,
    • productivité : le temps de démarrage d'une VM peut être long,
    • si l'on passe par un serveur dédié de VM : le coût est très important pour le serveur et les performances ne sont pas toujours au rendez-vous ;
  • ou bien utiliser Docker avec sa gestion de container léger.

Installation

L'objectif est d'installer plusieurs environnements Liferay.

Pré-requis:

  • Linux relativement récent (Fedora >= 19, Ubuntu >= 12.04) ;
  • avoir les droits d'administration sur le Linux (root ou bien sudo) ;
  • installer Docker : Cf. https://www.docker.io/gettingstarted/.

Pour Liferay, il est nécessaire d'installer :

  • une JVM ;
  • un serveur de servlet ou serveur d'application JEE ;
  • une base de données ;
  • un IDE : l'objectif étant de mettre au point un poste de développement.

Docker propose de nombreux containers. Il est préférable de partir d'images existantes si l'on est pas soumis à de fortes contraintes de version.

Pour rappel, Docker propose d'instancier des containers à partir d'images (un container figé) et de pouvoir créer une image à partir d'un container.

Une recherche sur https://index.docker.io/ :

Image non disponible

ou bien en ligne de commande :

Image non disponible

Il existe 2 images dont une validée par la communauté mais n'ayant aucune note d'appréciation.

En regardant en détails l'image kameshsampath/liferay, son créateur fournit le fichier Dockerfile qui a permis de la construire : https://index.docker.io/u/kameshsampath/liferay/

Image non disponible

Pour réaliser ce container, l'auteur s'est basé sur une autre image (kameshsampath/openjdk-jre-6) qui elle-même est basée sur une image de base Ubuntu.

La suite du fichier permet de connaître la version du JDK installé ainsi que la version de Liferay.

  • OpenJDK 6.
  • Liferay 6.2.0 Community Edition.

Cette image constitue une bonne base de travail, évitant ainsi d'installer le JDK et Liferay.

Récupération en local de cette image :

 
Sélectionnez
docker pull kameshsampath/liferay

Cette étape peut être assez longue lors de la toute première exécution, car Docker récupère l'ensemble des images (snapshot) nécessaires à la constitution de l'image.

Pour rappel, une image n'est pas une archive contenant tout, mais un ensemble d'images qui, par superposition, constitue la cible. Le filesystem Aufs est utilisé pour créer cette superposition d'images.

Image non disponible

Source : Docker.io

Personnalisation de l'image

L'image téléchargée constitue une bonne base, mais il manque un serveur de base de données MySQL (Liferay propose par défaut d'utiliser en mode dev Hsqldb qui est une base de données embarquée légère mais n'offrant pas la richesse de MySQL) et Eclipse afin de pouvoir développer des modules Liferay.

Pour profiter pleinement du déploiement rapide des porlets, l'IDE Eclipse a besoin d'accéder au fichier de l'instance cible Liferay. Par conséquent, Eclipse est installé au sein du container. Bien que cela ne soit pas une bonne pratique, dans le cas présent, cela simplifie l'intégration avec Liferay.

D'autre part, il est tout à fait envisageable de mettre un serveur de base de données dans un container autonome, ce qui peut être avantageux si l'on souhaite la mutualiser avec d'autres outils. Dans le cas présent, l'objectif est d'avoir un container all-in-one. C'est pourquoi MySQL est également dans le container.

Création d'images personnalisées

Pour personnaliser cette image, un fichier DockerFile doit être créé :

 
Sélectionnez
FROM kameshsampath/liferay:6.2.0-ce-ga1

MAINTAINER Michael Pagès, mpages@ippon.fr

# mise à jour de la distribution (pour la secu & fixes)
RUN apt-get update
RUN apt-get upgrade -y

# installation de mysql 
RUN apt-get -y install mysql-server

# Ajout du service mysql au démarrage du container
RUN echo "[program:mysqld]"  >> /etc/supervisor/conf.d/supervisor.conf
RUN echo "command=/usr/sbin/mysqld" >> /etc/supervisor/conf.d/supervisor.conf
RUN echo "stdout_logfile=/var/log/supervisor/%(program_name)s_out.log" >> /etc/supervisor/conf.d/supervisor.conf
RUN echo "stderr_logfile=/var/log/supervisor/%(program_name)s_err.log" >> /etc/supervisor/conf.d/supervisor.conf
RUN echo "autorestart=true" >> /etc/supervisor/conf.d/supervisor.conf

RUN cd /opt; wget http://freefr.dl.sourceforge.net/project/lportal/Liferay%20IDE/2.0.1%20GA2/liferay-ide-eclipse-linux-x64-2.0.1-ga2-201401270944.tar.gz -O liferayIde.tar.gz 
RUN cd /opt; tar -zxvf liferayIde.tar.gz 

# Expose the ports: 22 pour ssh & 8080 liferay
EXPOSE 22 8080

# Start the supervisord - demon par defaut pour l'image liferay
CMD ["/usr/bin/supervisord"]

Création de l'image

Les noms doivent être en minuscules pour pouvoir être commités sur le registry !

 
Sélectionnez
docker build -t ippon/demoLF .
Image non disponible

Comme illustré, la création de cette image se base sur des caches, car une image similaire a déjà été effectuée avant.

Docker profite de nombreux mécanismes de capture différentielle pour optimiser les performances et limiter la quantité de données à stocker et par conséquent à transférer.

Une commande permet de visualiser les dépendances inter-images et les différentes étapes :

 
Sélectionnez
docker images --viz  | dot -Tpng -o docker.png
Image non disponible

Dans cette représentation, on constate 3 images constituées à partir de l'image Liferay initiale.

Test et validation images demoLF

Lancement du container :

 
Sélectionnez
docker run -P --name demoLF -i -t ippon/demoLF
  • -P : pour mapper sur un port aléatoire les ports exposés (voir DockerFile clause Expose 22, 8080) du container ;
  • -i : pour diriger la sortie standard vers la console et visualiser en direct les traces ;
  • -t : cible l'image à utiliser ;
  • -name : pour nommer le container.

De nombreuses autres options de lancement son disponible. Cf. : http://docs.docker.io/en/latest/reference/run/

La commande docker ps permet de lister les containers actifs et les ports d'écoute associés.

Image non disponible

Lancement d'Eclipse:

 
Sélectionnez
ssh root@localhost -p 49155 -XY  /opt/eclipse/eclipse

Liferay est accessible à l'URL suivante : http://localhost:49156.

L'image étant opérationnelle et validée, suppression de ce container temporaire :

 
Sélectionnez
docker rm demoLF

Exécution container par projet

Création d'un container pour chaque projet :

 
Sélectionnez
docker run -d -p 10022:22 -p 18080:8080 --name projet1 -i -t ippon/demoLF
docker run -d -p 10122:22 -p 19080:8080 --name projet2 -i -t ippon/demoLF

Index, Registry & Partage

L'index est l'outil propriétaire de Docker permettant de rechercher, naviguer, administrer le registry accessible à l'URL https://index.docker.io/.

Le registry quant à lui est ouvert et accessible, permettant de stocker et partager les images : https://github.com/dotcloud/docker-registry.

Docker propose d'héberger des images publiques via leur registry, il est également possible de créer son registry privé.

Dans notre cas, il est préférable de mettre en place un registry d'entreprise et d'y stocker les images projet.

Pour installer un registry, rien de plus simple grâce à Docker :

Installation du registry et lancement du registry

 
Sélectionnez
docker pull registry; docker run -d -i --name registyDocker -p 5000:5000 -m 512m registry
  • -d : pour le lancer en mode démon ;
  • -i : redirection de la sortie standard. Bien que docker soit lancé en mode démon, les traces sont consultables directement via la commande : docker logs registyDocker ;
  • -name : pour nommer le container ;
  • -p : pour mapper le port 5000 sur le port 5000 ;
  • -m : pour limiter la RAM allouée à ce container à 512 Mo.

Transfert de l'image dans le registy

Docker détermine la destination de l'image (registry public ou privé) en fonction de la 1ère partie de son nom.

XXX/image

Si XXX est une simple chaîne de caractères, c'est donc le registry public qui sera utilisé.

Si XXX ressemble à un hostname[:port] alors ce sera l'URL du registry cible.

Avant de commiter, il faut renommer notre image (les noms doivent être en minuscules pour être commités !) :

Image non disponible
 
Sélectionnez
docker tag ba6e34242e1d localhost:5000/demolf

La commande tag permet de renommer l'image ou bien de changer le tag (à “latest” dans le cas présent). Dans un contexte projet, il sera intéressant de changer le tag pour refléter la version de l'environnement lors des différentes phases de release. Grâce à cela, un environnement de test peut être aisément stabilisé et remis à 0.

Image non disponible

Naturellement, Docker n'a pas supprimé le tag ippon/demoLF ce qui permet d'avoir une même image référencée via différents noms.

L'image ippon/demoLF peut être supprimée via la commande docker rmi ippon/demoLF. Cependant, cela n'effacera pas l'image réelle dont l'ID est ba6e34242e1d. L'image réelle ne sera supprimée que si la commande est faite via son ID ou bien si toutes les images référençant son ID sont supprimées.

 
Sélectionnez
docker commit localhost:5000/demolf
Image non disponible
Image non disponible

L'image est accessible à tous sur le registry.

Attention, le registry n'est pas indexé et n'a aucun lien avec le serveur public. Il est donc impossible d'exécuter des commandes de recherche.

Récupération de l'image depuis le registry :

 
Sélectionnez
docker pull localhost:5000/demolf

Fonctions avancées

Docker ne se limite pas au contenu de la présentation. De nombreuses autres fonctions existent, telles que :

  • Gestion de volume partagé inter-containers :

Création d'un container de partage :

 
Sélectionnez
docker run -v /var/volume1 -v /var/volume2 -name DATA busybox true
  • Utilisation du volume dans un autre container :
 
Sélectionnez
docker run -t -i -rm -volumes-from DATA -name client1 ubuntu bash

Plus d'informations : http://docs.docker.io/en/latest/use/working_with_volumes/.

  • Gestion des connexions réseau point-à-point inter-containers via les commandes link et utilisation d'ambassadeur centralisation des accès inter-containers.

Par défaut, les containers en cours d'exécution se relancent automatiquement lors du redémarrage de la machine host. Si un container est arrêté (manuellement ou bien bug), il est possible de le retrouver grâce à la commande :

 
Sélectionnez
docker ps -a

Celle-ci liste l'ensemble des containers tous états confondus (sauf ceux supprimés).

De plus, de nombreux outils annexes existent pour faciliter son utilisation, par exemple :

Bien d'autres outils référencés sur :

Conclusion

Ce tutoriel a permis de créer une image dédiée, la sauvegarder sur un référentiel, la partager et l'instancier autant de fois que nécessaire pour différents clients et environnements.

Docker, grâce à sa gestion de container simple et légère, est un outil adapté au poste de développement pour faire des sandbox permettant de tester des outils, tout comme pour la création d'images servant à des environnements de production en mode cluster.

Naturellement, Docker étant un outil bas-niveau et n'offrant pas de service clef en main avec IHM, outil de supervision, certains préfèreront directement se tourner vers des services de cloud privé ou public dédié à leurs usages.

Pour les plus vaillants d'entre vous qui souhaitent s'aventurer à l'utiliser, Docker est un produit stable (bien que jeune). Sa légèreté et sa simplicité font de lui un très bon outil adapté pour le dev, pour la gestion de promotion d'environnement, pour le cloud…

Les cas d'utilisation ne manquent pas. Les grands noms du web eBay, Google ont d'ailleurs misé sur cet outil : http://www.docker.com/about_docker/usecases/.

Remerciements

Nous tenons à remercier Francis Walter pour la mise au gabarit puis Mickael Baron pour la relecture.