L’association de Dropwizard et Docker constitue une solution fort intéressante pour une architecture orientée microservices.
En effet, elle répond remarquablement aux besoins :
- d’isolation de l’environnement d’exécution d’un service
- de déploiement rapide et sans couture
- de portabilité et de scalabilité
- de compatibilité avec des solutions d’hébergement dans un Cloud privé, public ou hybride
Accessoirement, une application Dropwizard est packagée sous la forme d’un fichier jar unique et autonome ce qui rendra d’autant plus simple la fabrication d’une image Docker comme on le verra dans cet article.
En pratique, nous verrons comment :
- dockeriser le service de consultation des horaires du métro parisien, une application Dropwizard qui a fait l’objet du précédent billet de la série (sa lecture préalable est recommandée) et dont le code source est disponible sur GitHub
- créer des environnements d’exécution cloisonnés en mappant un volume de données du conteneur sur le système de fichier local
- publier l’image dans un dépôt privé (situé dans un réseau local) mais également dans le dépôt en ligne Docker Hub
Construction de l’image Docker
J’ai choisi une recette simple en construisant séparément :
- l’application Dropwizard matérialisée par le fichier jar
trafic-ratp-1.0.0-SNAPSHOT.jar
- une image Docker dérivée de l’image publique d’OpenJDK 7 (
FROM dockerfile/java:openjdk-7-jdk
) à laquelle on intègre le jar de l’application précédemment fabriqué ainsi que son fichier de configuration (`trafic-ratp.yml)
Le fichier Dockerfile
résultant est le suivant :
Quelques observations :
- le premier paramètre de l’instruction
ADD
correspond au fichier source à copier dans le conteneur (target/trafic-ratp-1.0.0-SNAPSHOT.jar
).
Le chemin est relatif au répertoire contenant le fichierDockerfile
(répertoire racine). Il n’est pas possible d’ajouter un fichier situé à l’extérieur du répertoire racine ou de ses sous-répertoires (par ex.../dist/20150204/trafic-ratp-1.0.0-SNAPSHOT.jar
) - le second paramètre de l’instruction
ADD
correspond au fichier de destination dans le système de fichiers du conteneur (/app/trafic-ratp-1.0.0-SNAPSHOT.jar
) - le service est exposé par le conteneur sur le port
8080
(instructionEXPOSE
)
La séquence complète de construction de l’image en repartant du code source sur GitHub se résume aux commandes suivantes :
Si l’on ne dispose pas d’environnement de développement, on pourrait tout à fait dockeriser l’étape de construction du microservice :
- en partant de l’image de base d’une Debian (
FROM debian:wheezy
) - sur laquelle on installerait OpenJDK (
RUN apt-get install -y openjdk-7-jdk
), git (RUN apt-get install -y git
) et Maven (RUN apt-get install -y maven
) - suivie de la construction de l’application (récupération du code source et compilation)
Démarrage du conteneur
Il n’existe pas d’hôte Docker natif pour les systèmes d’exploitation autres que Linux. Sous Windows ou Mac OS X, vous devez installer la VM ultra légère Boot2docker, basée sur Virtual Box et la distribution Tiny Core Linux.
Dans cette situation, les conteneurs Docker ne s’exécutent pas directement au dessus de l’OS mais au sein de la machine virtuelle Boot2docker.
La commande docker run
permet de lancer un conteneur à partir de l’image précédemment construite :
L’application embarquée dans le conteneur ne sera accessible qu’à travers l’adresse IP et le port de la VM (et non localhost
).
La commande boot2docker ip
permet de connaître l’adresse IP de la VM :
Le service dockerisé est donc interrogeable via cURL comme suit :
Créer des environnements cloisonnés en mappant les volumes
Pour créer 2 environnements d’exécution distincts (appelons les dev et recette) à partir de la même image, il suffit de mapper le volume /conf
du conteneur vers le répertoire du système de fichier local contenant le fichier de configuration idoine :
- configuration de dev :
~/conf/dev/trafic-ratp-dropwizard.yml
- configuration de recette :
~/conf/rec/trafic-ratp-dropwizard.yml
Le fichier Dockerfile
initial a été très légèrement modifié de sorte à ne pas ajouter le fichier de configuration dans l’image :
Ainsi, le démarrage des instances de dev et recette (ports 9010
et 9020
) s’effectue avec les commandes docker run
suivantes :
- dev :
docker run -t -p 9010:8080 -v ~/conf/dev:/conf --name svc-metro-dev ksahnine:trafic-ratp-dropwizard
- recette :
docker run -t -p 9020:8080 -v ~/conf/rec:/conf --name svc-metro-rec ksahnine:trafic-ratp-dropwizard
L’option -v rep_local:rep_conteneur
rend accessible le contenu d’un répertoire local (rep_local
) depuis le conteneur (rep_conteneur
).
Si vous travaillez sous Mac OS X, le point de montage du conteneur accède en réalité à la VM boot2docker et non au système de fichier du Mac.
Depuis la version 1.3 de Docker, le montage de volume s’effectue sans couture mais est limité uniquement aux sous-répertoires contenus dans le répertoire /Users
.
Pour les versions antérieures de Docker il est nécessaire d’installer une version modifiée de boot2docker (lire cet excellent article).
Distribuer une image Docker
Publier dans un index privé d’images
Il suffit d’une machine sur le réseau local (192.168.0.29
dans l’exemple ci-après) sur laquelle est installée Docker, puis d’installer et démarrer le registry en exécutant la commande suivante :
La commande docker push
permet d’ajouter l’image de notre microservice dockerisé :
L’accès à un index non sécurisé (HTTP) doit être explicitement autorisé au démarrage du démon docker (option --insecure-registry
), sous peine de rencontrer l’erreur suivante :
Avec boot2docker
, l’option peut être passée via la variable EXTRA_ARGS
:
- accéder à la VM en mode shell :
- puis renseigner la variable
EXTRA_ARGS
dans le fichier/var/lib/boot2docker/profile
:
- enfin sortir du shell :
A noter que le client boot2docker
sera à relativement court terme remplacé par la commande docker machine
toujours en cours de développement à ce jour.
Une simple interrogation de l’index via cURL confirme que l’image a bien été publiée :
Elle peut ensuite être récupérée via la commande docker pull
:
et enfin exécutée :
Publier sur Docker Hub
Docker Hub est le dépôt central des repositories hébergés chez Docker. L’hébergement d’index publics est gratuit tout comme le premier index privé (payant au delà).
Mon repository public ksahnine/ratp-rest-api
contient l’image de notre service dockerisé.
La publication de l’image dans le repository s’effectue comme suit :
La récupération de l’image suivie de la création du conteneur et du démarrage du service depuis le hub s’effectue par cette simple commande :
Sauvegarder et restaurer une image
Plus rustique, la commande docker save
permet d’exporter une image dans un fichier de dump :
Réciproquement, la commande docker load
permet de restaurer une image à partir d’un dump :