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 : deux projets Java pour deux 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 deux 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 deux 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 n'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/ :
ou bien en ligne de commande :
Il existe deux images dont une validée par la communauté, mais n'ayant aucune note d'appréciation.
En regardant en détail l'image kameshsampath/liferay, son créateur fournit le fichier Dockerfile qui a permis de la construire : https://index.docker.io/u/kameshsampath/liferay/.
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 :
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.
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éé :
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 IDE/2.0.1 GA2/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 !
docker build -t ippon/demoLF .
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 interimages et les différentes étapes :
docker images --viz | dot -Tpng -o docker.png
Dans cette représentation, on constate trois images constituées à partir de l'image Liferay initiale.
Test et validation images demoLF▲
Lancement du container :
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 sont disponibles. 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.
Lancement d'Eclipse:
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 :
docker rm demoLF
Exécution container par projet▲
Création d'un container pour chaque projet :
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 et 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 et lancement du registry▲
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 1re 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 !) :
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.
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.
docker commit localhost:5000/demolf
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 :
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é intercontainers :
Création d'un container de partage :
docker run -v /var/volume1 -v /var/volume2 -name DATA busybox true
- Utilisation du volume dans un autre container :
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 intercontainers via les commandes link et utilisation d'ambassadeur centralisation des accès intercontainers.
Par défaut, les containers en cours d'exécution se relancent automatiquement lors du redémarrage de la machine hôte. Si un container est arrêté (manuellement ou bien bogue), il est possible de le retrouver grâce à la commande :
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 :
- IHM : dockerui , dockland, shipyard ;
- gestion multicontainers : https://github.com/toscanini/maestro.
Bien d'autres outils référencés sur :
- http://blog.docker.io/2013/07/docker-projects-from-the-docker-community/ ;
- https://sourcegraph.com/github.com/mindreframer/docker-stuff.
Conclusion▲
Ce tutoriel a permis de créer une image dédiée, de la sauvegarder sur un référentiel, de 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.x
Naturellement, Docker étant un outil bas niveau et n'offrant pas de service clef en main avec IHM, ni 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▲
Cet tutoriel a été publié avec l'aimable autorisation d'ippon.fr que nous remercions.
Nous tenons également à remercier Francis Walter pour la mise au gabarit, Mickael Baron, ced, Milkosech et Jacques_jean pour la relecture orthographique.