La conteneurisation (containerisation en anglais) consiste à regrouper dans une même entité tous les éléments nécessaires au fonctionnement d’une application : le code, les fichiers de configuration, l’environnement d’exécution… Ainsi, cette entité est l’élément unique et nécessaire pour déployer une application. C’est donc un concept clé en dataops, en particulier pour mettre en œuvre le principe d’« infrastructure as code ».
De plus, en data, il est très courant d’utiliser des API pour le déploiement du résultat d’un projet. Dans cet article, nous allons voir comment conteneuriser une API simple pour les personnes souhaitant s’initier à cette technique.
Docker, l’outil incontournable pour conteneuriser une application
Parmi les outils de conteneurisation, Docker est le plus utilisé, et de loin. C’est même le deuxième outil DevOps le plus utilisé par les développeurs (au sens très large du terme), derrière Git, selon l’enquête annuelle StackOverflow.
Il existe bien sûr des alternatives, mais qui seront utiles pour des cas d’utilisation assez particuliers (à l’image de Hyper-V pour créer des conteneurs Windows).
Bref, dans 99 % des cas, Docker est l’outil à utiliser, d’autant plus que vous trouverez facilement des ressources en ligne.
On a déjà parlé du fonctionnement général de Docker dans un article précédent. Ce n’est pas l’objet de cet article, qui présente un exemple concret pour conteneuriser une API.
Conteneuriser une API : par où commencer ?
L’un des grands avantages de Docker est la possibilité de créer et d’échanger des images de conteneurs au sein de la communauté (via le Docker Hub principalement). En particulier, vous pouvez récupérer des images Docker déjà existantes et les adapter à vos besoins, pour éviter de repartir de zéro.
Donc la première chose à faire lorsque vous souhaitez conteneuriser une API est de chercher sur Google « Docker image for [nom du framework que vous utilisez] ». Il est très probable que vous trouviez des configurations d’images dans des repository Git, des tutoriels, ou même dans la documentation officielle du framework que vous utilisez.
Quelques exemples pour des frameworks populaires :
Un exemple concret avec une API FastAPI
Malgré tout, lorsqu’on est novice sur Docker, les ressources trouvées en ligne peuvent être très absconses. Nous avons donc préparé un exemple simple en vous expliquant pas à pas les différentes étapes.
Avant tout, assurez-vous d’avoir installé et lancé Docker (instructions pour installer Docker).
Les fichiers utiles pour conteneuriser notre API
Parlons tout d’abord de la structure des fichiers de notre micro-projet :
On va créer dans le dossier racine deux fichiers : requirements.txt et Dockerfile. On va également avoir un sous-dossier app contenant le code de notre API.
Pour cet exemple, on crée une API très basique avec FastAPI. On place le code de notre API dans le fichier app/main.py :
Explications :
- On déclare une instance FastAPI stockée dans la variable app
- On déclare une route GET à la racine renvoyant une paire clé-valeur statique {« Hello »: « World« }.
Concernant le fichier requirements.txt, il va contenir la liste des librairies nécessaires à notre API ainsi que leurs versions :
Tips : avec Python, vous pouvez lister toutes les librairies installées dans votre environnement (avec leurs numéros de versions) via la commande pip freeze, cela vous aidera à remplir votre fichier requirements.txt
Enfin, le plus important, le fichier Dockerfile :
Explications ligne par ligne du fichier Dockerfile
- La commande FROM permet d’utiliser une image préexistante comme base. Cette base est identifiée via son « tag » (ici python:3.9). Docker cherchera cette image de base sur le Docker Hub (chaque tag y est unique) lorsqu’on compilera notre image. Cette commande est toujours la première dans un fichier Dockerfile.
- WORKDIR indique à Docker de se placer dans un répertoire donné au sein du conteneur (ici le répertoire/app) pour la suite des opérations.
-
COPY permet de copier des fichiers depuis votre ordinateur vers le conteneur :
- Le chemin de gauche est l’origine sur votre ordinateur. Dans notre exemple, on indique à Docker de chercher requirements.txt dans le dossier courant de votre ordinateur. - Le chemin de droite est la destination au sein du conteneur. Comme on a défini/app comme « workdir » dans le conteneur, ./requirements.txt est équivalent à /app/requirements.txt - RUN permet d’exécuter une commande shell ; en l’occurrence, nous installons les librairies externes nécessaires pour notre API telles que définies dans requirements.txt
- À nouveau, on utilise COPY pour copier les fichiers de notre API. Pourquoi ne pas avoir tout copié d’un coup deux lignes plus tôt ? Parce que Docker garde en cache le résultat de chaque ligne, donc la compilation de l’image repartira de cette ligne si on change le code de notre API, plutôt que de repartir deux lignes plus haut.
- Enfin, CMD indique à Docker quelle commande exécuter lorsqu’on démarre notre conteneur.
Compiler notre image et lancer un conteneur
Avant de démarrer un conteneur, il faut compiler l’image que nous venons de définir dans le fichier Dockerfile. Pour ce faire, on ouvre un terminal et on se place dans le dossier racine de notre projet (là où se trouve le Dockerfile).
Pour lancer la compilation, on utilise la commande docker build suivante :
Pour lancer la compilation, on utilise la commande docker build suivante :
L’option -t my_api permet de donner un nom à notre image compilée.
Enfin, pour lancer un conteneur, on utilise la commande docker run suivante :
- L’option -p 80:80 indique à Docker de relier le port 80 du conteneur avec le port 80 de votre ordinateur (on a défini le port 80 comme le port utilisé par notre API dans le Dockerfile à l’étape CMD).
- L’option -i (pour « interactive ») permet de voir les logs générés dans le conteneur.
- Élément de liste #1
Vous devriez alors voir l’API démarrer, comme ci-dessous :
Si vous ouvrez votre navigateur à l’adresse http://127.0.0.1/ vous devriez voir s’afficher le résultat de votre API.
Vous venez de conteneuriser votre API, félicitations !
Docker est un outil complexe nécessitant de la pratique, il reste donc beaucoup à apprendre sur les possibilités qu’offre cet outil. Sachez de plus que Saagie est un outil « conteneur natif », toutes les tâches y sont conteneurisées : Docker s’intègre donc parfaitement à vos projets data gérés grâce à Saagie.