Aller au contenu
Développement medium

Automatiser l’administration SSH avec Fabric

14 min de lecture

logo python

Python Fabric simplifie l’administration distante grâce à l’automatisation des tâches via SSH. Avec son approche basée sur les fabfiles, Fabric permet d’exécuter facilement des commandes sur plusieurs serveurs, de déployer rapidement des applications et de gérer les infrastructures avec quelques lignes de code Python. Pourquoi continuer à exécuter manuellement des scripts répétitifs quand Fabric peut le faire pour vous ? Découvrez dans ce guide comment gagner du temps et automatiser efficacement vos déploiements.

Pour commencer à utiliser Python Fabric, vous avez besoin d’un environnement Python configuré et d’un accès SSH fonctionnel à vos serveurs distants.

Fabric communique avec vos serveurs via SSH, il est donc recommandé d’utiliser une authentification par clés SSH pour éviter les connexions par mot de passe répétées.

Si vous n’avez pas encore configuré de clés SSH, générez-en une sur votre machine locale avec la commande :

Fenêtre de terminal
ssh-keygen -t rsa -b 4096 -C "email@example.com"

Envoyez ensuite votre clé publique vers votre serveur distant :

Fenêtre de terminal
ssh-copy-id utilisateur@votre-serveur

Vérifiez que votre connexion SSH sans mot de passe est fonctionnelle :

Fenêtre de terminal
ssh utilisateur@votre-serveur

Si vous êtes connecté directement sans demande de mot de passe, vous êtes prêt à utiliser Fabric.

L’installation de Fabric est très simple grâce au gestionnaire de paquets pipx qui crée un environnement isolé pour chaque application Python. Voici les étapes à suivre :

Fenêtre de terminal
pipx install fabric

Pour vérifier que Fabric est correctement installé, exécutez la commande suivante :

Fenêtre de terminal
fab --version

Vous devriez obtenir une sortie semblable à celle-ci :

Fenêtre de terminal
Fabric 3.2.2
Paramiko 3.4.0
Invoke 2.2.0

Fabric repose sur l’utilisation d’un fichier nommé fabfile.py, où vous définissez vos tâches (tasks). Ce fichier est le cœur de vos scripts d’automatisation.

Un fabfile se compose de fonctions Python décorées avec l’annotation @task, indiquant à Fabric que ces fonctions peuvent être exécutées à distance :

from fabric import task
@task
def mise_a_jour(c):
c.run('sudo apt update && sudo apt upgrade -y')

Dans cet exemple :

  • mise_a_jour est une tâche simple qui exécute une commande sur le serveur distant pour mettre à jour les paquets.

Pour vérifier que votre fabfile fonctionne, vous pouvez exécuter la commande suivante :

Fenêtre de terminal
fab --list
Available tasks:
mise-a-jour

Vous remarquez que le nom de la tâche est automatiquement converti en snake_case. Pour exécuter la tâche mise_a_jour, utilisez la commande suivante en remplaçant <user> et <host> par vos informations de connexion SSH :

Fenêtre de terminal
fab -H <user>@<host> mise-a-jour

Fabric établit une connexion SSH automatique et exécute la commande définie. Vous verrez une sortie détaillée affichée directement dans votre terminal, comme ceci :

Fenêtre de terminal

Vous pouvez facilement passer des arguments à vos tasks pour les rendre réutilisables. Exemple avec une tâche qui redémarre un service spécifique :

from fabric import task
@task
def redemarrer_service(c, nom_service):
c.run(f'sudo systemctl restart {nom_service}')

L’exécution se fait alors en spécifiant l’argument :

Fenêtre de terminal
fab -H utilisateur@serveur-distant redemarrer_service --nom-service=nginx

Fabric permet d’exécuter une commande sur votre machine locale à partir de votre fabfile.py grâce à la fonction local.

from fabric import task
@task
def sauvegarde_locale(c):
c.local('tar -czf sauvegarde.tar.gz /chemin/dossier')

L’exécution se fait simplement via :

Fenêtre de terminal
fab sauvegarde-locale

