La cuisson avec Docker

Préparer une application

Même si l’on code massivement avec des langages de script pour ne pas passer par la case compilation, il y a forcément une étape de préparation avant de pouvoir livrer une application à partir de ses sources : télécharger les modules et compiler les potentiels binding en C, mais surtout gérer tout le bazar lié aux assets : JavaScript et CSS.

Cette étape de préparation avant déploiement porte en anglais le nom poétique de baking : on cuit le pain avant de le livrer.

Il n’y a aucun intérêt à réaliser cette étape sur le serveur de production qui a surement mieux à faire : c’est long, ça requière des outils plus ou moins louches, et si l’application est distribuée, il faut recommencer sur chaque instance.

Préparer Isso

Voici un exemple commenté de préparation et déploiement de Isso, un clone libre et local de Disqus, qui permet d’embarquer des commentaires depuis du JavaScript, sur un site qui peut même être statique. Le serveur est en Python, et il fournit du JavaScript à embarquer dans ses pages HTML.

Pour ne pas pourrir ma machine en installant des outils bizarres, j’utilise des containers Docker à usage unique. Pour avoir un build sans trop de répétitions, j’utilise un simple Makefile. Oui, Makefile est vieux et moche, mais pas plus que bash, et il est un standard de fait. Pour des taches de tailles raisonnables, il reste tout à fait pertinent.

En montant un dossier local dans le container, le résultat du traitement se retrouvera dans ce dossier. La source et le résultat sont locaux, le traitement distant.

Cerise sur le gâteau, grâce à boot2docker,l’action lancée depuis un Mac, va faire travailler un Linux, et surtout, produire du contenu pour Linux.

Pour éviter toutes surprises, je n’utilise que des images officielles de Docker, forcément basé sur Debian (et Wheezy, si possible).

Cuire le Python

Isso est packagé sur Pypi : il s’installe simplement avec pip. Je sais installer python, mais comme la vie est courte, autant utiliser python:2-wheezy.

Makefile pense à l’envers, en pensant prérequis et dépendances. Pour avoir l’application Isso, j’ai besoin d’un python dans un virtualenv, qui a besoin d’un dossier app. Ce qui donne :

app/bin/isso: app/bin/python
    docker run --volume=`pwd`/app:/app --rm --workdir=/app python:2-wheezy /app/bin/pip install isso

app/bin/python: app
    docker run --volume=`pwd`/app:/app --rm --workdir=/app python:2-wheezy virtualenv .

app:
    mkdir app

Comme je suis radin, j’efface (—rm) le container dès qu’il a exécuté son action.

Cuire le JavaScript

Le JavaScript, de nos jours, utilise plus de bazars que du C++ pour être utilisable. Isso est sobre, il se contente de Bower pour aller chercher les bibliothèques et leurs dépendances, Uglify pour compacter, et on échappe à Grunt, un Makefile est utilisé à la place.

js: src/isso/js/embed.js
    docker run --volume=`pwd`/src:/src --rm --workdir=/src node:wheezy sh -c 'npm install -g bower requirejs jade && make init && make js'
    echo "Your minified javascript files are here:"
    find src/isso/js -name *.min.js

src/isso/js/embed.js: src
    git clone https://github.com/posativ/isso.git src/

src:
    mkdir src

Même tactique, une image jetable avec nodejs : node:wheezy est utilisée. Petite astuce, “docker run” n’accepte qu’une seule commande en argument, du coup, il faut passer par un sh -c 'pim && pam && poum'

Livrer le gâteau

La cuisson s’est faite dans des containers, mais le résultat est à chaque fois un simple dossier, tout ce qu’il y a de plus traditionnel.

Il est possible de déployer l’application ainsi, avec un rsync et un supervisor.

J’ai fait le choix de la déployer avec Docker. Le Dockerfile utilisé est minimaliste.

FROM python:2-wheezy

COPY app /app

VOLUME /conf
WORKDIR /app
EXPOSE 1234
CMD ["/app/bin/isso", "-c", "/conf/isso.conf", "run"]

Le dossier contenant le fichier de configuration est réclamé, par contre, l’application est embarquée.

Pour configurer tout ça, un docker-compose.yml qui va utiliser le Dockerfile.

---
isso:
    build: . # Dans le même dossier
    # Aucun privilège
    cap_drop:
        - ALL
    ports:
        - "1234:1234"
    volumes:
        - "conf:/conf" # Pour la configuration
        - "data:/data" # Pour la base de données

La configuration isso est tout aussi simple

[general]
dbpath = /data/comments.db
host = https://example.tld/
[server]
listen = http://0.0.0.0:1234/

Le dossier data monté dans compose est utilisé pour accueillir la base sqlite, et le serveur écoute bien le port 1234.

Il faut ensuite tricoter les urls pour avoir le site web et Isso.

Le site en production n’aura aucune séquelle de son installation, pas de nodejs, pas de choses qui trainent, juste une Wheezy spartiate et une application.

Tout le code est disponible sur github, sous Licence BSD.

blogroll

social