Mes déploiements en production prennent 15 minutes. Je ne les regarde pas. Je ne retiens pas mon souffle. Je me fais un thé, et le temps qu'il infuse, la nouvelle version est en ligne.
Ça n'a pas toujours été le cas.
Il y a deux ans, les déploiements étaient un rituel. Bloquer une heure. Prévenir l'équipe. Lancer le script à la main. Surveiller les logs. Prier. Corriger ce qui a cassé. Relancer. Prier plus fort. Le tout prenait 2 à 3 heures et laissait tout le monde vidé. On déployait le vendredi parce qu'on se détestait.
Si ça te parle, c'est que tes déploiements tournent à l'adrénaline, pas aux systèmes. En mars 2026, il n'y a plus aucune excuse. Voici comment j'ai transformé un festival d'anxiété de 3 heures en 15 minutes d'ennui. ⚙️
Le problème : onze étapes dans la tête de quelqu'un
Déployer — le processus qui consiste à pousser du nouveau code depuis ton ordinateur vers le serveur où les utilisateurs le voient — impliquait 11 choses à la fois. Récupérer le code. Installer les dépendances (les bibliothèques externes dont ton appli a besoin). Lancer les migrations (mettre à jour la structure de la base de données pour correspondre au nouveau code). Compiler les assets. Redémarrer le service. Vider le cache. Mettre à jour le reverse proxy. Vérifier l'endpoint de santé.
Tout ça vivait sur une page wiki obsolète à 40%. Les nouveaux étaient terrifiés. Les anciens étaient juste fatigués.
La solution, ce n'était pas un outil magique. C'était de la discipline.
Étape 1 : Un script, une commande
J'ai écrit un seul script bash — un petit programme qui exécute des commandes en séquence, comme une recette que l'ordinateur suit ligne par ligne. Je l'ai appelé deploy.sh. Il fait les 11 choses dans l'ordre. Si une étape échoue, tout s'arrête et il te dit laquelle a cassé et pourquoi.
#!/bin/bash
set -euo pipefail
APP=$1
DEPLOY_LOG="/var/log/deploys/${APP}-$(date +%Y%m%d-%H%M%S).log"
echo "Deploying ${APP}..." | tee "$DEPLOY_LOG"
# Chaque étape : nom, commande, rollback
deploy_step "Pull code" "git -C /srv/${APP} pull origin main"
deploy_step "Install deps" "cd /srv/${APP} && pip install -r requirements.txt"
deploy_step "Run migrations" "cd /srv/${APP} && python manage.py migrate"
deploy_step "Build assets" "cd /srv/${APP} && npm run build"
deploy_step "Restart service" "systemctl restart ${APP}"
deploy_step "Health check" "curl -sf http://localhost:8080/health"
echo "Deploy complete: ${APP}" | tee -a "$DEPLOY_LOG"
La fonction deploy_step encapsule chaque commande avec du logging, du chronométrage et de la gestion d'erreurs. Si le health check échoue, elle redémarre automatiquement la version précédente — un rollback, c'est-à-dire ' annuler et revenir à ce qui marchait '.
Temps de mise en place : 45 minutes. Ces 45 minutes ont économisé des centaines d'heures depuis. L'idée centrale vient directement de la méthodologie Twelve-Factor App — une base de code, un build, une commande de déploiement.
Étape 2 : CI/CD — le robot qui déploie à ta place
CI/CD signifie Continuous Integration / Continuous Deployment. En clair : un système qui teste automatiquement ton code quand tu pousses des changements (ça, c'est le CI), et si les tests passent, le déploie automatiquement sur le serveur (ça, c'est le CD). Tu pousses ton code, le robot s'occupe du reste.
Pour une petite équipe, tu n'as pas besoin de Jenkins (un serveur d'automatisation poids lourd), d'ArgoCD (un outil de déploiement Kubernetes), ni d'un cluster Kubernetes (un système d'orchestration de conteneurs — si ces mots ne te disent rien, tant mieux, tu n'en as pas besoin). Tu as besoin de GitHub Actions et d'un serveur avec un accès SSH. GitHub Actions existe depuis 2019 et s'est imposé comme le choix CI/CD par défaut pour les équipes déjà sur GitHub — stable, bien documenté, et gratuit pour les petits volumes.
# .github/workflows/deploy.yml
name: Deploy
on:
push:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: pip install -r requirements.txt
- run: pytest --tb=short
deploy:
needs: test
runs-on: ubuntu-latest
if: success()
steps:
- name: Deploy to production
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.SERVER_HOST }}
username: deploy
key: ${{ secrets.SSH_KEY }}
script: bash /srv/myapp/deploy.sh myapp
Voilà le pipeline complet — une séquence d'étapes automatisées que le code traverse de ton laptop jusqu'à la production. Tu pousses sur main (la branche principale de ton code). Les tests tournent sur les serveurs de GitHub. S'ils passent, GitHub se connecte à ton serveur via SSH (un protocole de connexion distante sécurisée) et lance deploy.sh.
Pas de conteneurs. Pas d'orchestrateurs. Pas de fichiers YAML de 200 lignes. Le tier gratuit de GitHub Actions te donne 2 000 minutes par mois — largement suffisant pour une petite équipe qui déploie 2 à 3 fois par jour.
Étape 3 : Un health check qui vérifie vraiment la santé
La plupart des health checks, c'est une URL /health qui renvoie {"status": "ok"}. Ça te dit que le serveur web tourne. Ça ne te dit rien sur le fonctionnement réel de l'appli. C'est comme demander à quelqu'un ' t'es vivant ? ' alors que tu devrais demander ' tu vois, tu entends, et tu peux bouger les doigts ? '
Mes health checks vérifient trois choses :
@app.get("/health")
async def health():
checks = {
"database": await check_db_connection(),
"cache": await check_redis_ping(),
"disk": check_disk_space_above(20), # percent
}
all_ok = all(checks.values())
return JSONResponse(
status_code=200 if all_ok else 503,
content={"status": "healthy" if all_ok else "degraded", "checks": checks}
)
Base de données en panne ? Le health check échoue. Redis (un cache en mémoire — une couche de stockage temporaire ultra-rapide) injoignable ? Échoue. Disque rempli à 95% ? Échoue. Le script de déploiement appelle cet endpoint après le redémarrage. S'il renvoie 503 (le code HTTP pour ' service indisponible '), le déploiement fait un rollback automatique.
Ce seul endpoint a détecté plus de problèmes post-déploiement que tous nos tests manuels réunis. ⚙️
Étape 4 : Des notifications, pas des dashboards
Je ne reste pas assis devant des dashboards de monitoring. Le script de déploiement envoie exactement deux messages :
- Déploiement lancé — ' Déploiement de myapp à 14:32. Déclenché par le commit abc123. '
- Déploiement terminé — ' myapp déployé en 14m 22s ' ou ' Déploiement de myapp ÉCHOUÉ à l'étape : health check. Rollback effectué. '
Ça part dans un channel Telegram. Si je vois une notif d'échec, j'investigue. Si je vois un succès, je sirote mon thé.
Pas de Grafana (un outil de dashboards populaire). Pas de PagerDuty (un service d'alertes qui te réveille à 3h du mat). Pour une petite équipe avec 2-3 services, un message Telegram, c'est le bon niveau de complexité. La complexité doit correspondre à la taille du problème, pas à la taille de tes ambitions. 🫶
Étape 5 : Déployer le lundi matin
On a arrêté de déployer le vendredi. Maintenant c'est lundi et mercredi matin.
Pourquoi ? Parce que si quelque chose casse le lundi, tu as cinq jours pour le corriger avec un cerveau frais. Un déploiement le vendredi, c'est du debug le week-end. Le debug le week-end, c'est du burnout. Le burnout, ce sont des erreurs. Les erreurs, c'est encore plus de debug le week-end.
C'est une boucle de rétroaction négative — un cycle où chaque mauvais résultat provoque le suivant. Ce n'est pas une stratégie de déploiement.
Le planning ennuyeux : lundi et mercredi matin. Rien après 15h. Rien le vendredi. Rien pendant le déjeuner. Si c'est pas prêt pour le créneau du lundi, ça attend. Attendre ne coûte rien. Le burnout coûte cher.
Ce que tu sacrifies
Honnêteté. Ce setup a des compromis.
Pas de déploiement sans interruption. Quand systemctl restart tourne, il y a une coupure de 2 à 5 secondes où l'appli est indisponible. Pour un service qui gère des millions de requêtes, c'est un problème. Pour la plupart des petites équipes, personne ne s'en aperçoit. Si tu dépasses ce stade, regarde du côté du déploiement blue-green (faire tourner deux copies de ton appli et basculer le trafic de l'une à l'autre) — mais ne commence pas par là.
Un seul serveur, un seul point de défaillance. Si le serveur meurt, tout meurt. La redondance coûte de l'argent. Pour la plupart des projets sous 10 000 € de revenu mensuel, un serveur unique bien entretenu avec des sauvegardes quotidiennes, c'est la bonne réponse. Les problèmes de montée en charge sont de bons problèmes à avoir.
Pas de conteneurisation. Docker (un outil qui empaquette ton appli avec toutes ses dépendances dans une unité isolée) est formidable pour les environnements complexes. Pour une appli Python avec une base de données et Redis sur un seul serveur, c'est du surplus. Tu pourras toujours l'ajouter plus tard.
Les recherches DORA de Google montrent que les équipes d'élite déploient à la demande avec des délais de mise en production inférieurs à une heure. Mais elles montrent aussi qu'on y arrive progressivement — pas en adoptant tous les outils d'un coup.
Le résultat
Avant : déploiements de 3 heures, 1 à 2 fois par semaine, équipe de 3 personnes bloquée. Après : déploiements de 15 minutes, 2 à 3 fois par semaine, zéro personne qui surveille.
Temps gagné par mois : environ 24 heures de temps d'équipe cumulé. Coût annuel du setup CI/CD : 0 € (tier gratuit GitHub Actions plus un script bash). Temps de mise en place : un week-end.
Rends ça ennuyeux
L'objectif du bon ops, ce n'est pas de rendre les déploiements excitants. C'est de les rendre tellement ennuyeux que tu oublies qu'ils ont lieu.
Quand tu déploies sans adrénaline, tu déploies plus souvent. Quand tu déploies plus souvent, chaque déploiement est plus petit. Quand chaque déploiement est plus petit, moins de choses cassent. Quand moins de choses cassent, tu dors mieux.
C'est toute la philosophie. Un script. Un pipeline. Un health check. Un canal de notification. Un matin calme par semaine.
Rends ça ennuyeux. Rends ça petit. Rends ça automatique. Va te faire un thé. 🫶