Pour exécuter une commande nécessitant les privilèges root sur le serveur distant, Fabric fournit la méthode sudo :

from fabric import task
@task
def redemarrer_nginx(c):
c.sudo('systemctl restart nginx')

Cette commande vous demandera un mot de passe si votre utilisateur n’est pas configuré en sudo sans mot de passe :

Fenêtre de terminal
fab -H utilisateur@serveur-distant redemarrer_nginx

Fabric offre aussi des outils pratiques pour gérer le contexte d’exécution :

  • Changer de répertoire (cd) :
from fabric import task
@task
def deploy(c):
with c.cd('/var/www/monapp'):
c.run('git pull')
  • Ajouter un préfixe (prefix) (par exemple, pour activer un virtualenv) :
from fabric import task
@task
def deploy_app(c):
with c.prefix('source /env/bin/activate'):
c.run('pip install -r requirements.txt')
  • Modifier temporairement la variable d’environnement PATH (path) :
from fabric import task
@task
def execute_script(c):
with c.path('/opt/scripts', behavior='prepend'):
c.run('script_personnalise.sh')

Grâce à ces fonctions, Fabric simplifie considérablement l’exécution cohérente et structurée de vos commandes locales et distantes.

Fabric facilite également le transfert de fichiers entre votre machine locale et le serveur distant.

  • put : pour envoyer des fichiers vers le serveur distant.
  • get : pour récupérer des fichiers depuis le serveur distant.

Exemple d’utilisation :

from fabric import task
@task
def envoyer_fichier(c):
c.put('mon_fichier.txt', '/tmp/mon_fichier.txt')
@task
def recuperer_fichier(c):
c.get('/tmp/mon_fichier.txt', 'mon_fichier.txt')

Python Fabric excelle particulièrement dans l’automatisation des déploiements d’applications. Voici comment automatiser simplement votre déploiement grâce à quelques lignes de Python.

Imaginons une application hébergée sur GitHub que vous souhaitez déployer rapidement sur votre serveur distant :

from fabric import task
@task
def deploy(c):
with c.cd('/var/www/mon_app'):
c.run('git pull origin main')
c.sudo('systemctl restart mon_app.service')

Ce script réalise en une seule tâche :

  1. Le téléchargement des dernières modifications depuis GitHub.
  2. Le redémarrage automatique du service lié à votre application.

Exécutez simplement :

Fenêtre de terminal
fab -H utilisateur@serveur-distant deploy

Fabric permet également d’effectuer des déploiements en parallèle sur plusieurs serveurs à la fois. Cela accélère considérablement les mises à jour en environnement de production :

Fenêtre de terminal
fab -H web1,web2,web3 --parallel deploy

Chaque serveur exécute indépendamment le déploiement en simultané, réduisant drastiquement le temps nécessaire à la mise à jour globale.

Fabric s’arrête par défaut si une erreur se produit. Vous pouvez contrôler ce comportement grâce au paramètre warn=True :

@task
def deploy(c):
with c.cd('/var/www/mon_app'):
result = c.run('git pull origin main', warn=True)
if result.failed:
print("Erreur lors de la mise à jour du dépôt Git")
else:
c.sudo('systemctl restart mon_app.service')

Fabric peut également déployer différentes branches selon vos besoins (production, test…) :

@task
def deploy(c, branche='main'):
with c.cd('/var/www/mon_app'):
c.run(f'git checkout {branche}')
c.run('git pull')
c.sudo('systemctl restart mon_app.service')

Utilisation :

Fenêtre de terminal
fab -H serveur-prod deploy --branche=prod
fab -H serveur-test deploy --branche=develop

Grâce à ces techniques, Fabric facilite et accélère vos déploiements tout en limitant les erreurs humaines.

Utiliser Group pour exécuter sur plusieurs hôtes

Section intitulée « Utiliser Group pour exécuter sur plusieurs hôtes »

Fabric propose un outil puissant pour exécuter des tâches sur plusieurs serveurs à la fois : l’objet Group. Il permet de gérer un groupe de connexions distantes de manière simple et cohérente, notamment pour les déploiements multi-hôtes.

