1. Introduction : Exécution de la logique de déploiement en arrière-plan
Bonjour ! Dans le dernier article, nous avons configuré l'environnement du serveur de staging et construit ensemble le squelette de base d'un serveur webhook FastAPI qui reçoit les requêtes Webhook de GitHub et vérifie le secret. Dans ce processus, nous avons pu entrevoir la clé de la logique de déploiement réelle grâce aux fonctions handle_deploy
et should_rebuild
incluses dans le fichier main.py
.
Dans cet article, nous allons clarifier le fonctionnement de la logique du gestionnaire de déploiement sommairement abordée dans le précédent article, et nous nous concentrerons sur la façon de enregistrer ce serveur webhook FastAPI en tant que service Systemd afin qu'il soit automatiquement exécuté et fonctionne de manière stable même après un redémarrage du serveur. Votre système de déploiement automatique est maintenant prêt à devenir beaucoup plus robuste !
Si vous n'avez pas consulté les articles précédents, je vous recommande de les lire d'abord.
① Pourquoi implémenter soi-même ?
② Conception de l'architecture et des processus
③ Configuration de l'environnement du serveur de staging et construction du serveur webhook FastAPI
2. Revoir la logique du gestionnaire de déploiement (handle_deploy
)
La fonction handle_deploy
dans le fichier main.py
que nous avons écrite dans l'article précédent est responsable des tâches de déploiement réelles qui s'exécutent en arrière-plan lorsque des requêtes Webhook de GitHub arrivent. Cette fonction joue un rôle clé qui est le suivant.
Je vous recommande de consulter l'exemple de code du précédent article tout en suivant ce guide ci-dessous.
2.1. Gestion de plusieurs projets et configuration des variables d'environnement
Pour gérer plusieurs dépôts (projets) GitHub avec un seul serveur webhook, vous devez indiquer où chaque dépôt se trouve sur le serveur. La fonction handle_deploy
utilise le dictionnaire repo_paths
à cet effet, et ces valeurs sont conçues pour être lues depuis les variables d'environnement du serveur.
Des variables d'environnement telles que SAMPLE_PROJECT_1_PATH
apparaissent dans le code d'exemple. Vous devez définir les chemins réels de chaque projet dans le fichier .env
de votre serveur de staging (ce fichier doit se trouver dans le même répertoire que main.py
du serveur webhook) ou dans le fichier de service systemd
comme suit.
Extrait de code
# ~/projects/webhook_server/.env
# Secret GitHub Webhook (défini dans le 3e article)
GITHUB_WEBHOOK_SECRET="your_github_webhook_secret_value"
# Chemins réels sur le serveur pour chaque projet
SAMPLE_PROJECT_1_PATH="/var/www/my-project1"
SAMPLE_PROJECT_2_PATH="/home/user/another-project"
SAMPLE_PROJECT_3_PATH="/opt/third-project"
La fonction handle_deploy
recherche le chemin de ce projet dans le dictionnaire repo_paths
en utilisant le nom du dépôt transmis dans le payload Webhook. Si aucun chemin mappé n'est trouvé, un avertissement Unknown repository
est affiché et la fonction se termine.
De plus, un code flexible est inclus pour lire des valeurs de configuration supplémentaires telles que DEBUG
ou COLOR
à partir du fichier .env
de chaque projet (par ex. /var/www/my-project1/.env
), qui est utilisé pour la sélection de fichiers Docker Compose (docker-compose.dev.yml
ou docker-compose.prod.yml
) ou pour la configuration du nom de projet Docker. Cela est très utile pour personnaliser les méthodes de déploiement en fonction des caractéristiques de chaque projet.
2.2. Décision de reconstruire l'image Docker (should_rebuild
)
Reconstruire l'image Docker à chaque déploiement est chronophage et inefficace. La fonction should_rebuild
utilise la commande diff
de Git pour détecter si des fichiers clés affectant la construction de l'image Docker comme Dockerfile
, requirements.txt
ou .env
ont été modifiés.
Cette fonction vérifie les différences à l'aide de la commande git diff --name-only HEAD~1
et si la liste des fichiers modifiés contient des fichiers prédéfinis trigger_files
(par ex. Dockerfile
, requirements.txt
, .env
, REBUILD_TRIGGER
, etc.), elle renvoie True
pour indiquer qu'une reconstruction de l'image est nécessaire.
Particulièrement, le fichier REBUILD_TRIGGER
est un truc utile qui force une reconstruction même s'il est vide. Ce fichier peut être créé manuellement sur le serveur pour indiquer qu'une reconstruction de l'image est nécessaire pour une raison autre qu'un git pull
. Si la fonction should_rebuild
détecte ce fichier, elle le supprime automatiquement afin qu'il ne cause pas une reconstruction inutile lors du déploiement suivant.
2.3. Exécution des commandes Git et Docker Compose
La fonction handle_deploy
utilise le module subprocess
de Python pour exécuter les commandes git
et docker compose
sur le serveur.
-
subprocess.run(["git", "-C", repo_path, "pull"], check=True)
: L'optioncheck=True
déclenche unesubprocess.CalledProcessError
si une erreur se produit lors de l'exécution de la commande Git, ce qui permet au code Python de la détecter et de la consigner correctement. L'option-C
permet d'exécuter les commandes Git dans le répertoire spécifié. -
subprocess.run(["docker", "compose", "-p", project_name, "-f", compose_file, "up", "-d", "--build"], check=True)
: Selon le résultat de la fonctionshould_rebuild
, elle exécute soitup -d
, soit ajoute l'option--build
pour déclencher une reconstruction de l'image. L'option-p
spécifie le nom du projet Docker Compose pour éviter les conflits entre plusieurs projets.
Grâce à cette logique, une seule requête Webhook peut extraire le code le plus récent du projet et reconstruire l'image uniquement si nécessaire, permettant ainsi une mise à jour efficace du service.
3. Exécution du serveur webhook FastAPI en tant que service Systemd
Jusqu'à présent, nous avons lancé le serveur webhook manuellement en utilisant la commande uvicorn main:app --reload
. Cependant, si le serveur redémarre, ce processus disparaît, et le service sera interrompu même si la session du terminal se termine. Pour éviter cela et assurer un fonctionnement stable, nous devons enregistrer le serveur webhook FastAPI en tant que service Systemd.
3.1. Pourquoi utiliser Systemd ?
-
Démarrage automatique : le service webhook démarre automatiquement même en cas de redémarrage du serveur.
-
Exécution continue : toujours exécuté en arrière-plan et ne dépend pas de la session terminal.
-
Gestion facile : il est facile de démarrer, d'arrêter, de redémarrer, de vérifier l'état, de consulter les journaux du service avec la commande
systemctl
. -
Efficacité des ressources: Comme expliqué dans l'article 2, le serveur webhook lui-même est une application Python légère exécutée via Systemd, tandis que des outils lourds comme Git ou Docker sont directement utilisés, évitant ainsi une configuration Docker dans Docker ou un augmentation de la taille des conteneurs.
3.2. Création du fichier de service Systemd (*.service
)
Le service Systemd est défini à l'aide d'un fichier .service
, qui doit se trouver dans le répertoire /etc/systemd/system/
. Nous allons créer un fichier nommé github-webhook-deployer.service
. J'ai choisi un nom long pour faciliter l'explication, mais vous pouvez choisir un nom suffisamment court et compréhensible.
# Création du fichier (nécessite des privilèges sudo)
sudo nano /etc/systemd/system/github-webhook-deployer.service
Contenu du fichier :
# /etc/systemd/system/github-webhook-deployer.service
[Unit]
Description=Service GitHub Webhook Deployer
After=network.target # Démarre ce service après l'activation du réseau.
[Service]
User=your_username # Compte utilisateur pour exécuter ce service (ex : ubuntu, your_user)
Group=your_username # Groupe pour exécuter ce service (ex : ubuntu, your_user)
WorkingDirectory=/home/your_username/projects/webhook_server # Répertoire contenant l'application FastAPI
# Configuration des variables d'environnement:
# 1. L'application FastAPI charge elle-même le fichier .env, donc les variables utilisées dans l'application
# n'ont pas nécessairement besoin d'être chargées avec EnvironmentFile. Cependant, si vous souhaitez gérer
# toutes les environnements de manière cohérente au niveau de systemd, vous pouvez laisser le chemin de EnvironmentFile.
# EnvironmentFile=/home/your_username/projects/webhook_server/.env
# 2. Pour appeler des commandes système telles que git, docker, docker compose via subprocess.run(),
# ajoutez explicitement les chemins où ces commandes sont situées à la variable PATH.
# Le chemin d'exemple ci-dessous inclut les chemins des systèmes Linux typiques et ceux de l'environnement virtuel Python.
# Adaptez 'your_username' et 'venv' en fonction de votre environnement réel.
# Vous pouvez vérifier le chemin exact dans le fichier .bashrc du serveur ou en utilisant la commande 'echo $PATH'.
Environment="PATH=/home/your_username/projects/webhook_server/venv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
ExecStart=/home/your_username/projects/webhook_server/venv/bin/uvicorn main:app --host 0.0.0.0 --port 8000 # Utilisation du chemin Uvicorn de l'environnement virtuel
Restart=always # Redémarre automatiquement le service s'il cesse de fonctionner.
StandardOutput=journal # Envoie la sortie standard au journal Systemd.
StandardError=journal # Envoie les erreurs standard au journal Systemd.
[Install]
WantedBy=multi-user.target # Le service se lance automatiquement au démarrage de l'état multi-utilisateur (état normal du serveur).
Explication :
-
[Unit]
section : Définit des informations générales sur le service (description, dépendances).After=network.target
permet de démarrer ce service uniquement après que le service réseau soit opérationnel. -
[Service]
section : Définit comment le service doit être exécuté.-
User
,Group
: Utilisateur et groupe pour exécuter le service. Doit être un utilisateur ayant les droits Docker (par ex. défini avecsudo usermod -aG docker your_username
). -
WorkingDirectory
: Répertoire où se trouve le fichiermain.py
de l'application FastAPI. -
Environment="PATH=..."
: Ce point est crucial. Lorsque vous appelez des commandes externes (commegit
,docker
,docker compose
) viasubprocess.run()
, la variable d'environnementPATH
dans l'environnement systemd peut être différente de celle définie dans.bashrc
. Par conséquent, vous devez spécifier explicitement le chemin du exécutableuvicorn
de l'environnement virtuel (/home/your_username/projects/webhook_server/venv/bin
) ainsi que les chemins d'exécution de base du système (/usr/local/bin
,/usr/bin
, etc.). -
EnvironmentFile
(optionnel) : L'application FastAPI charge son propre fichier.env
à traverspython-dotenv
, donc les variables d'environnement internes (par ex.GITHUB_WEBHOOK_SECRET
,SAMPLE_PROJECT_N_PATH
, etc.) n'ont pas besoin d'être chargées via cette option. Cependant, pour que systemd charge de manière explicite ces variables avant de démarrer le service (afin de fournir un environnement uniforme à tous les processus exécutés paruvicorn
), l'utilisation deEnvironmentFile
peut être une option valide. Cela peut être commenté ou maintenu selon la préférence de l'utilisateur. -
ExecStart
: Commande réelle pour démarrer le service. Le chemin du fichier exécutableuvicorn
de l'environnement virtuel doit être précisé correctement.--host 0.0.0.0 --port 8000
indique que le serveur doit accepter les requêtes sur le port 8000 depuis n'importe quelle IP. -
Restart=always
: Si le service cesse de fonctionner pour une raison quelconque, systemd tentera automatiquement de le redémarrer. -
StandardOutput=journal
,StandardError=journal
: Toutes les sorties et erreurs du service sont envoyées au système de journalisation intégré de systemd,journalctl
.
-
-
[Install]
section: Définit quel but (target) active le service.WantedBy=multi-user.target
fait en sorte que le service démarre automatiquement lors du démarrage du serveur dans son état normal (multi-utilisateur).
3.3. Enregistrement et démarrage du service Systemd
Après avoir créé le fichier de service, vous devez le faire reconnaître par systemd et démarrer le service.
# Avertir systemd du nouveau fichier de service.
sudo systemctl daemon-reload
# Paramétrer le service pour démarrer automatiquement au démarrage.
sudo systemctl enable github-webhook-deployer.service
# Démarrer le service.
sudo systemctl start github-webhook-deployer.service
# Vérifier l’état du service. Devrait afficher 'active (running)'.
sudo systemctl status github-webhook-deployer.service
Votre serveur webhook FastAPI est maintenant configuré pour s'exécuter automatiquement même après un redémarrage du serveur, et il attend de manière stable les requêtes webhook en arrière-plan.
4. Surveillance et débogage du service webhook FastAPI
L'utilisation de services Systemd facilite la vérification des journaux et le diagnostic des problèmes.
- Vérifier l'état du service :
sudo systemctl status github-webhook-deployer.service
Cette commande montre l'état actuel du service, la dernière heure d'exécution et l'ID du processus.
- Vérification des journaux en temps réel :
sudo journalctl -u github-webhook-deployer.service -f
L'option -u
permet de voir les journaux d'un service spécifique et l'option -f
affiche les nouveaux journaux en temps réel. À chaque fois qu'une requête webhook arrive, les messages de journalisation définis dans main.py
apparaîtront ici.
Si le service ne démarre pas ou ne fonctionne pas comme prévu, vous devriez d'abord consulter les journaux journalctl
pour rechercher les messages d'erreur.
5. Conclusion : Annonce du prochain article
Dans cet article 4, nous avons clarifié le fonctionnement de la logique du gestionnaire de déploiement que nous avons mise en œuvre dans l'article 3, et nous avons examiné l'une des étapes les plus importantes : comment enregistrer le serveur FastAPI webhook en tant que service Systemd pour un fonctionnement stable. Maintenant, votre serveur webhook fonctionnera sans faille même après un redémarrage du serveur.
Dans le prochain article 5, nous complèterons les dernières pièces du puzzle pour finaliser le système. Nous aborderons le processus de configuration de Nginx en tant que proxy inverse pour exposer le serveur webhook en toute sécurité, d'application de HTTPS pour renforcer la sécurité, et enfin d'intégration du webhook sur le dépôt GitHub pour tester le déploiement automatique réel. Restez à l'écoute !
Aucun commentaire.