Aller au contenu
English
CI/CD & Automatisation medium

Rollback et concurrence des déploiements GitHub Actions

Read this page in English

30 min de lecture

Un rollback ne s'improvise pas le jour de l'incident : il se prépare au moment où tout va bien. Cette page montre comment revenir à la version précédente sans rejouer le pipeline, pourquoi cancel-in-progress est dangereux sur un job de déploiement, et ce que l'historique GitHub permet de retrouver quand il faut décider vite.

  • Distinguer un rollback d'un correctif d'urgence, et savoir lequel appliquer
  • Rejouer le digest précédent sans reconstruire ni retester
  • Retrouver la version précédente dans l'historique des déploiements
  • Sérialiser les déploiements avec concurrency, sans annuler celui qui tourne
  • Préparer ce qui doit exister avant l'incident pour que tout cela marche

Rollback ou correctif : deux réponses différentes

Section intitulée « Rollback ou correctif : deux réponses différentes »

Face à une régression en production, deux chemins existent, et les confondre coûte du temps au pire moment.

RollbackCorrectif d'urgence
PrincipeRedéployer la version précédente, connue bonneCorriger, tester, déployer une nouvelle version
DuréeMinutesLe temps d'un cycle complet
RisqueFaible, l'artefact a déjà tournéCelui d'un déploiement normal, sous pression
QuandRégression fonctionnelle, panneFaille de sécurité, corruption de données

La règle par défaut est rollback d'abord, diagnostic ensuite. Le correctif direct se justifie quand revenir en arrière n'est pas sûr, typiquement après une migration de schéma irréversible, ou quand la version précédente porte la vulnérabilité qu'on vient de corriger.

La condition préalable : un artefact toujours disponible

Section intitulée « La condition préalable : un artefact toujours disponible »

Un rollback n'est possible que si la version précédente existe encore, et qu'on sait la nommer. C'est la contrepartie de la chaîne de promotion : on ne redéploie pas un commit, on redéploie un digest.

Déploiement N-1 -> ghcr.io/mon-org/mon-app@sha256:3f1c... (toujours dans le registre)
Déploiement N -> ghcr.io/mon-org/mon-app@sha256:9a47... (la régression)
Rollback -> redéployer sha256:3f1c..., sans rebuild

Trois conditions rendent cela vrai, et chacune se vérifie avant l'incident :

  • l'image précédente n'a pas été supprimée du registre par une politique de nettoyage trop agressive ;
  • le digest est retrouvable, par l'historique des déploiements ou par les tags du registre ;
  • le workflow de déploiement accepte un digest en entrée, et ne se contente pas de déployer main.

L'historique des déploiements de GitHub garde la trace de chaque déploiement par environnement. En ligne de commande, la CLI gh l'interroge directement :

Fenêtre de terminal
# Les derniers déploiements de l'environnement production
gh api "repos/mon-org/mon-app/deployments?environment=production&per_page=10" \
--jq '.[] | {id, sha, created_at, ref}'

Pour retrouver les images disponibles côté registre, avec leurs digests :

Fenêtre de terminal
# Les versions publiées du paquet de conteneur
gh api "orgs/mon-org/packages/container/mon-app/versions" \
--jq '.[] | {id, digest: .name, tags: .metadata.container.tags, created_at}'

Ces deux commandes sont à connaître avant d'en avoir besoin. Les taper pour la première fois pendant une panne, c'est ajouter un problème à un problème.

Il n'y a pas de workflow de rollback spécifique : c'est le déploiement paramétré par digest, appelé avec la valeur précédente. Le même chemin, les mêmes contrôles, les mêmes approbations.

