Part 1 introduit les principes de Docker, part 2 est un tutoriel pour illustrer un cas concret d’utilisation de Docker.
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écessites 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érent 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 profile 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 tout 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 & 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’image existante si l’on est pas soumis à de fortes contraintes de version.
Pour rappel, Docker propose d’instancier des containers à partir d’image (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 2 images dont une validée par la communauté mais n’ayant aucun 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
Attention 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é 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 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éé :
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 minuscule 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 inter-images et les étapes intermédiaires :
docker images --viz | dot -Tpng -o docker.png
Dans cette représentation, on constate 3 images constituées à partir de l’image Liferay initiale.
Test & 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 : lance un pseudo terminal TTY
- –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 container 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 & 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 quand à 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 & 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 allouer à 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 son nom.
XXX/image
Si XXX est une simple chaîne de caractère, 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 minuscule 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érencent 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 telle que :
- Gestion de volume partagé inter-containers : 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 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:
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 multi-containers : https://github.com/toscanini/maestro
Bien d’autre 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, la sauvegarder sur un référentiel, la partager et l’instancier autant de fois que nécessaire pour différent 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 pour 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éront 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/.