Déploiement continu d’une API de production avec supervision et tests automatisés
Une PME de services numériques DataSense développe une API REST interne pour exposer des données métiers à différentes équipe. L’API se nomme : ProdX
Le problème : les déploiements sont encore manuels, source d’erreurs, et les tests ne sont pas systématiques.
L’objectif est donc de mettre en place une chaîne CI/CD GitLab complète, du commit au déploiement automatisé, tout en assurant la qualité du code et la stabilité des versions déployées.
Concevoir et documenter un pipeline GitLab CI qui permette de :
Vous devez avoir exécuté les instances docker, ci et runner fonctionnelles.
Sur votre Gitlab, en tant que root, activez l’import de projet depuis un URL.

Retournez en utilisateur classique Gitlab (votre nom) et importez un projet (New project > Import Project), et précisez l’URL :
https://gitlab.differangles.fr/bcallar/cicd-tp-final.git
Le projet est une API REST développée en Python 3.12 mettant à disposition les fonctions CRUD (Create, Read, Update and Delete) sur une table SQL « products ».
Les sources de l’API sont dans le dossier backend.
La base de données est stockée dans un serveur Mysql ou Mariadb.
La gestion des dépendances est réalisée grâce à poetry (qu’il est nécessaire d’installer au préalable avec pip), deux commandes peuvent être lancée :
Le schéma de base de données est géré grâce à alembic.
Les tests unitaires sont exécutés grâce à pytest, et le lint est réalisé grâce black et flake8.
Le processus de développement logiciel est le Domain Driven Design, de ce fait, l’échange entre les éléments se fait grâce à pydantic.
L’application est versionnée. Afin de changer la version, il faut lancer la commande : poetry run version X.Y.Z, ou X.Y.Z est la version voulue.
Au lancement de l’application, il est nécessaire dans un premier temps de mettre à jour la base de données avec la commande : alembic upgrade head, puis ensuite de lancer le serveur grâce à la commande : poetry run web_server.
Afin de se lancer, l’API a besoin de la variable d’environnement suivante :
Une fois lancée, le swagger de l’API est accessible à l’url https://gitlab.differangles.fr/bcallar/cicd-tp-final.git, vous pouvez avoir accès aux fonctions CREATE, READ, UPDATE et DELETE. Il est vivement conseillé de tester toutes ces fonctions manuellement une fois afin de comprendre et être sûr que l’API fonctionne.
Plus d’informations sont disponibles dans le README du dossier backend.
En partant de votre nouveau projet, créer une nouvelle branche add-ci et réalisez votre première pipeline CI comprenant les étapes suivantes :
Si ce n’est pas déjà fait, vous pouvez vous baser sur l’Annexe 1 pour configurer votre runner pour build des images docker.
Une fois cette CI terminée, faites un merge de la branche add-ci sur main.
Sur votre instance docker, déployez les conteneurs suivants (un seul docker compose peut suffire) :
Comme pour la partie CI, partez de la branche main et créez une nouvelle branche add-cd, puis mettez à jour votre CI/CD pour y ajouter une étape :
Créez une nouvelle version de l’application en lancant la commande poetry run version 1.0.1 depuis le dossier backend. Vérifiez qu’au bout d’une minute la version est mise à jour (dans le /docs).
Notre runner Gitlab tourne actuellement avec Docker. Pour des raisons de sécurité, les conteneurs docker sont lancés avec beaucoup de restrictions et notamment impossibilité pour un conteneur de build ou run un autre conteneur.
Afin de faire cela plusieurs solutions s’offre à nous :
Monter le fichier docker.sock à l’interieur du conteneur. Solution non sécurisée, les jobs ont accès aux autre jobs. Acceptable pour un runner projet réservé.
Changer la méthode de lancement de Job vers une solution plus scalable et privilégié comme avec docker-autoscale qui pourrait lancer des instances EC2 à la volée, et donc avec des droits nécessaires à la création d’image. Solution très sécurisé car les ressources sont très isolées et éphémères mais assez complexe à mettre en place. Cette solution est d’ailleurs la solution utilisée par le runner publics de Gitlab.
Utiliser un autre builder d’image, possiblement rootless comme buildkit ou buildah. Cependant cette solution nécessite de dévérrouiler certaines couches d’isolation et ne sera donc pas privilégiée
Utiliser docker-in-docker (dind) avec un conteneur dind lui même privilégié mais le client build lui ne l’est pas. Cette solution est plutôt sécurisé car dind permet d’exécuter un environnement docker isolé et donc le job ne peux pas accéder aux autres Job (images, ...). C’est cette solution qui sera envisagée. En plus de cette solution, quelques optimisations sont à envisager :
Les différentes méthodes sont expliquées dans le lien de la documentation officielle.
https://docs.gitlab.com/ci/docker/using_docker_build/#use-docker-in-docker
Sur le runner Gitlab, modifiez le fichier /etc/gitlab-runner/config.toml et dans la section [runners.focker], rajoutez :
[runners.docker]
...
services_privileged = true
allowed_privileged_services = ["docker.io/library/docker:*-dind", "docker.io/library/docker:dind", "docker:*-dind", "docker:dind"]
volumes = ["/runner/services/docker"]
Dans votre pipeline GitLab-ci il vous suffira d’apper Docker-dind lorque vous aurez besoin de build des images.
job:
variables:
# This variable is shared by both the DinD service and Docker client.
# For the service, it will instruct DinD to create `docker.sock` here.
# For the client, it tells the Docker client which Docker Unix socket to connect to.
DOCKER_HOST: "unix:///runner/services/docker/docker.sock"
services:
- docker:24.0.5-dind
image: docker:24.0.5-cli
script:
- docker version