Un Group représente une liste de connexions SSH. Voici comment l’utiliser :

from fabric import task, Group
@task
def uptime_group(c):
group = Group("web1", "web2", "web3")
for connection in group:
connection.run("uptime")

Chaque hôte défini dans le groupe exécutera la commande uptime indépendamment.

Vous pouvez spécifier le nom d’utilisateur, la clé SSH ou d’autres options globales au moment de la création du groupe :

group = Group(
"web1", "web2", "web3",
user="admin",
connect_kwargs={"key_filename": "~/.ssh/id_rsa"}
)

Pour aller plus loin, utilisez ThreadingGroup (fourni par le module fabric.connection) pour exécuter les commandes en parallèle, ce qui est idéal lors de déploiements sur plusieurs machines :

from fabric import task
from fabric.connection import ThreadingGroup
@task
def deploy_parallel(c):
hosts = ["web1", "web2", "web3"]
group = ThreadingGroup.from_connections([
c.clone(host=host) for host in hosts
])
group.run("git -C /var/www/app pull origin main")
group.sudo("systemctl restart mon_app.service")

Vous pouvez facilement capturer les erreurs et afficher les résultats pour chaque hôte :

for connection in group:
result = connection.run("uptime", warn=True)
if result.failed:
print(f"{connection.host} : commande échouée")

Pour une meilleure organisation de vos tâches, vous pouvez structurer votre fabfile.py en plusieurs fichiers. Par exemple, créez un dossier fabfile/ et placez-y vos scripts :

Fenêtre de terminal
fabfile/
├── __init__.py
├── deploy.py # Tâches de déploiement
├── system.py # Mises à jour système, gestion des services
└── db.py # Sauvegardes, migrations, nettoyages

Dans le fichier __init__.py, importez les tâches pour les rendre accessibles :

from .deploy import deploy
from .system import mise_a_jour, redemarrer_service
from .db import sauvegarde, migration

Dans le fichier deploy.py, définissez vos tâches de déploiement :

from fabric import task
@task
def deploy(c):
c.run('git pull origin main')
c.sudo('systemctl restart mon_app.service')

Dans les autres fichiers, ajoutez les tâches correspondantes.

Un fabfile bien structuré rend vos automatisations plus lisibles, maintenables et évolutives. Voici les meilleures pratiques à adopter pour tirer le meilleur parti de Fabric.

Choisissez des noms explicites et en français ou anglais selon votre convention d’équipe :

@task
def redemarrer_nginx(c): ...

Cela facilite l’appel via la CLI :

Fenêtre de terminal
fab redemarrer_nginx

Fabric extrait la première ligne de docstring pour l’afficher dans fab --list. Exemple :

@task
def deploy(c):
"""Déploie la dernière version de l'application"""
...

Résultat :

Fenêtre de terminal
Available tasks:
deploy Déploie la dernière version de l'application

Utilisez warn=True pour éviter qu’un échec ne stoppe tout le processus, et traitez les erreurs manuellement si nécessaire :

result = c.run('git pull', warn=True)
if result.failed:
print("Échec du pull Git")

Les arguments de tâches rendent vos scripts adaptables :

@task
def restart_service(c, name):
"""Redémarre un service donné"""
c.sudo(f'systemctl restart {name}')

Appel :

Fenêtre de terminal
fab restart_service --name=nginx

Ajoutez un fichier README.md dans votre répertoire fabfile/ expliquant comment installer, configurer et utiliser vos tâches.

Si votre priorité est d’avoir un outil d’automatisation rapide à mettre en place, lisible et intégrable facilement à des scripts Python existants, Fabric constitue une excellente alternative à Ansible. Mais attention, Fabric n’est pas conçu pour gérer des configurations complexes ou des infrastructures massives. Il est plus adapté pour des tâches simples et des déploiements rapides.

Fabric est un outil puissant pour automatiser vos tâches d’administration système et de déploiement d’applications. Grâce à sa simplicité d’utilisation, vous pouvez rapidement mettre en place des scripts pour gérer vos serveurs distants, déployer vos applications et automatiser les tâches répétitives.