Previous slide Next slide Toggle fullscreen Toggle overview view Open presenter view
Partie I : L'Enfer du YAML
L'Infrastructure as Code est devenue l'Infrastructure as YAML
Et personne n'avait demandé ça
Le 10ème cercle de Dante, c'était juste un fichier YAML avec une mauvaise indentation
Vous vous souvenez de cette promesse ?
Infrastructure as Code → Infrastructure as YAML
On nous a menti
Code : "Un langage de programmation lisible par l'humain"
YAML : "Un fichier de définition lisible par la machine" (à peine)
L'un est du code, l'autre est un appel à l'aide.
L'état actuel du DevOps
"Simplifions la gestion de l'infrastructure !"
Et voilà ce qu'on a créé :
- name: Deploy application
hosts: all
vars:
deploy_state: "{{ lookup('env', 'STATE') |
default('present') }} "
tasks:
- name: Ensure application is {{ deploy_state }}
when: ansible_os_family == "Debian" and
not (ansible_distribution == "Ubuntu" and
ansible_distribution_version is
version('20.04', '>=' ))
Sur-simplifié, et pourtant sur-compliqué
Voilà ce qui arrive quand on demande à un fichier de config d'être un langage de programmation
Le cauchemar du développeur
Sensibilité à l'indentation → 2 espaces ? 4 ? Des tabulations ? Déploiement annulé.
L'enfer du templating → Du Jinja2 dans du YAML dans du Jinja2 ({{ "{{" }} inception {{ "}}" }})
Pas de vraies fonctions → Copier-coller des "roles" partout
Du debug ? → "ERROR: undefined variable" quelque part dans 47 fichiers
Support IDE ? → Du feeling et des prières
Le problème de la Norvège → country: NO devient country: false
Les messages d'erreur Ansible
TASK [Deploy app] *******************
fatal: [web01]: FAILED! => {"msg": "The task includes
an option with an undefined variable. The error was:
'dict object' has no attribute 'nonexistent'\n\nThe
error appears to be in '/playbook.yml': line 42,
column 3, but may be elsewhere in the file depending
on the exact syntax problem."}
"quelque part dans le fichier" — Merci, super utile !
Ajouter -vvvv et scroller 1000 lignes d'output ?
Les tests Ansible
Yo mec, j'ai entendu que t'aimais le YAML alors j'ai mis du YAML dans tes tests YAML
import pytest
Pas de pdb. Pas de breakpoint(). Juste... debug: msg="{{ variable }}".
Partie II : PyInfra entre en scène
Votre infrastructure. Du vrai Python.
Tout est en Python (y compris votre santé mentale)
>>> import antigravity
>>> from yaml import pain
ImportError: No more. We're done here.
>>> import pyinfra
>>> # *chef' s kiss*
C'est quoi PyInfra ?
Du code Python en entrée, des commandes shell en sortie
pyinfra transforme du code Python en commandes shell et les exécute sur vos serveurs.
Exécuter des commandes ad-hoc
Écrire des opérations déclaratives
Cibler des serveurs SSH, la machine locale, des conteneurs Docker
Passe à l'échelle d'un à des milliers de serveurs
Pas besoin de Python sur les systèmes cibles — juste un accès shell POSIX !
Phase 1 : Collecte des faits
PyInfra se connecte aux hôtes et collecte des faits sur l'état actuel :
Paquets installés, services en cours, checksums des fichiers
Détails de l'OS, configuration réseau, utilisateurs
Phase 2 : Exécution des opérations
PyInfra compare l'état souhaité avec les faits actuels :
Génère uniquement les commandes shell nécessaires
Ignore les opérations dont l'état correspond déjà
Exécute les commandes en parallèle sur les hôtes
Résultat : Changements minimaux, efficacité maximale, vraie idempotence
Le concept de base
from pyinfra.operations import apt, systemd
apt.packages(
name="Install nginx" ,
packages=["nginx" ],
)
systemd.service(
name="Restart and enable the nginx service" ,
service="nginx.service" ,
running=True ,
restarted=True ,
enabled=True ,
)
Du Python en entrée, du shell en sortie.
Attendez... C'est juste du Python !
EXACTEMENT !
De vraies def functions() qui marchent vraiment
De vraies for loops sans gymnastique with_items
De vrais if/else sans spaghetti Jinja2
De vrais import et pytest
Type hints & autocomplétion → mypy approuve
List comprehensions → [server for server in fleet if server.is_alive()]
Opérations déclaratives
Ne faire des changements que quand c'est nécessaire
PyInfra intègre la vérification de diff et des opérations idempotentes
apt.packages(packages=["nginx" ])
systemd.service(service="nginx" , running=True )
files.put(src="config.j2" , dest="/etc/nginx/nginx.conf" )
De l'infrastructure déclarative avec du vrai code
Architecture sans agent
Zéro dépendance sur les systèmes cibles
Déployez sur n'importe quel système avec un accès shell POSIX
Pas d'agents à installer, pas de démons à gérer
Pas de bootstrapping nécessaire
Juste SSH et un shell.
Fonctionne avec : Linux, macOS, BSD, conteneurs, VMs cloud, bare metal, routeurs
Connecteurs : ciblez n'importe quoi
pyinfra @ssh/web1.example.com deploy.py
pyinfra @local deploy.py
pyinfra @docker/my-container deploy.py
pyinfra inventory.py deploy.py
ssh_hosts = ["web1" , "web2" , "db1" ]
docker_hosts = [("@docker/app" , {"env" : "staging" })]
local = ["@local" ]
Un outil. Toutes les cibles.
Totalement extensible
Profitez de tout l'écosystème de packages Python
import requests
hosts = requests.get("https://api/hosts" ).json()
import boto3
instances = boto3.client('ec2' ).describe_instances()
from slack_sdk import WebClient
slack = WebClient(token=TOKEN)
slack.chat_postMessage(channel="#ops" , text="Deploy complete!" )
Pas de plugins custom. Juste pip install. Plus de 400 000 packages sur PyPI.
Intégrez PyInfra partout
C'est une bibliothèque, pas juste un CLI
from pyinfra.api import Config, Inventory, State
from pyinfra.api.operations import run_ops
from pyinfra.operations import server
inventory = Inventory((["web1.example.com" ], {}))
state = State(inventory, Config())
server.shell(commands=["echo 'Deployed from my Flask app!'" ])
run_ops(state)
De l'automatisation d'infrastructure dans VOTRE appli
Intégration transparente
Récupérez l'inventaire depuis Terraform, Coolify, ou n'importe quelle API
Exécutez sur des conteneurs Docker
Intégrez dans Django, FastAPI, des outils CLI
import requests
hosts = requests.get("https://api/hosts" ).json()
from datetime import datetime
if datetime.now().hour > 20 :
print ("Pas de déploiement après 20h !" )
exit(1 )
Partie III : PyInfra vs Ansible
En quoi c'est mieux ?
Comptons les avantages...
Ansible :
Séquentiel par défaut
Couches d'abstraction lourdes
Python requis sur la cible
PyInfra :
Multiplexage SSH efficace
Exécution parallèle intégrée
Commandes shell directes
Passe à l'échelle sur des milliers de serveurs
Jusqu'à 10x plus rapide en déploiement
Face à face : installation de paquets
Ansible (YAML verbeux)
- name: Install packages
hosts: webservers
become: yes
tasks:
- name: Update apt cache
apt:
update_cache: yes
- name: Install packages
apt:
name: "{{ item }} "
state: present
with_items:
- nginx
- postgresql
- redis
18 lignes pour installer 3 paquets
Face à face : installation de paquets
PyInfra (du Python propre)
from pyinfra.operations import apt
apt.packages(
packages=["nginx" , "postgresql" , "redis" ],
update=True ,
)
6 lignes contre 18
Face à face : logique conditionnelle
Ansible
- name: Configure based on environment
template:
src: "{{ 'prod.j2' if env == 'production'
else 'dev.j2' }} "
dest: /etc/app/config
when: env is defined
PyInfra
template = "prod.j2" if env == "production" else "dev.j2"
files.template(src=template, dest="/etc/app/config" )
Juste du Python. Pas de gymnastique Jinja2.
Face à face : les boucles
Ansible
- name: Create users
user:
name: "{{ item.name }} "
groups: "{{ item.groups }} "
with_items:
- { name: alice , groups: sudo }
- { name: bob , groups: developers }
when: item.name != 'root'
Face à face : les boucles
PyInfra
users = [
{"name" : "alice" , "groups" : ["sudo" ]},
{"name" : "bob" , "groups" : ["developers" ]}
]
for user in users:
if user["name" ] != "root" :
server.user(user.name, groups=user.groups)
Les list comprehensions > with_items
Debug : retour instantané
Ansible
Ajouter le flag -vvvv et scroller des milliers de lignes
Utiliser des tâches debug
Bonne chance pour trouver la vraie erreur
PyInfra
Output des commandes shell en temps réel
Utiliser pdb (breakpoint() fonctionne directement)
Support du debugger IDE avec des breakpoints
Messages d'erreur : de vraies stack traces
Traceback (most recent call last):
File "deploy.py" , line 42 , in <module>
config["nonexistent" ]
KeyError: 'nonexistent'
Fichier exact, ligne, et erreur. Fini le "may be elsewhere".
Tests : de vrais tests unitaires
PyInfra
import pytest
from deploy import setup_nginx
def test_nginx_config ():
config = setup_nginx("production" )
assert "ssl" in config
assert config["worker_processes" ] == 4
C'est du Python. Testez-le comme du Python.
Support IDE : développement moderne
Ansible
Coloration syntaxique YAML basique
Peut-être un peu de linting
Pas d'autocomplétion, pas de refactoring
PyInfra
Autocomplétion complète avec type hints
Documentation inline
Support du refactoring (renommer, extraire)
Aller à la définition
Réutilisation de code : modules Python
Ansible
Copier-coller des rôles depuis Galaxy
Personnaliser avec 5 répertoires différents
Se battre avec les dépendances de rôles
PyInfra
import vos fonctions
Utilisez plus de 400 000 packages PyPI
Écrivez du code propre et modulaire
from my_company.infra import setup_monitoring, configure_firewall
Bénéfices en production
Jusqu'à 10x plus rapide qu'Ansible
70% de code en moins à maintenir
Vraie réutilisation de code via import
5x plus rapide en développement avec le support IDE
De vrais tests unitaires avec pytest
Les juniors comprennent — ils ont appris Python
Passe à l'échelle sur des milliers de serveurs
Intégrable dans vos applis
Mais et si...
"Ansible a des milliers de modules !"
PyInfra a plus de 400 000 packages Python. pip install requests > module Ansible custom.
"Tout le monde connaît Ansible !"
Tout le monde connaît mieux Python. Et déteste débuguer Ansible.
"Le déclaratif c'est mieux !"
PyInfra EST déclaratif. Vérification de diff, opérations idempotentes. Avec du vrai code.
Mais et si... (suite)
"Et les dépendances sur les systèmes cibles ?"
Zéro. Sans agent. N'importe quel système avec un accès shell POSIX.
"Mais j'ai besoin de l'intégration Terraform/Docker !"
PyInfra fait les deux. Question suivante ?
"Le changement fait peur !"
Votre playbook de 5000 lignes que personne n'ose toucher aussi.
Chemin de migration
Commencez petit — Un playbook à la fois
Utilisez votre IDE — Autocomplétion, refactoring
Profitez de Python — packages pip, stdlib
Testez en local — pyinfra @local deploy.py
Dormez mieux — Fini le debug à 3h du mat'
De nombreuses équipes ont migré avec succès d'Ansible vers pyinfra.
Prêt pour la production ?
Prêt pour la production
Éprouvé au combat — Des entreprises dans le monde entier gèrent leur prod avec
APIs stables — Pas de casse entre les versions
Couverture de tests complète
Maintenance active — Releases régulières
Licence MIT — Open source et gratuit pour toujours
Lancez-vous aujourd'hui !
pip install pyinfra
from pyinfra.operations import apt, systemd
apt.packages(name="Install nginx" , packages=["nginx" ])
systemd.service(
name="Start nginx" ,
service="nginx.service" ,
running=True ,
enabled=True ,
)
pyinfra @localhost deploy.py
C'est tout. De l'IaC avec du vrai code.
Arrêtez le YAML, passez au Python
Venez me voir après pour discuter de :
Vos histoires d'horreur Ansible (thérapie de groupe )
Stratégies de migration
Pourquoi le YAML vous a fait du mal
Comment import pyinfra peut vous guérir
Contribuez
resources = {
"docs" : "docs.pyinfra.com" ,
"github" : "github.com/pyinfra-dev/pyinfra" ,
"pypi" : "pip install pyinfra" ,
"examples" : "github.com/pyinfra-dev/pyinfra/tree/3.x/examples" ,
}
Starrez le repo • Essayez aujourd'hui • Ne touchez plus jamais au YAML
SCRIPT: "PyInfra n'est pas qu'un CLI — c'est une bibliothèque. Intégrez-la dans Django, FastAPI, n'importe où."
SCRIPT: "C'est juste du Python. Récupérez l'inventaire depuis Terraform, ajoutez des freezes de déploiement, bloquez les déploiements du vendredi — tout en Python standard."
SCRIPT: "PyInfra versus Ansible. Comptons les avantages..."
SCRIPT: "Jusqu'à 10x plus rapide. Multiplexage SSH, exécution parallèle, commandes shell directes."
SCRIPT: "18 lignes de YAML pour installer 3 paquets."
SCRIPT: "PyInfra : 6 lignes. Un import, un appel de fonction, terminé."
SCRIPT: "Logique conditionnelle : du Jinja2 dans du YAML vs une expression ternaire."
SCRIPT: "Les boucles. En Ansible : with_items, with_dict, with_file, with_nested... En Python : une boucle for."
SCRIPT: "En PyInfra : une boucle for. Celle que vous avez apprise la première semaine de Python."
SCRIPT: "Debug : -vvvv et scroller des milliers de lignes, ou utiliser pdb comme une personne civilisée."
SCRIPT: "PyInfra : fichier, numéro de ligne, problème exact. KeyError à la ligne 42. Terminé."
SCRIPT: "Tests : import pytest, écrire des tests. Pas de molecule, pas de test kitchen."
SCRIPT: "Support IDE : coloration YAML vs autocomplétion complète, refactoring, aller à la définition."
SCRIPT: "Réutilisation de code : copier des rôles depuis Galaxy ou juste importer un module."
SCRIPT: "10x plus rapide. 70% de code en moins. Les juniors comprennent parce qu'ils ont appris Python."
SCRIPT: "Objections : Ansible a des modules ? PyInfra a 400k packages. Tout le monde connaît Ansible ? Tout le monde déteste le debug."
SCRIPT: "Zéro dépendance sur les cibles. Intégration Terraform et Docker. Le changement fait peur — le playbook de 5000 lignes aussi."
SCRIPT: "Commencez petit. Prenez un playbook. Convertissez-le. Savourez."
SCRIPT: "Prêt pour la production. APIs stables. Maintenance active. Licence MIT."
SCRIPT: "Prêt pour la production. APIs stables. Maintenance active. Licence MIT."
SCRIPT: "Cas d'usage : provisionnement de serveurs, déploiement, configuration, conteneurs. Si ça a SSH, PyInfra peut lui parler."
SCRIPT: "pip install pyinfra. Écrivez deploy.py. Lancez. Terminé. Essayez pendant les questions."
SCRIPT: "Arrêtez le YAML. Passez au Python. Venez me voir après pour une thérapie de groupe."
SCRIPT: "Starrez le repo. Essayez aujourd'hui. Ne touchez plus jamais au YAML."
SCRIPT: "Merci ! Allez libérer votre infrastructure ! On se retrouve au bar après ? Des questions ?"