git clone https://github.com/uptime-formation/microblog/
Ouvrez VSCode avec le dossier microblog
en tapant code microblog
ou bien en lançant VSCode avec code
puis en cliquant sur Open Folder
.
Dans VSCode, vous pouvez faire Terminal > New Terminal
pour obtenir un terminal en bas de l’écran.
Déployer une application Flask manuellement à chaque fois est relativement pénible. Pour que les dépendances de deux projets Python ne se perturbent pas, il faut normalement utiliser un environnement virtuel virtualenv
pour séparer ces deux apps.
Avec Docker, les projets sont déjà isolés dans des conteneurs. Nous allons donc construire une image de conteneur pour empaqueter l’application et la manipuler plus facilement. Assurez-vous que Docker est installé.
Pour connaître la liste des instructions des Dockerfiles et leur usage, se référer au manuel de référence sur les Dockerfiles.
Dans le dossier du projet ajoutez un fichier nommé Dockerfile
et sauvegardez-le
Normalement, VSCode vous propose d’ajouter l’extension Docker. Il va nous faciliter la vie, installez-le. Une nouvelle icône apparaît dans la barre latérale de gauche, vous pouvez y voir les images téléchargées et les conteneurs existants. L’extension ajoute aussi des informations utiles aux instructions Dockerfile quand vous survolez un mot-clé avec la souris.
Ajoutez en haut du fichier : FROM ubuntu:latest
Cette commande indique que notre image de base est la dernière version de la distribution Ubuntu.
Nous pouvons déjà contruire un conteneur à partir de ce modèle Ubuntu vide :
docker build -t microblog .
Une fois la construction terminée lancez le conteneur.
Le conteneur s’arrête immédiatement. En effet il ne contient aucune commande bloquante et nous n’avons précisé aucune commande au lancement. Pour pouvoir observer le conteneur convenablement il fautdrait faire tourner quelque chose à l’intérieur. Ajoutez à la fin du fichier la ligne :
CMD ["/bin/sleep", "3600"]
Cette ligne indique au conteneur d’attendre pendant 3600 secondes comme au TP précédent.
Reconstruisez l’image et relancez un conteneur
Affichez la liste des conteneurs en train de fonctionner
Nous allons maintenant rentrer dans le conteneur en ligne de commande pour observer. Utilisez la commande : docker exec -it <id_du_conteneur> /bin/bash
Vous êtes maintenant dans le conteneur avec une invite de commande. Utilisez quelques commandes Linux pour le visiter rapidement (ls
, cd
…).
Il s’agit d’un Linux standard, mais il n’est pas conçu pour être utilisé comme un système complet, juste pour une application isolée. Il faut maintenant ajouter notre application Flask à l’intérieur. Dans le Dockerfile supprimez la ligne CMD, puis ajoutez :
RUN apt-get update -y
RUN apt-get install -y python3-pip
Reconstruisez votre image. Si tout se passe bien, poursuivez.
Pour installer les dépendances python et configurer la variable d’environnement Flask ajoutez:
COPY ./requirements.txt /requirements.txt
RUN pip3 install -r requirements.txt
ENV FLASK_APP microblog.py
Reconstruisez votre image. Si tout se passe bien, poursuivez.
Ensuite, copions le code de l’application à l’intérieur du conteneur. Pour cela ajoutez les lignes :
COPY ./ /microblog
WORKDIR /microblog
Cette première ligne indique de copier tout le contenu du dossier courant sur l’hôte dans un dossier /microblog
à l’intérieur du conteneur.
Nous n’avons pas copié les requirements en même temps pour pouvoir tirer partie des fonctionnalités de cache de Docker, et ne pas avoir à retélécharger les dépendances de l’application à chaque fois que l’on modifie le contenu de l’app.
Puis, dans la 2e ligne, le dossier courant dans le conteneur est déplacé à /
.
Reconstruisez votre image. Observons que le build recommence à partir de l’instruction modifiée. Les layers précédents avaient été mis en cache par le Docker Engine.
Si tout se passe bien, poursuivez.
Enfin, ajoutons la section de démarrage à la fin du Dockerfile, c’est un script appelé boot.sh
:
CMD ["./boot.sh"]
Reconstruisez l’image et lancez un conteneur basé sur l’image en ouvrant le port 5000
avec la commande : docker run -p 5000:5000 microblog
Naviguez dans le navigateur à l’adresse localhost:5000
pour admirer le prototype microblog.
Lancez un deuxième container cette fois avec : docker run -d -p 5001:5000 microblog
Une deuxième instance de l’app est maintenant en fonctionnement et accessible à l’adresse localhost:5001
docker login
, docker tag
et docker push
, poussez l’image microblog
sur le Docker Hub. Créez un compte sur le Docker Hub le cas échéant.python:3-alpine
et en remplaçant les instructions nécessaires (pas besoin d’installer python3-pip
car ce programme est désormais inclus dans l’image de base), repackagez l’app microblog en une image taggée microblog:slim
ou microblog:light
. Comparez la taille entre les deux images ainsi construites.Le serveur de développement Flask est bien pratique pour debugger en situation de développement, mais n’est pas adapté à la production. Nous pourrions créer deux images pour les deux situations mais ce serait aller contre l’impératif DevOps de rapprochement du dev et de la prod.
Pour démarrer l’application, nous avons fait appel à un script de boot boot.sh
avec à l’intérieur :
#!/bin/bash
# ...
set -e
if [ "$APP_ENVIRONMENT" = 'DEV' ]; then
echo "Running Development Server"
exec flask run -h 0.0.0.0
else
echo "Running Production Server"
exec gunicorn -b :5000 --access-logfile - --error-logfile - app_name:app
fi
Déclarez maintenant dans le Dockerfile la variable d’environnement APP_ENVIRONMENT
avec comme valeur par défaut PROD
.
Construisez l’image avec build
.
Puis, grâce aux bons arguments allant avec docker run
, lancez une instance de l’app en configuration PROD
et une instance en environnement DEV
(joignables sur deux ports différents).
Avec docker ps
ou en lisant les logs, vérifiez qu’il existe bien une différence dans le programme lancé.
EXPOSE 5000
pour indiquer à Docker que cette app est censée être accédée via son port 5000
.-p port_de_l-hote:port_du_container
reste nécessaire, l’instruction EXPOSE
n’est là qu’à titre de documentation de l’image.HEALTHCHECK
permet de vérifier si l’app contenue dans un conteneur est en bonne santé.
Dockerfile
dont le contenu est le suivant :FROM python:alpine
RUN apk add curl
RUN pip install flask==0.10.1
ADD /app.py /app/app.py
WORKDIR /app
HEALTHCHECK CMD curl --fail http://localhost:5000/health || exit 1
CMD python app.py
app.py
avec ce contenu :from flask import Flask
healthy = True
app = Flask(__name__)
@app.route('/health')
def health():
global healthy
if healthy:
return 'OK', 200
else:
return 'NOT OK', 500
@app.route('/kill')
def kill():
global healthy
healthy = False
return 'You have killed your app.', 200
if __name__ == "__main__":
app.run(host="0.0.0.0")
Observez bien le code Python et la ligne HEALTHCHECK
du Dockerfile
puis lancez l’app. A l’aide de docker ps
, relevez où Docker indique la santé de votre app.
Visitez l’URL /kill
de votre app dans un navigateur. Refaites docker ps
. Que s’est-il passé ?
(Facultatif) Rajoutez une instruction HEALTHCHECK
au Dockerfile
de notre app microblog.
Une image est composée de plusieurs layers empilés entre eux par le Docker Engine et de métadonnées.
Affichez la liste des images présentes dans votre Docker Engine.
Inspectez la dernière image que vous venez de créez (docker image --help
pour trouver la commande)
Observez l’historique de construction de l’image avec docker image history <image>
Visitons en root (sudo su
) le dossier /var/lib/docker/
sur l’hôte. En particulier, image/overlay2/layerdb/sha256/
:
Vous pouvez aussi utiliser la commande docker save votre_image -o image.tar
, et utiliser tar -C image_decompressee/ -xvf image.tar
pour décompresser une image Docker puis explorer les différents layers de l’image.
Pour explorer la hiérarchie des images vous pouvez installer https://github.com/wagoodman/dive
Créons un nouveau Dockerfile qui permet de faire dire des choses à une vache grâce à la commande cowsay
.
Le but est de faire fonctionner notre programme dans un conteneur à partir de commandes de type :
docker run --rm cowsay Coucou !
docker run --rm cowsay -f stegosaurus Yo!
docker run --rm cowsay -f elephant-in-snake Un éléphant dans un boa.
Doit-on utiliser la commande ENTRYPOINT
ou la commande CMD
? Se référer au manuel de référence sur les Dockerfiles si besoin.
Pour information, cowsay
s’installe dans /usr/games/cowsay
.
La liste des options (incontournables) de cowsay
se trouve ici : https://debian-facile.org/doc:jeux:cowsay
ENTRYPOINT
et la gestion des entrées-sorties des programmes dans les Dockerfiles peut être un peu capricieuse et il faut parfois avoir de bonnes notions de Bash et de Linux pour comprendre (et bien lire la documentation Docker).--rm
pour les supprimer dès qu’ils s’arrêtent.Transformez le Dockerfile
de l’app dnmonster
située à l’adresse suivante pour réaliser un multi-stage build afin d’obtenir l’image finale la plus légère possible :
https://github.com/amouat/dnmonster/
La documentation pour les multi-stage builds est à cette adresse : https://docs.docker.com/develop/develop-images/multistage-build/