name: Deploy
on:
workflow_dispatch:
inputs:
digest:
description: "Digest à déployer (sha256:...), y compris pour un rollback"
required: true
type: string
permissions: {}
concurrency:
group: deploy-production
cancel-in-progress: false # on ne coupe jamais un déploiement en cours
jobs:
deploy:
runs-on: ubuntu-24.04
timeout-minutes: 15
environment:
name: production
url: https://mon-app.example.com
permissions:
contents: read
env:
IMAGE: ghcr.io/mon-org/mon-app
DIGEST: ${{ inputs.digest }}
steps:
- name: Vérifier la provenance du digest demandé
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: gh attestation verify "oci://${IMAGE}@${DIGEST}" --owner mon-org
- name: Déployer
run: ./deploy.sh "${IMAGE}@${DIGEST}"
env:
DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}

Maintenir la vérification de provenance dans le chemin de rollback est délibéré. C'est précisément sous pression qu'on accepterait de déployer n'importe quoi « juste pour que ça remarche », et c'est précisément le moment où un attaquant a intérêt à ce que vous le fassiez.

Le bloc concurrency regroupe les exécutions et décide du sort de celles qui se chevauchent. Sur une CI, on annule volontiers l'exécution précédente : elle porte sur un commit dépassé. Sur un déploiement, l'annulation est dangereuse.

# ✅ Déploiement : on met en file d'attente, on n'annule pas
concurrency:
group: deploy-production
cancel-in-progress: false
# ❌ Sur un déploiement : coupe une mise en production au milieu
concurrency:
group: deploy-production
cancel-in-progress: true

Un déploiement interrompu en plein vol laisse le système dans un état intermédiaire : moitié des instances sur la nouvelle version, migration appliquée mais code non déployé, verrou non relâché. C'est exactement la situation que le rollback devra démêler, en partant d'un état qu'aucune version n'a jamais connu.

Le nom du groupe mérite attention. Un groupe par environnement (deploy-production) sérialise les mises en production tout en laissant staging avancer en parallèle :

concurrency:
group: deploy-${{ github.event.inputs.environment || 'production' }}
cancel-in-progress: false

Sur la CI, en revanche, l'annulation reste la bonne réponse :

# CI : annuler les exécutions obsolètes de la même branche
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
  1. Un déploiement paramétrable par digest, pas seulement déclenché par un push sur main.

  2. Une politique de rétention qui conserve au moins les quelques dernières versions déployées, images non taguées comprises.

  3. Les commandes de recherche du digest précédent, écrites quelque part d'accessible hors de l'outil en panne.

  4. Un groupe de concurrence par environnement, avec cancel-in-progress: false.

  5. Une décision écrite sur les cas où le rollback est interdit, typiquement après une migration de schéma irréversible.

Vérifiez que l'essentiel de ce guide est acquis. Les questions portent uniquement sur ce qui vient d'être expliqué ici.

Contrôle de connaissances

Validez vos connaissances avec ce quiz interactif

6 questions
6 min.
70% requis

Informations

  • Le chronomètre démarre au clic sur Démarrer
  • Questions à choix multiples, vrai/faux et réponses courtes
  • Vous pouvez naviguer entre les questions
  • Les résultats détaillés sont affichés à la fin

Lance le quiz et démarre le chronomètre

  • Rollback d'abord, diagnostic ensuite, sauf migration irréversible ou faille corrigée par la version en cours.
  • Un rollback redéploie un digest, pas un commit : il n'y a ni rebuild, ni nouveaux tests, donc ni nouveau risque.
  • La rétention du registre et des artefacts fixe la profondeur réelle du rollback ; 90 jours par défaut côté artefacts.
  • Le workflow de rollback est le déploiement paramétré, avec les mêmes vérifications de provenance et la même approbation.
  • Sur un déploiement, cancel-in-progress: false : une mise en production coupée en deux laisse un état qu'aucune version n'a connu.
  • Un groupe de concurrence par environnement sérialise la production sans bloquer staging.
  • Les commandes qui retrouvent le digest précédent se testent avant l'incident, pas pendant.
  • Concurrency : Le mécanisme de groupement détaillé, dont le cancel-in-progress qu'un déploiement doit laisser à false.
  • Runners : introduction : Choisir et durcir les machines qui exécutent ces déploiements.

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn