Accueil Nos publications Blog Déploiement d’une application Java sur Azure via Docker

Déploiement d’une application Java sur Azure via Docker

SOAT-challenge Dans le cadre de notre dernier concours de code, nous avons déployé une application événementielle sur la plateforme Azure en utilisant Docker. L’objectif était de pouvoir consommer les solutions des différents participants et d’en extraire des statistiques comme leurs scores ou le nombre de propositions de solution par participant, le tout dynamisé par l’utilisation des flux de réseaux sociaux (Twitter, pour ne pas le citer).
L’application ayant tenu ses promesses, il est temps de faire le point. Pourquoi avoir choisi le cloud de Microsoft pour l’hébergement ? En quoi Docker nous a-t-il aidés ?

Pourquoi le cloud ?

Le concours n’aura lieu que le temps d’une soirée. Même s’il est nécessaire de configurer et de valider le service au préalable, le besoin en hébergement est très ponctuel. L’application doit pouvoir se lancer temporairement, le temps d’installer la plateforme du concours, et le temps du concours (contrairement à d’autres services qui nécessitent d’être en ligne en permanence). Notre besoin s’oriente parfaitement vers le cloud, qui offre cette souplesse d’utilisation.

Dans l’écosystème .NET, le cloud Azure est reconnu, mais il l’est moins dans le monde Java. Pourtant il est déjà possible de déployer une application Java dans un serveur web tel que Tomcat ou Jetty, le tout hébergé sur ce PaaS (Platform As A Service). Azure propose également une partie IaaS (Infrastructure As A Service) où l’on peut provisionner des machines virtuelles et avoir complètement la main dessus. Cette solution permet d’avoir plus de souplesse dans ses choix d’architecture. Ainsi, la porte reste ouverte pour le choix de la base de données, par exemple, même si Azure propose d’instancier directement les différentes bases de données actuellement disponibles sur le marché (type Cassandra, MongoDB…)

Pourquoi Docker ?

Notre application sera constituée de plusieurs composants : une base de données, la webapp qui notera les participants, ainsi qu’une application qui consommera un flux twitter. Il doit être facile de gérer le cycle de vie de ces éléments : installer, démarrer, et arrêter un composant doit se faire le plus facilement possible. Docker permet d’uniformiser la manipulation de ces différents services qu’importe leurs natures intrinsèques. Cette simplification de gestion permet de tester rapidement l’intégration d’un nouveau composant. Par exemple, tester un nouveau système de base de données ne demande pas plus que l’utilisation de la commande docker run.

L’utilisation de docker-compose, autre outil fourni par Docker donne la possibilité d’orchestrer le lancement de ces applications. Ainsi, via le fichier descriptif docker-compose.yml, nos applications et notre base de données vont démarrer dans le bon ordre. Docker va nous permettre de gérer facilement l’ensemble des composants de notre application.

Création de la machine virtuelle via Docker-machine

La création de la machine virtuelle peut se faire via le portail Azure ou via les outils lignes de commande fournis par Azure. Mais un autre outil fourni par Docker, docker-machine, permet également de créer une machine virtuelle. Une fois votre certificat configuré sur le portail Azure, la commande suivante permet d’instancier une machine à partir d’une image Ubuntu contenant le daemon docker.


./docker-machine create --azure-location="East US" --azure-subscription-id="<abonnementId>" --azure-subscription-cert=<certificat> -d azure <nom-machine>

Docker-machine va créer la machine virtuelle à partir des paramètres fournis (ici, notre machine sera démarrée sur la plaque Est Américaine).

Cet outil permet de gérer notre machine, comme la créer, mais il peut également la démarrer, l’arrêter, permettre de se connecter au docker distant ou encore permettre une connexion SSH sur la dite machine.

Création des conteneurs

Les composants de notre application s’appuieront sur la stack de Spring Boot. Cette stack permet de démarrer très rapidement une petite application, ici une application web, avec tous les composants minimum nécessaires.

La création de l’image docker à partir de la webapp est simple et déjà documentée du côté de Spring Source : Le Dockerfile part d’une image Java 8, y ajoute le jar et démarre l’application.


FROM java:8
ADD gs-spring-boot-docker-0.1.0.jar app.jar
RUN bash -c 'touch /app.jar'
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]

Pour construire l’image docker, la commande docker build fait l’affaire. Mais il est possible d’industrialiser ce processus via maven grâce à un plugin conçu par Spotify. Le plugin permet de configurer différents paramètres de notre image, dont son nom, que l’on peut alors préfixer par le nom de notre repository Docker privé.


       <plugin>
              <groupId>com.spotify</groupId>
              <artifactId>docker-maven-plugin</artifactId>
              <configuration>
              <imageName>registry.example.com/my-image</imageName>
