Pourquoi ce titre entre guillemets? Parce que je pense que ça dépend aussi du besoin de chacun. Ceci étant dit, entrons dans le vif du sujet.

Ce matin, j’ai eu à dockerizer une application Flask que je suis en train de coder et ça m’a fait penser à vous montrer ma façon de faire.

Note : Dockerizer : ce terme existe ou n’existe pas, ça dépend de la ligne de réalité dans laquelle vous vous trouvez. Comme vous lisez cet article, je pars du principe que vous vivez dans la même réalité que moi, donc vous validez.

En premier lieu, je pars de l’image alpine, car elle est particulièrement efficace pour créer des images légères. Je vous laisse faire le test, mais si vous buildez la même app en partant d’une image, au hasard ubuntu, je vous garantis que l’image finale ne fera pas du tout le même poids.

FROM alpine:latest
LABEL maintainer="cazzaniga.sandro@gmail.com" \
      description="A xxxxx app written in Flask"

Ensuite, j’installe les paquets qui vont bien, donc du python, pip et sqlite. Je créé également les répertoires qui vont accueillir les statiques, les templates Jinja ainsi que la base SQLite.

RUN apk add --update --no-cache --virtual python3-dev py3-pip sqlite && \
    mkdir -p /app/static /app/db /app/templates

Je copie ensuite tout le nécessaire dans le conteneur, dans le répertoire de travail que j’ai choisi, à savoir /app, et déclare d’ailleurs ce répertoire comme tel.

Je fais trois COPY plutôt qu’un, car si je n’en fait qu’un les fichiers à l’intérieur des dossiers templates et static se retrouvent à la racine de l’application, ce qui a pour effet de rendre l’application inutilisable (elle ne trouve pas ses templates, ergo erreur 500). Sans doute un truc que j’ai mal compris dans l’utilisation de COPY (ou de ADD, qui m’a fait le même comportement).

COPY requirements.txt app.py config.py /app/
COPY templates/* /app/templates
COPY static/* /app/static

WORKDIR /app

Il me faut ensuite préparer tout ce qui va bien pour que l’application fonctionne :

  • Installer les dépendances Python nécessaires à l’application
  • Créer la base de données
  • Effectuer la migration nécessaire à la création des tables

J’effectue ceci à l’aide d’une instruction RUN :

RUN pip install -r requirements.txt && \
    flask db init && \
    flask db migrate && \
    flask db upgrade

Tout est prêt, j’expose maintenant le port de production de mon application et j’indique le point d’entrée de l’application, qui sera finalement la commande lancée par le conteneur.

EXPOSE 8080

ENTRYPOINT [ "python3", "app.py" ]

En faisant ainsi, il faudra lancer le conteneur avec une option --detach pour qu’il me rende la main, et je pourrais retrouver la sortie sur un docker logs.

Normalement, en production, il faut utiliser un serveur wsgi couplé à un serveur web comme Apache ou Nginx, mais comme précisé dans l’intro, le “proprement” est relatif à mon besoin 😄