Thématiques principales

vendredi 16 août 2019

Python dans docker

Nous avons dans un article précédent [1] proposer un exemple de mise en oeuvre  de deux applications python exploitant ou exposant une interface ReST.

Dans un second article [2],  nous avons également vu qu’il était possible de de packager et livrer des applications python avec divers outils comme setuptools[3] ou pyinstaller [4].

Nous avions cependant laisser une question en suspend concernant une dernière façon de déployer nos appli python. Ainsi, comme vous l’avez deviné, (le titre à tout spoiler…) nous allons dans ce présent article nous intéresser au packaging python dans des container docker.

Alors du coup après avoir lu l’article précédent, vous allez surement demander, mais pourquoi? quel est l'intérêt? et bien pour deux raisons:

  • la première est la devise de docker [5]: build once, run everywhere ce qui permet d’aller bien au delà des plateformes et des machines virtuelles
  • la seconde est que comme à la place de livrer un package ou des sources, on va livrer une image docker, alors peu importe ce que nous mettrons dans le conteneur, cela restera dans le conteneur sous notre responsabilité en minimisant complètement les interventions d’installations d’un utilisateur

La limitation est évidemment que nous ne nous intéresserons qu’aux applications basées sur le réseaux…. (WEB, CLI, etc)

Du coup pour illustrer cet article, je vous propose de reprendre l’exemple déjà traité précédemment [1] avec lequel nous proposons de déployer dans un ou plusieurs conteneur docker les différentes parties applicatives.

Pour cela nous allons donc utiliser une image de base de type alpine dans laquelle nous allons ensuite déployer ce que nous aurons décidé d’etre notre livrable. Ici, le plus simple, et de directement pousser nos sources dans l’image en s’assurant préalablement que python est bien installé ainsi que les dépendances de notre application.

On va donc définir deux Dockerfile en s’inspirant de [6]: Dockerfile_people et Dockerfile_stat respectivement pour chaque applications:


#Dockerfile_people:

FROM alpine:latest
RUN apk add --no-cache python3
RUN pip3 install setuptools Wheel
RUN pip3 install flask
COPY . /opt/
CMD cd /opt;python3 -m people



#Dockerfile_stat:

FROM alpine:latest
RUN apk add --no-cache python3
RUN pip3 install setuptools Wheel
RUN pip3 install flask python_http_client
COPY . /opt/
CMD cd /opt;python3 -m people_stat


Puis on construit nos images:


$ docker build -t people -f ./Dockerfile_people .
$ docker build -t people_stat -f ./Dockerfile_stat .


Et on les lances (en oubliant pas d’exposer leur ports d'écoutes respectifs 5001 et 5002 avec le paramètre -p)


$ docker run -it -p 5001:5001 people
$ docker run -it -p 5002:5002 people_stat


Et la ca marche! euh oui mais pas complètement… autant si on essaye d'accéder à l’interface http://localhost:5001/humans, cela fonctionne mais…. si ont tente http://localhost:5002/recall, la rien ne va plus!

Qu’est ce qui se passe?

C’est simple dans la configuration applicative réalisant les requêtes sur “recall”, nous avons dit à notre application d’aller chercher les informations sur localhost:5001/humans…. mais ce localhost…. c’est lui même! Ce que l’on voulait c'était qu'il aille sur l’autre container! Alors l’erreur semble évidente mais souvent on la fait car on développe sur un poste en local sans se préoccuper de l'aspect distribué du système que l’on est en train de faire… et donc je vous assure tout le monde tombera dans cette erreur.

Donc du coup on fait quoi?

C’est simple on ne met pas localhost mais le hostname de la machine qui expose réellement ce port! C’est à dire dans notre situation, la machine physique. (je vous laisse essayer ).

Alors bien sur généralement une information comme celle ci ne devra pas être mis en dur dans le code, on préférera s’appuyer sur des fichiers de configuration, accessibles depuis un volume ou définis par des variables d’environnement alimenté au moment du lancement du container. L’idée ici n’est pas d’aller jusque la mais déjà de voir ce que permet docker basiquement et certaines des limitations que cela induit, ici entre autre une adhérence résiduelle à la machine physique.

Nous verrons dans un prochain article comme avec docker toujours s’en affranchir.

Références:

[1] https://un-est-tout-et-tout-est-un.blogspot.com/2019/08/rest-avec-python.html
[2] https://un-est-tout-et-tout-est-un.blogspot.com/2019/08/deployer-du-python.html
[3] https://setuptools.readthedocs.io/en/latest/setuptools.html
[4] https://www.pyinstaller.org/
[5] https://uwm.edu/business/event/docker/
[6] https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-xix-deployment-on-docker-containers

Aucun commentaire:

Enregistrer un commentaire