Docker est un logiciel libre permettant de gérer des conteneurs. Un conteneur est une abstraction qui regroupe le code et toutes ses dépendances afin que l’application s’exécute rapidement et de manière fiable d’un environnement informatique à un autre. On peut donc voir un conteneur comme une (mini-) machine qu’on va configurer de sorte à ce que notre application marche, et qu’on pourra déployer (transporter) dans l’environnement de production.
Différence entre Machine Virtuelle (VM) et Conteneur
Les deux sont bien tes types de virtualisation cependant ils sont différents de par la façon dont ils utilisent les ressources de la machine hôte.
Quand on crée une marchine virtuelle, il faut allouer une certaine quantité de la mémoire de l’hôte à la machine virtuelle. L’hyperviseur (programme qui gère la virtualisation) établit donc une séparation entre les ressources des différentes VM ainsi que celles de l’hôte. Alors que la création de conteneur ne necessite pas d’allocation de ressource physique. Ceci est possible parce que tous les conteneurs utilisent directement le Kernel de l’hôte.
Cette différence est illustrée par l’image suivante (de site officiel de Docker):
Avantage des conteneurs (et de Docker)
Comme on l’a déjà dit les conteneurs permettent packager nos applications avec leurs dependances. Ainsi l’application ne dépend plus de l’hôte sur lequel il est déployé (ou développé) mais du conteneur dans lequel il est packagé.
Par rapport à une machine virtuel un conteneur est beaucoup plus rapide et plus simple à utiliser. En plus, quand on utilise Docker, on a accès à des milliers d’images pour tout type d’application via Docker Hub. Par exemple on pourrait utilisée une image MySQL qui est rien d’autre qu’un modèle de conteneur dans lequel MySQL est installé et prêt à être utilisé. Cela évite d’installer plein de paquets sur notre machine alors que ceux-ci ne serviront plus dans quelques jours.
Quelques concepts clés
Image : Une image est l’élément de base d’un conteneur. Il s’agit d’un ensemble de fichiers systèmes et de paramètres d’executions. Une image n’a pas d’état et est executée par la runtime docker. Elle peut être vue comme « une description » d’un conteneur.
On peut créer une nouvelle image soit en modifiant un conteneur déjà en marche (une sorte de snapshot d’un conteneur) soit en créant un Dockerfile basé sur une image qui existe déjà.
Conteneur : Un conteneur est une instance en execution d’une image.
Dockerfile : Il s’agit d’un fichier texte qui décrit une image. Il est constitué d’instructions qui servent à décrire une image Docker. Et permet d’automatiser la « build » (création) d’images.
Un Dockerfile ressemble à ça :
FROM ubuntu:18.04 # On crée notre image à partir de l'image ubuntu:18.04
COPY . /app # On copie tout le repertoire courant de l'hôte dans un /app dans le (futur) conteneur
RUN make /app # On execute la commande 'make /app' qui build notre application
CMD python /app/app.py # On specifie la commande à lancer au moment du démarrage du conteneur
Entrypoint : Le point d’entrée d’un conteneur. Il s’agit d’une commande qui se lance au démarrage du conteneur (à l’entrée). La plupart des images officielles Docker sont configurées avec un entrypoint /bin/sh ou /bin/bash.
Cas d’usage
L’installation de Docker n’a rien de spécial, je vous laisse aller regarder le site officiel de Docker et choisir le type d’installation qui vous convient.
Une fois Docker installé, nous allons executer quelques commandes (celles qu’il faudra retenir). Pour ne pas avoir à entrer des commandes dans le vide, je vous propose de reprendre le projet API en Python déjà fait sur ce blog.
Objectif
Le but est de packager le projet API en Python dans un conteneur Docker.
Pour cela nous aurons à utiliser une images MySQL de Docker Hub pour la base de donnée et nous créerons une image pour notre API à partir d’un fichier de description Dockerfile.
Run l’image MySQL
On va sur le site de Docker Hub et on cherche « MySQL » et en cliquant sur l’image officielle (la première qui a pour nom mysql normalement), on peut voir tous les détails de l’image, notamment, des informations sur comment il faut lancer.
Avant de « run » notre image il faut la télécharger sur notre server. En faisant :
docker pull mysql
Pour voir toutes les images qu’on a en local on peut faire
docker images
On on vérifie qu’on a bien l’image « mysql » qu’on vient de télécharger dans la liste des images en local. Puis on lance un conteneur en faisant :
docker run --name mysql -d -e MYSQL_ROOT_PASSWORD=secret -e MYSQL_DATABASE=users mysql
Cette ligne de commande lance le serveur MySQL en arrière plan (option ‘d’) avec comme mot de passe root « secret » crée une base de donnée « users ». Pour vérifier que notre conteneur est bien en marche on fait :
docker ps
On voit bien que le nom de notre conteneur est bien « ‘mysql » comme indiqué par l’option « –name » de la commande précédente.
On peut « entrer » dans notre conteneur en faisant :
docker exec -it mysql bash
On n’est plus sur notre machine mais à l’interieur du conteneur. Dans le cas de l’image mysql (et pour la plupart des images sur DockerHub), il s’agit d’un conteneur linux, on peut donc executer la plupart des commandes lunix habituelles. Et vu que MySQL est déjà installé dans notre conteneur, on peut faire :
mysql -u root -p
Puis le mot de passe « secret ». On voit bien qu’on n’est connecté à MySQL. Pour sortir du conteneur on peut faire Ctrl + D ou taper la commande « exit ».
La prochaine étape est de se connecter à notre serveur MySQL à partir de la machine hôte. Pour ça il faudra trouver l’adresse IP de notre conteneur.
Il faut retenir que, par défaut, tous les conteneurs Docker ainsi que l’hôte sont connectés à un sous-réseau sur l’interface virtuel « docker0 ».
Pour trouver l’adresse IP (et plein d’autres informations) sur le conteneur mysql, on fait :
docker inspect mysql
L’adresse IP est tout en bas, la valeur du champ « IPAddress ». Dans mon cas l’adresse de mon conteneur est 172.17.0.2 . On vérifie qu’on peut bien faire un ping sur cet adresse.
On peut donc se connecter à MySQL avec l’adresse de notre conteneur :
mysql -h 172.17.0.2 -u root -p
Normalement, on est connecté à MySQL et la prochaine étape est de packager notre API.
Packager le projet API
Le projet contient deux fichiers Python :
- wrapper.py : Un module qui contient les fonctions CRUD pour la base MySQL
- main.py : Le fichier qui contient toutes les routes et lance l’API Flask
NB: Dans le fichier wrapper, il faudra s’assurer que l’adresse du server MySQL correspond bien à l’adresse IP du conteneur MySQL que l’on a lancé.
La prémière chose à faire pour packager notre projet est de créer un fichier « requirements.txt » qui va contenir toutes les bibliothèques à installer dans notre conteneur.
Il faut retenir que notre projet doit avoir tout ce dont il a besoin, pour fonction normalement, dans notre conteneur.
Le fichier « requirements.txt » ressemble à ça :
flask==1.1.1 pymysql==0.9.3 SQLAlchemy==1.3.13
NB: Le fichier requirements n’est pas necessaire à la création de notre conteneur, il est seulement pratique.
La prochaine étape et la création du Dockerfile :
FROM python3 # On se base sur l'image officielle de python3 # On est donc sur d'avoir python deja installe COPY . /api # On copie le repertoire du projet dans un dossier /api dans le conteneur RUN pip install -r requirements.txt # On install toutes les biblio requises dans le conteneur CMD ["python3", "run"] # On lance le serveur Flask
Une fois le Dockerfile créé on « build » l’image :
docker build -t api .
Après le build on peut vérifier que l’image est bien dans la liste des images en local (docker images).
Et pour finir il on lance l’API en lançant le conteneur :
docker run --name monapipython api
Pour tester l’API il nous faudra son adresse pour les différents appels. Pour trouver l’adresse faudra faire un « docker inspect » comme on a fait plus haut.
Voilà voilà. On a fait le tour des commandes de bases et vous savez comment packager un projet, build et run une image.
N’hésitez pas à laisser un commentaire. À bientôt!
Salut, j’ai un petit souci en suivant ce petit tuto, arriver au packaging il n’est pas indiqué où ni comment trouver les deux fichier wrapper.py et main.py ni où crée le fichier requirements.txt. (si il faut les trouver dans le docker mysql ou dans un dossier de la machine maitre, si c’est dans le docker mysql comment accèder au fichiers lister si dessus car les commandes linux ne fonctionnent plus pour moi une fois dans le docker… Voilà désolé, ça doit juste être un manque de connaissance de ma part sur le mysql ou les docker, mais étant donné que je me cert de tutos pour apprendre, je pense que ces quelques informations ne serait pas de trop pour votre tuto pour les « noobs ». =)
Bonjour,
Les fichiers (requirements.txt, wrapper.py et main.py) se trouvent dans le répertoire racine du projet. Vous pouvez trouver sur ce repo => https://github.com/olivierded/ledatascientist/tree/master/api_python . Il s’agit de fichiers d’une API qu’on a écrit dans le cadre d’un autre tuto => https://ledatascientist.com/creer-une-api-web-en-python/
Merci pour le tutoriel.
Petite information: si vous avez une erreur dans l’exécution du requirements.txt lors de la création du Dockerfile, vous pouvez changer l’instruction de ce dernier comme ceci:
RUN pip install -r requirements.txt par : RUN pip freeze > -r requirements.txt