raml-logoSi vous me lisez, vous avez pu remarquer lors de mon article sur Vagrant vs Ubuntu vs NPM vs Bower que j’utilise l’api:Console de MuleSoft pour déployer en ligne de la documentation au format RAML pour des APIs REST.

Cette console tourne correctement dans Vagrant mais je ne suis dis que la création un container pour cette application serait une première application de Docker judicieuse et adaptée. 🙂

Recherche d’une Base Docker Image

La première étape est de vérifier s’il n’existe pas déjà un container qui le fait déjà dans le Docker Hub Registry. Je n’ai rien trouvé.

Ensuite, avant de construire une image à partir de rien, il est plus rapide de se baser sur une image existante. L’api:Console nécessite l’installation de Node.js, Bower et Grunt. Justement, Docker propose eux-même une image avec ces outils : dockerfile/nodejs-bower-grunt. Nous allons donc la réutiliser.

Construction de l’image Docker

Afin de capitaliser sur la construction de cette image, nous allons utiliser un Dockerfile :

FROM dockerfile/nodejs-bower-grunt
MAINTAINER John DOE "xxxxxxxx@gmail.com"

# télécharge la dernière version de l'api:Console pour RAML
RUN git clone https://github.com/mulesoft/api-console.git /data

# installe les dépendences NPM et Bower
RUN npm install
RUN bower install --allow-root

# modifie la page d'accueil de la console pour pointer sur un sous-répertoire "apis" avec un fichier "main.raml"
ADD index.html /data/app/
# modifie la configuration du serveur pour activer le live-reload sur tous les fichiers du sous-répertoire "apis"
ADD Gruntfile.js /data/
# ajoute une documentation RAML d'exemple
ADD main.raml /data/app/apis/
# déclenche la copie de toute la documentation pour les images se basant sur notre image
ONBUILD ADD . /data/app/apis/

EXPOSE 9000
EXPOSE 35729

# démarre le server Node.js
ENTRYPOINT ["grunt", "server", "--force"]

Quelques explications sur l’instruction ONBUILD. Cette instruction n’est pas exécutée lors de la construction de l’image. Elle le sera lors de la construction d’image utilisant notre image. Ainsi, il sera possible de créer de nouvelles images à partir de celle-ci. Toute la documentation RAML sera alors automatiquement copiée dans le répertoire /data/app/apis du container et donc pris en compte par l’api:Console.

Maintenant, construisons l’image avec cette commande :

$ docker build -t mycompany/api-console

Déploiement du container

Standard

Si l’on souhaite déployer ce container en production, il suffit d’exécuter la commande suivante :

$ docker pull mycompany/api-console
$ docker run -p 9000:9000 -d mycompany/api-console

Rendez-vous sur votre serveur (sur le port 9000) pour admirer la superbe documentation ! 😮

Avancée

En phase de développement conception, cette documentation est amenée à changer souvent. Le rédacteur souhaite valider l’affichage de sa documentation avant de la commiter. Alors au lieu de reconstruire l’image à chaque fois que l’on modifie un fichier, nous allons monter un volume qui va surcharger le répertoire qui contient la documentation RAML ainsi :

# le répertoire /Users/myproject/doc-raml contient les fichiers éditables (dont main.raml)
$ docker run -v /Users/myproject/doc-raml:/data/app/apis --name RAML-DATA busybox true
$ docker run --volumes-from RAML-DATA -p 9000:9000 -p 35729:35729 -d mycompany/api-console

Grace à l’activation du live reload sur le répertoire /data/app/apis, une modification d’un fichier sur le host est directement prise en compte dans le container et donc sur dans le navigateur sans rechargement.

Création d’une image spécifique

Nous avons vu que l’image précédemment créée a été pensée pour être réutilisée. Créons donc un nouveau fichier main.raml (contenant la documentation de votre choix) et le Dockerfile suivant :

FROM mycompany/api-console
MAINTAINER John DOE "xxxxxxxx@gmail.com"

Construisons notre nouvelle image pour notre projet :

$ docker build -t mycompany/api-console-myproject

Démarrons le container :

$ docker run -p 9000:9000 mycompany/api-console-myproject

L’api:Console est déployée et contient la documentation spécifique à notre projet. Notez qu’il est toujours possible aux rédacteurs de cette dernière d’utiliser l’astuce de montage d’un volume pour pouvoir la modifier en direct sans avoir à reconstruire et redéployer le container.

Conclusion

Cet exemple est le cas classique où un container Docker est pertinent :

  • installation d’un serveur web (avec des dépendances plus ou moins simples à installer)
  • installation d’une application web (avec construction et configuration)
  • déploiement (avec de multiples instances)

Ainsi, au lieu de suivre une procédure d’installation (où l’erreur peut être humaine) ou d’exécuter un script de provisionning (qui peut échouer selon l’environnement), il est maintenant possible de lancer simplement une unique ligne de commande pour avoir notre serveur en ligne !

La prochaine étape (pour moi) est de publier cette image sur le Docker Hub Registry avec les sources complètes et la documentation…