...
 

Orchestration via Docker-compose

Notre application est composée de différents éléments. Pour que la plateforme se lance correctement, il est nécessaire de démarrer tous les composants, dans un ordre prédéfini. Un script batch lançant tous les conteneurs pourrait faire l’affaire, mais docker-compose se propose de faire cette orchestration et de gérer la configuration des différents conteneurs, via un fichier docker-compose.yml.


mongo:
 container_name: mongo
 image: mongo

judge:
 container_name: judge
 image: repository.example.com:5000/soat-challenge-judge
 links:
   - mongo
 ports:
   - "80:8080"

Le fichier d’exemple ci-dessus décrit deux conteneurs. Le premier est un conteneur portant le nom mongo et utilisant l’image se nommant elle-même mongo. Il s’agit ici de démarrer notre base de données qui sera, comme vous l’avez deviné, une base MongoDB. Le second conteneur sera un des composants développés pour le bon déroulement du concours. Il sera nommé judge et se basera sur notre image Docker, que nous avons poussée dans notre repository privé.

De plus, ce container exposera son port 8080 sur le port 80 de la machine, pour être accessible depuis l’extérieur sur le port http par défaut. Il sera également lié au container mongo, via la propriété links, qui sera exposé dans notre conteneur via un nom DNS. Il est donc possible de se connecter à notre base mongo, depuis notre conteneur, en utilisant l’url mongodb://mongo:27017/database.

Il est à noter que le format pour ce fichier docker-compose évolue. Ce n’est pas la dernière version du format de fichier qui a été utilisée ici. L’autre point est que links impose que le conteneur lié soit sur la même machine. Via docker-swarm, il est possible de lier deux conteneurs qui sont physiquement distants, et donc rendre l’application complètement indépendante de la topologie physique des machines. Cela demanderait un peu plus de configuration mais serait idéal dans une utilisation telle que le cloud !

Push et start de la plateforme sur Azure

Pour simplifier le déploiement de nos conteneurs sur la machine virtuelle, un docker-registry a été installé. Cela permet de pousser notre conteneur, depuis la machine de développement et de le rendre disponible sur notre infrastructure. Docker va aider aux transferts de nos conteneurs : il ne va pousser que les parties du conteneur dont notre registry n’a pas connaissance.


docker push repository.example.com:5000/soat-challenge-judge

Ainsi, lors du premier push, le conteneur complet va devoir être poussé dans notre registry, mais par la suite, seule la différence entre nos deux versions de conteneurs sera poussée. L’usage de la bande passante se voit ainsi réduite et permet d’avoir un déploiement plus rapide de notre application.

Une fois les conteneurs poussés dans notre registry, il reste encore à démarrer notre application, grâce à docker-compose. Depuis la machine virtuelle, et depuis le répertoire contenant le fichier docker-compose.yml, la commande suivante va démarrer la plateforme complète.


docker-compose pull && docker-compose up --force-recreate -d

docker-compose va d’abord récupérer les images docker (docker-compose pull) puis va démarrer la plateforme complète (docker-compose up). On force ici la recréation des conteneurs (-- force-recreate) et nous les démarrons en tant que daemon (-d)

Notre plateforme va démarrer chaque composant, dans l’ordre et en les liants entre eux.

Nous avons lancé docker-compose depuis la machine virtuelle, mais il est également possible, avec l’aide de docker-machine, de se connecter au daemon Docker distant et d’utiliser docker-compose depuis notre machine. Cela permet d’appliquer une configuration locale à une machine distante.

Point d’attention

La création de machine virtuelle et le démarrage de conteneur sur la plateforme Azure se fait simplement, à travers docker-machine et Docker. Malheureusement, docker-machine n’a pas voulu créer la machine sur la plaque européenne (le choix de cette plaque étant refusé par le driver).

L’image par défaut utilisée par docker-machine crée une machine virtuelle avec Docker, mais sans docker-compose. Si l’on veut utiliser docker-compose depuis la machine virtuelle, son installation est donc nécessaire. Elle est très simple – il suffit de télécharger l’outil – mais nécessite tout de même une intervention utilisateur.

Microsoft vient d’annoncer un nouveau service : Azure Container Service. Ce service permet de déployer un cluster Docker complet sur Azure, avec les outils associés. La société de Redmond travaille actuellement sur le driver Azure de docker-machine. Cela montre bien que Microsoft veut et va supporter Docker sur sa plateforme Azure, fournissant les outils et simplifiant leur utilisation sur sa plateforme.