Introduction
L'automatisation CI/CD GitLab transforme une modification de code en un résultat déployé et testé sans intervention manuelle. Cet article s'adresse aux développeurs, aux consultants DevOps et aux équipes techniques de startups qui souhaitent des procédures concrètes, à portée de version, plutôt que des conseils génériques. Dans chaque section, vous trouverez des commandes précises, les résultats attendus, les signaux d'échec et les étapes de récupération pour les pipelines CI/CD GitLab.
L'objectif est la sécurité opérationnelle : observer avant de modifier, limiter le rayon d'impact, utiliser des espaces réservés au lieu de véritables secrets, vérifier le résultat et documenter la récupération si l'état attendu n'est pas atteint.
Inventaire des versions et de l'environnement
Pour GitLab CI/CD, la première étape consiste à enregistrer exactement ce que vous exécutez. Cela évite de déboguer la mauvaise version ou la mauvaise topologie. L'inventaire couvre l'instance GitLab, le runner et les exécuteurs tels que Docker ou Kubernetes qui affectent le comportement du pipeline.
Collecter des informations en lecture seule
Exécutez les commandes en lecture seule suivantes depuis une machine qui peut atteindre votre instance GitLab. Ces commandes ne modifient rien et peuvent être exécutées à tout moment en toute sécurité.
# Version du serveur GitLab depuis l'API (nécessite un jeton avec le scope read_api)
curl --silent --header "PRIVATE-TOKEN: $GITLAB_READ_TOKEN" \
"https://gitlab.example.com/api/v4/version" | jq .
La sortie attendue comprend la version et la révision :
{
"version": "16.7.0-ee",
"revision": "abc123def"
}
Pour GitLab Runner, vérifiez la version sur l'hôte :
gitlab-runner --version
La sortie attendue est une seule ligne similaire à :
Version: 16.7.0
Git revision: abc123de
Git branch: 16-7-stable
GO version: go1.21.5
Built: 2024-01-15T00:00:00+00:00
OS/Arch: linux/amd64
Enregistrez le type d'exécuteur depuis la configuration du runner :
gitlab-runner list
Exemple de sortie :
Runtime platform arch=amd64 os=linux pid=1234 revision=abc123de version=16.7.0
Listing configured runners ConfigFile=/etc/gitlab-runner/config.toml
my-docker-runner Executor=docker Token=glrt-xxxx URL=https://gitlab.example.com
Notez l'exécuteur (docker, shell, kubernetes, etc.) car il change la façon de déboguer un job.
Définir vos prérequis
Avant toute modification, vérifiez que :
- L'instance GitLab est joignable depuis le runner.
- Le runner est en ligne et assigné aux bons tags.
- Vos variables CI/CD sont définies au bon niveau (projet, groupe ou instance).
- Vous avez au moins le rôle Mainteneur sur le projet pour modifier
.gitlab-ci.ymlet déclencher des pipelines.
Utilisez un jeton fictif pour l'authentification. Ne collez jamais un vrai jeton dans un article, un chat ou un commit. Pour les tests locaux, exportez un jeton avec les droits limités read_api, read_repository et write_repository uniquement :
export GITLAB_READ_TOKEN="glpat-XXXXXXXXXXXXXXXXXXXX"
export GITLAB_WRITE_TOKEN="glpat-YYYYYYYYYYYYYYYYYYYY"
Décider du plus petit changement justifié
Supposons qu'un pipeline échoue au job de déploiement. Le plus petit changement pourrait être de corriger un nom de variable dans .gitlab-ci.yml. Avant de modifier, capturez le fichier actuel et le statut du pipeline :
gitlab-ci-local --list 2>/dev/null || true
curl --silent --header "PRIVATE-TOKEN: $GITLAB_READ_TOKEN" \
"https://gitlab.example.com/api/v4/projects/$PROJECT_ID/pipelines?per_page=1" | jq '.[0].status'
Le statut attendu est failed ou success. Enregistrez l'ID du pipeline et le journal du job pour comparaison après la correction.
Vérifier le résultat
Après le changement, déclenchez un nouveau pipeline et vérifiez le statut du job concerné :
curl --silent --request POST \
--header "PRIVATE-TOKEN: $GITLAB_WRITE_TOKEN" \
--form ref=main \
"https://gitlab.example.com/api/v4/projects/$PROJECT_ID/pipeline" | jq '.id'
Puis interrogez le statut du pipeline :
curl --silent --header "PRIVATE-TOKEN: $GITLAB_READ_TOKEN" \
"https://gitlab.example.com/api/v4/projects/$PROJECT_ID/pipelines/$PIPELINE_ID" | jq '.status'
Le statut final attendu est success. Sinon, inspectez le journal du job. Le chemin de récupération consiste à revenir à la version précédente du fichier de configuration et à relancer le pipeline.
Chemin de configuration sûr
Cette section montre comment modifier .gitlab-ci.yml en toute sécurité. Le principe est de faire un changement à portée à la fois, avec un rayon d'impact connu et un retour en arrière testé.
Exemple : corriger un nom de variable dans le job de déploiement
Supposons que le pipeline a un job deploy_production qui échoue parce qu'il référence $AWS_ACCESS_KEY mais que la variable s'appelle AWS_ACCESS_KEY_ID. La correction consiste à mettre à jour le script du job. D'abord, montrez la définition actuelle du job :
deploy_production:
stage: deploy
script:
- echo "Deploying to production"
- aws s3 cp ./build s3://my-bucket --region us-east-1
variables:
AWS_ACCESS_KEY_ID: $AWS_ACCESS_KEY
Le problème est clair : la variable AWS_ACCESS_KEY n'est pas définie dans les paramètres CI/CD. Le nom correct est AWS_ACCESS_KEY_ID. Le changement est d'une seule ligne.
Appliquer le changement
Modifiez .gitlab-ci.yml et remplacez $AWS_ACCESS_KEY par $AWS_ACCESS_KEY_ID :
deploy_production:
stage: deploy
script:
- echo "Deploying to production"
- aws s3 cp ./build s3://my-bucket --region us-east-1
variables:
AWS_ACCESS_KEY_ID: $AWS_ACCESS_KEY_ID
Ce changement n'affecte que le job deploy_production. Le rayon d'impact est limité à ce job et à tout job en aval qui en dépend via needs ou dependencies.
Vérifier le changement
Validez le changement et poussez-le. Ensuite, surveillez le pipeline :
git push origin main
Vérifiez le journal du job pour l'étape de déploiement. Si la CLI AWS s'authentifie maintenant, le job réussit. Vous pouvez aussi vérifier que la variable est définie en affichant une version masquée dans le journal (ne jamais imprimer de secrets) :
script:
- echo "AWS Access Key ID is set to ${AWS_ACCESS_KEY_ID:0:4}..."
Sortie attendue :
AWS Access Key ID is set to AKIA...
Chemin de récupération
Si le déploiement échoue toujours, annulez le commit :
git revert HEAD --no-edit
git push origin main
Cela restaure la configuration précédente. Gardez toujours le .gitlab-ci.yml fonctionnel précédent dans le contrôle de version. Pour des changements plus importants, utilisez une branche et une demande de fusion au lieu de pousser directement sur main.
Vérification et diagnostic
La vérification signifie prouver que le pipeline a fait ce que vous attendiez. Le diagnostic signifie trouver pourquoi il ne l'a pas fait. Les deux reposent sur la lecture des journaux, la vérification des artefacts et la comparaison de l'état observé à l'état attendu.
Vérifier un pipeline réussi
Après la fin d'un pipeline, vérifiez le statut et les détails du job :
curl --silent --header "PRIVATE-TOKEN: $GITLAB_READ_TOKEN" \
"https://gitlab.example.com/api/v4/projects/$PROJECT_ID/pipelines/$PIPELINE_ID" | jq '{status, sha, ref, created_at}'
Sortie attendue :
{
"status": "success",
"sha": "a1b2c3d4e5f6",
"ref": "main",
"created_at": "2024-03-15T10:30:00.000Z"
}
Ensuite, listez les jobs de ce pipeline :
curl --silent --header "PRIVATE-TOKEN: $GITLAB_READ_TOKEN" \
"https://gitlab.example.com/api/v4/projects/$PROJECT_ID/pipelines/$PIPELINE_ID/jobs" | jq '.[] | {name, stage, status, duration}'
Attendez-vous à ce que chaque statut de job soit success ou manual le cas échéant.
Diagnostiquer un job en échec
Si un job échoue, récupérez sa trace de journal :
curl --silent --header "PRIVATE-TOKEN: $GITLAB_READ_TOKEN" \
"https://gitlab.example.com/api/v4/projects/$PROJECT_ID/jobs/$JOB_ID/trace" | less
Cherchez l'erreur exacte. Les échecs courants incluent :
- Variables CI/CD manquantes :
The requested URL returned error: 403ouAccessDenied. - Mauvaise image Docker :
Unable to find image 'node:14' locallyalors que vous avez besoin denode:16. - Inadéquation de l'exécuteur du runner : les commandes shell échouent dans un exécuteur Docker car les dépendances ne sont pas installées.
Utilisez les artefacts du job pour inspecter les fichiers générés. Par exemple, si un job de test échoue, téléchargez le rapport JUnit :
curl --silent --header "PRIVATE-TOKEN: $GITLAB_READ_TOKEN" \
"https://gitlab.example.com/api/v4/projects/$PROJECT_ID/jobs/$JOB_ID/artifacts" --output artifacts.zip
unzip artifacts.zip -d artifacts/
Ensuite, inspectez les résultats des tests pour voir quel test a échoué.
Vérifier le statut du runner
Si les jobs restent en attente, vérifiez le statut du runner :
gitlab-runner verify
Sortie attendue :
Runtime platform arch=amd64 os=linux pid=1234 revision=abc123de version=16.7.0
Running in system-mode.
Verifying runner... is alive runner=abcd1234
Si le runner est hors ligne, redémarrez-le :
sudo gitlab-runner restart
Puis redéclenchez le pipeline.
Modes d'échec et récupération
Chaque pipeline peut échouer. Cette section décrit les modes d'échec courants et les étapes de récupération. La clé est d'avoir un chemin de récupération testé avant d'en avoir besoin.
Mode d'échec 1 : le pipeline de demande de fusion échoue à cause d'un mauvais commit
Un développeur pousse un commit qui casse la compilation. Le pipeline de demande de fusion affiche une croix rouge. Pour récupérer :
- Identifiez le mauvais commit en utilisant le SHA du commit du pipeline.
- Annulez le commit sur la branche de fonctionnalité :
git revert <bad-commit-sha> --no-edit
git push origin feature-branch
- Redémarrez le pipeline automatiquement via le push. Si manuel, cliquez sur le bouton de reprise ou utilisez l'API :
curl --silent --request POST \
--header "PRIVATE-TOKEN: $GITLAB_WRITE_TOKEN" \
"https://gitlab.example.com/api/v4/projects/$PROJECT_ID/pipelines/$PIPELINE_ID/retry" | jq '.status'
Sortie attendue : success après un certain temps.
Mode d'échec 2 : le déploiement en production réussit mais l'application est cassée
Parfois, le pipeline est vert mais l'application déployée renvoie des erreurs 500. Cela signifie que le déploiement lui-même a réussi mais que la version est mauvaise. La récupération nécessite un retour en arrière immédiat.
Stratégie de retour en arrière : artefact précédent
- Trouvez l'artefact du pipeline réussi précédent. Utilisez l'API GitLab pour lister les artefacts du projet :
curl --silent --header "PRIVATE-TOKEN: $GITLAB_READ_TOKEN" \
"https://gitlab.example.com/api/v4/projects/$PROJECT_ID/jobs?scope=success&per_page=100" | jq '.[] | select(.name=="build") | .artifacts_file.filename'
- Téléchargez l'artefact précédent et redéployez manuellement, ou déclenchez un job de retour en arrière dédié qui utilise un artefact stocké.
Créez un job de retour en arrière dans .gitlab-ci.yml qui déploie un artefact connu bon d'un pipeline précédent :
rollback_production:
stage: deploy
image: alpine:latest
script:
- echo "Rolling back to previous version"
- wget "https://gitlab.example.com/api/v4/projects/$CI_PROJECT_ID/jobs/$PREVIOUS_BUILD_JOB_ID/artifacts" --header "PRIVATE-TOKEN: $GITLAB_READ_TOKEN" -O rollback.zip
- unzip rollback.zip -d ./previous
- # Déployez la version précédente (par exemple, copie sur le serveur, push vers S3, etc.)
when: manual
only:
- main
Ce job est manuel pour qu'un humain décide quand faire le retour en arrière. Le PREVIOUS_BUILD_JOB_ID doit être défini comme variable CI/CD basée sur le dernier job connu bon.
Vérifier le retour en arrière
Après le retour en arrière, vérifiez que l'application répond correctement :
curl --silent --output /dev/null --write-out "%{http_code}" https://app.example.com/health
Sortie attendue : 200.
Mode d'échec 3 : pipeline bloqué en attente
Si un pipeline est en pending pendant longtemps, vérifiez si le runner est disponible et a de la capacité :
sudo gitlab-runner status
Sortie attendue : gitlab-runner: Service is running.
S'il est en cours d'exécution, vérifiez la limite de concurrence du runner dans config.toml :
concurrent = 1
Augmentez-la si de nombreux jobs sont en concurrence :
concurrent = 4
Puis redémarrez le runner :
sudo gitlab-runner restart
Documenter vos étapes de récupération
Pour chaque mode d'échec qui survient, notez les étapes exactes que vous avez suivies pour récupérer. Stockez-les dans le wiki du projet ou un fichier RUNBOOK.md. Exemple d'entrée de runbook :
# Runbook : Retour en arrière de la production
**Déclencheur :** Le pipeline de déploiement en production a réussi mais l'application renvoie 500.
**Étapes :**
1. Trouvez l'ID du job de build réussi précédent dans la liste des pipelines.
2. Définissez `PREVIOUS_BUILD_JOB_ID` dans les variables CI/CD du projet.
3. Exécutez le job manuel `rollback_production`.
4. Vérifiez que le point de terminaison de santé renvoie 200.
**Temps prévu :** 5 minutes.
**Responsable :** Ingénieur d'astreinte.
Liste de contrôle des opérations
Utilisez cette liste de contrôle avant et après tout changement de pipeline. Remplacez les valeurs d'exemple par vos propres identifiants de projet, de pipeline et de ressource.
Liste de contrôle avant changement
- [ ] Enregistrez la version actuelle du serveur GitLab :
16.7.0-ee(exemple). - [ ] Enregistrez la version et l'exécuteur du runner :
16.7.0,docker(exemple). - [ ] Confirmez le chemin du projet et l'ID du pipeline :
my-group/my-project,#12345(exemple). - [ ] Lisez le
.gitlab-ci.ymlactuel et notez la section exacte à modifier. - [ ] Identifiez le rayon d'impact : quels jobs, étapes et environnements sont affectés ?
- [ ] Assurez-vous que le changement est réversible : le fichier précédent est dans le contrôle de version.
- [ ] Utilisez des espaces réservés pour les identifiants, jetons ou URL privées dans la documentation.
- [ ] Définissez le résultat attendu : par exemple, le statut du pipeline devient
successet le journal du job de déploiement contientDeploying to production.
Vérification après changement
- [ ] Poussez le changement ou fusionnez la demande de fusion.
- [ ] Attendez que le pipeline se termine.
- [ ] Vérifiez le statut du pipeline :
success(attendu). - [ ] Vérifiez chaque statut de job :
successpour build, test, deploy (attendu). - [ ] Si le changement affecte le déploiement, vérifiez que le point de terminaison de santé de l'application renvoie
200. - [ ] Si le pipeline échoue, identifiez le job en échec et inspectez le journal.
- [ ] Si nécessaire, exécutez le chemin de récupération : annulez le commit ou exécutez le job de retour en arrière.
- [ ] Documentez tout nouveau mode d'échec et sa résolution dans le runbook.
Exemple : liste de contrôle pour la mise à jour d'une variable de déploiement
Supposons que vous deviez mettre à jour un secret AWS dans le job de déploiement. La liste de contrôle remplie pourrait ressembler à ceci :
- Version actuelle du serveur :
16.7.0-ee - Runner :
my-docker-runner, exécuteurdocker, version16.7.0 - Projet :
my-group/my-project - Changement : Mettre à jour la variable
AWS_SECRET_ACCESS_KEYdans.gitlab-ci.ymlde$OLD_VARà$NEW_VAR. - Rayon d'impact : Seulement le job de déploiement et ses jobs dépendants.
- Réversible : Oui, le fichier précédent est dans Git.
- Résultat attendu : Le job
deploy_productionréussit et le secret est masqué dans les journaux. - Vérification après changement : Pipeline
#12346statutsuccess. Le journal du job de déploiement ne montre aucune exposition de secret. La santé de l'application renvoie200.
Cette liste de contrôle garantit que vous ne sautez pas la vérification ou la planification de la récupération.
Conclusion
L'automatisation CI/CD GitLab n'est utile que lorsque chaque recommandation est à portée de version, observable et réversible dans la mesure où la technologie le permet. Copier une commande sans vérifier les prérequis et les résultats attendus n'est pas une procédure d'exploitation.
Comme prochaine étape, choisissez une vérification à faible risque pour GitLab CI/CD : enregistrez l'état actuel, exécutez une vérification documentée, comparez le résultat avec le signal attendu et examinez les dépendances telles que GitLab Runner, Docker et Kubernetes. Appliquez ensuite le même modèle à un petit changement de configuration et testez le chemin de récupération.
Un flux de travail technique fiable rend les échecs visibles, protège les valeurs sensibles, limite les changements à la ressource prévue et définit la vérification de la récupération avant qu'un incident ne force la décision.