Introduction
GitLab CI/CD est puissant, mais de petites erreurs peuvent bloquer la livraison. Ce guide se concentre sur les erreurs que vous rencontrerez le plus souvent dans les pipelines réels, pourquoi elles se produisent, comment confirmer la cause racine, et des correctifs sûrs, prêts à copier-coller. Restez pratique : reproduisez le problème avec l'exemple le plus petit, appliquez le plus petit changement sûr, puis généralisez.
Ce que vous obtiendrez :
- Explications claires des messages d'erreur GitLab CI/CD courants
- Reproductions minimales et extraits de jobs adaptables
- Correctifs sûrs par défaut testables localement avant déploiement
Aperçu du Workflow
Utilisez un flux reproductible qui transforme le bruit en signal :
- Reproduire et capturer le contexte
- Relancez le job échoué avec le même commit.
- Développez toutes les sections réduites dans le log du job. Lisez depuis le haut : infos runner, pull d'image, checkout,
before_script,script,after_script, artefacts/upload. - Notez la ligne qui échoue et la phase concernée.
- Astuce : Activez
CI_DEBUG_TRACE=truecomme variable CI pour un run unique afin de voir chaque commande exécutée.
- Confirmer la plus petite reproduction
- Mettez en commentaire les étapes non essentielles.
- Durcissez les variables qui affectent le flux.
- Si un service est impliqué (Docker, base de données, Kubernetes), testez avec un job unique et un script minimal.
- Appliquer le plus petit correctif sûr
- Préférez les correctifs de configuration aux contournements par script.
- Ajoutez des garde-fous (
rules,paths, outimeoutexplicite) pour prévenir les récidives.
- Vérifier et documenter
- Relancez le job, puis un pipeline complet.
- Ajoutez un court commentaire dans
.gitlab-ci.ymlprès du correctif.
Erreurs Courantes et Solutions
Voici les échecs fréquents, leurs causes, comment vérifier, et des correctifs sûrs.
1) .gitlab-ci.yml Invalide ou Structure YAML Incorrecte
Symptômes
- Le pipeline ne démarre pas, ou vous voyez : "Cette configuration GitLab CI est invalide\)."
- Messages au niveau job comme : "La configuration
before_scriptdoit être une chaîne ou une liste de chaînes\)."
Pourquoi ça arrive
- Erreurs d'indentation YAML ou de syntaxe de liste.
- Utilisation d'un mapping là où une liste est attendue, ou vice versa.
Comment diagnostiquer
- Réduisez à un
.gitlab-ci.ymlminimal avec un seul jobechopour isoler la faute. - Vérifiez que toutes les listes utilisent des tirets et que toutes les listes de chaînes sont des chaînes simples.
- Validez avec l'outil CI Lint dans GitLab (CI/CD > Éditeur > Lint) ou lancez
gitlab-ci-lintlocalement.
Exemple de correctif sûr
stages: [lint, test]
variables:
NODE_ENV: 'test'
lint:
stage: lint
image: node:20-alpine
script:
- node --version
- npm ci
- npm run lint
test:
stage: test
image: node:20-alpine
script:
- npm ci
- npm test
Astuces
- Évitez de mélanger tabulations et espaces.
- Gardez
scriptcomme liste de chaînes, pas comme chaîne multiligne unique.
2) Pipeline Sans Jobs
Symptômes
- La page du pipeline affiche : "Il n'y a pas de stages/jobs pour ce pipeline." ou rien ne s'exécute pour votre branche/MR.
Pourquoi ça arrive
rulesouonly/exceptexcluent votre ref.workflow: rulesempêche la création du pipeline.
Comment diagnostiquer
- Inspectez la branche ou l'événement MR et les variables d'environnement (
CI_PIPELINE_SOURCE,CI_COMMIT_BRANCH). - Ajoutez temporairement un job fourre-tout pour vérifier la correspondance.
Exemple de correctif sûr avec rules et fallback
workflow:
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
- when: always # assure la création d'un pipeline en cas de doute
build:
stage: build
image: alpine:3.20
rules:
- changes:
- src/**
when: on_success
- when: manual # fallback visible si aucun changement ne correspond
script:
- echo "Construction..."
3) Job Bloqué ou en Attente : Pas de Runners
Symptômes
- Le statut du job reste en pending avec : "Ce job est bloqué car le projet n'a aucun runner en ligne qui lui est assigné."\
Pourquoi ça arrive
- Aucun runner en ligne, ou les tags du runner ne correspondent pas au job.
- Le runner n'est pas autorisé à s'exécuter sur ce projet ou cette branche protégée.
Comment diagnostiquer
- Comparez les tags du job et du runner dans Settings > CI/CD > Runners.
- Confirmez que le runner est en ligne et non mis en pause.
- Pour les branches protégées, assurez-vous que le runner est marqué protégé ou que le job n'est pas restreint aux refs protégées.
Exemple de correctif sûr : aligner les tags ou supprimer l'exigence de tag
# Si votre runner a le tag 'docker', le job doit l'inclure
build-image:
tags: ['docker']
image: docker:24
services: ['docker:24-dind']
variables:
DOCKER_HOST: 'tcp://docker:2375'
DOCKER_TLS_CERTDIR: ''
script:
- docker version
- docker build -t demo: ci .
4) Docker-in-Docker : Impossible de Se Connecter au Démon Docker
Symptômes
- "Impossible de se connecter au démon Docker à unix:///var/run/docker.sock. Le démon docker est-il en cours d'exécution ?"\
Pourquoi ça arrive
- Service Docker non démarré, mauvais hôte, ou TLS mal configuré.
- Mismatch MTU sur l'interface réseau (fréquent avec les VPNs).
Comment diagnostiquer
- Affichez les variables d'env et essayez
docker info. - Assurez-vous que l'alias du service correspond au
DOCKER_HOST.
Exemple de correctif sûr
image: docker:24
services:
- name: docker:24-dind
command: ['--mtu=1460'] # résout les problèmes MTU sur certains réseaux
variables:
DOCKER_HOST: 'tcp://docker:2375'
DOCKER_TLS_CERTDIR: ''
DOCKER_DRIVER: 'overlay2'
build:
stage: build
script:
- docker version
- docker build -t $CI_REGISTRY_IMAGE:ci-$CI_COMMIT_SHORT_SHA .
- echo 'Construction terminée'
Astuces
- Désactivez TLS pour le service dind dans CI et gardez le réseau du job isolé.
- Si vous utilisez un runner partagé, préférez les images de base petites pour réduire le temps de pull.
5) Upload d'Artefacts : Fichier Introuvable
Symptômes
- "Upload des artefacts... AVERTISSEMENT : Aucun fichier à uploader" ou "Impossible de trouver un fichier correspondant à ..."\
Pourquoi ça arrive
- Le chemin est incorrect, les fichiers générés vont dans un autre répertoire, ou le job a échoué avant de les produire.
Comment diagnostiquer
- Ajoutez
ls -Rpour confirmer les chemins. - Assurez-vous que le répertoire de travail est
$CI_PROJECT_DIR.
Exemple de correctif sûr
test:
stage: test
image: node:20-alpine
script:
- npm ci
- npm test -- --reporter=junit --reporter-options output=reports/junit.xml
- mkdir -p dist && echo ok > dist/health.txt
artifacts:
when: always
paths:
- reports/junit.xml
- dist/
expire_in: '7 days'
6) Le Cache Ne Persiste Pas Entre les Jobs
Symptômes
- Les dépendances se réinstallent à chaque fois ; le taux de cache hit apparaît à 0%.
Pourquoi ça arrive
- Clé de cache trop large, trop étroite, ou qui change à chaque run.
Comment diagnostiquer
- Affichez la clé de cache et comparez entre jobs (ajoutez
echo "Clé cache : $CI_CACHE_KEY").
Exemple de correctif sûr : clé basée sur le contenu avec fallback
cache:
key:
files:
- package-lock.json
paths:
- node_modules/
policy: pull-push
install:
stage: .pre
image: node:20-alpine
script:
- npm ci --cache .npm --prefer-offline
artifacts:
paths: [.npm]
expire_in: '1 day'
7) Échec de Récupération des Sous-modules Git
Symptômes
- "fatal: could not read Username for 'https://gitlab.com': No such device or address"\
- "fatal: repository not found" pour les sous-modules.
Pourquoi ça arrive
- Les sous-modules utilisent HTTPS sans identifiants, ou pointent vers un projet privé auquel le token ne peut pas accéder.
Comment diagnostiquer
- Affichez
.gitmoduleset vérifiez les URLs. - Vérifiez que les projets de sous-modules accordent l'accès à
CI_JOB_TOKENsi vous utilisez des chemins relatifs.
Exemple de correctif sûr : utiliser CI_JOB_TOKEN pour HTTPS
variables:
GIT_SUBMODULE_STRATEGY: 'recursive'
GIT_SUBMODULE_UPDATE_FLAGS: '--jobs 4'
before_script:
- git config --global url."https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.com/" .insteadOf "https://gitlab.com/"
submodule_job:
stage: test
image: alpine:3.20
script:
- git submodule sync --recursive
- git submodule update --init --recursive
- echo 'Sous-modules prêts'
Astuces
- Préférez les URLs de sous-modules relatives dans la même instance GitLab pour permettre l'auth
CI_JOB_TOKEN. - Pour des sous-modules cross-instance ou privés, utilisez une clé SSH de déploiement stockée dans une variable CI.
8) Variables Protégées Manquantes sur Branches Non Protégées
Symptômes
docker loginou CLI cloud échoue avec 403 ou erreurs d'auth seulement sur les branches de fonctionnalité.
Pourquoi ça arrive
- Les variables sont marquées protégées et ne sont exposées que sur les refs protégées.
Comment diagnostiquer
- Comparez les drapeaux de protection des variables avec les paramètres de protection de branche dans Settings > CI/CD > Variables.
Exemple de correctif sûr : restreindre le job aux refs protégées quand nécessaire
docker_push:
stage: deploy
rules:
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
- if: '$CI_COMMIT_TAG'
- when: never
script:
- echo "$REGISTRY_PASSWORD" | docker login -u "$REGISTRY_USER" --password-stdin "$CI_REGISTRY"
- docker push $CI_REGISTRY_IMAGE:release
Alternative : Si les branches de fonctionnalité ont aussi besoin du secret, déprotégez la variable (moins sécurisé) ou créez une variable non protégée séparée pour le développement.
9) Kubernetes : Erreurs kubectl ou Helm
Symptômes
kubectl: "unable to recognize: no matches for kind ..."\- Helm : "UPGRADE FAILED: another operation is in progress" ou timeouts.
Pourquoi ça arrive
- Mauvais
apiVersionou CRDs manquantes ; permissions manquantes ; verrous Helm obsolètes ; kubeconfig non chargé.
Comment diagnostiquer
- Affichez
kubectl version --clientet les versions serveur. - Lancez
kubectl auth can-i ...pour vérifier les permissions. - Utilisez
helm listethelm historypour inspecter l'état du release.
Exemple de correctif sûr : passer kubeconfig via une variable et utiliser les upgrades Helm atomiques
deploy:
stage: deploy
image: alpine/helm:3.14.4
variables:
KUBECONFIG: '/builds/$CI_PROJECT_PATH/.kube/config'
before_script:
- mkdir -p $(dirname "$KUBECONFIG" )
- echo "$KUBECONFIG_DATA" | base64 -d > "$KUBECONFIG"
- kubectl version --client
- kubectl config get-contexts
script:
- kubectl apply -f k8s/ns.yaml
- helm upgrade --install app charts/app \
--namespace app \
--create-namespace \
--atomic --wait --timeout 5m
Astuces
- Gardez les versions client
kubectl/Helm compatibles avec votre cluster. - Utilisez
--atomicet--waitpour échouer vite et rollback en cas d'erreur. - Envisagez l'intégration Kubernetes de GitLab pour injecter automatiquement le kubeconfig.
10) Job Dépassant la Limite de Temps
Symptômes
- "script exceeded time limit" ou job annulé après une durée fixe.
Pourquoi ça arrive
- Timeout par défaut trop bas ; pulls d'images lents ; cache misses ; suites de tests longues.
Comment diagnostiquer
- Vérifiez la répartition de la durée du job dans les logs.
- Notez les temps de pull d'image et les attentes réseau.
Exemple de correctif sûr : définir un timeout par job et optimiser les pulls
long_tests:
stage: test
image: python:3.12-slim
timeout: 45m
script:
- pip install -r requirements.txt
- pytest -m 'not slow' -n auto --dist loadscope
Astuces
- Utilisez des images de base plus petites et activez le cache côté registre quand disponible.
- Divisez les jobs longs en shards parallèles et fusionnez les rapports comme artefacts.
- Ajustez le timeout au niveau projet dans Settings > CI/CD > General pipelines > Timeout si nécessaire.
Plan Pilote Local
Objectif : valider vos correctifs et patterns avec le plus petit pipeline utile que vous pouvez inspecter localement avant de le déployer sur tous les projets.
Périmètre
- Un repo, un runner partagé ou spécifique au projet.
- Stages : validate, test, build, package.
- Build Docker-in-Docker, cache basique, et un artefact.
Critères de succès
- Pipeline passe en moins de 10 minutes sur un runner propre.
- Cache hit au second run pour les dépendances.
- Aucun job en pending ; aucun avertissement d'upload d'artefacts.
Pipeline pilote de référence
stages: [validate, test, build, package]
default:
image: docker:24
services: ['docker:24-dind']
variables:
DOCKER_HOST: 'tcp://docker:2375'
DOCKER_TLS_CERTDIR: ''
validate_yaml:
stage: validate
image: alpine:3.20
script:
- echo 'Validation de la structure YAML'
- grep -q 'stages:' .gitlab-ci.yml
unit_tests:
stage: test
image: node:20-alpine
cache:
key:
files: [package-lock.json]
paths: [node_modules/]
policy: pull-push
script:
- npm ci
- npm test -- --reporter=junit --reporter-options output=reports/junit.xml
artifacts:
when: always
paths: [reports/junit.xml]
expire_in: '7 days'
build_image:
stage: build
tags: ['docker'] # assurez-vous que cela correspond à votre tag runner
script:
- echo "$CI_REGISTRY_PASSWORD" | docker login -u "$CI_REGISTRY_USER" --password-stdin "$CI_REGISTRY"
- docker build -t $CI_REGISTRY_IMAGE:ci-$CI_COMMIT_SHORT_SHA .
- docker image ls | head -n 5
package_sbom:
stage: package
image: alpine:3.20
script:
- mkdir -p out && echo '{"sbom":"demo"}' > out/sbom.json
artifacts:
paths: [out/sbom.json]
expire_in: '7 days'
Comment exécuter et inspecter
- Poussez une branche de fonctionnalité et ouvrez une petite MR.
- Confirmez que les tags runner correspondent et que le cache hit au second run.
- Cassez intentionnellement un chemin (ex: artefacts) pour voir l'erreur, puis revenez en arrière.
Déploiement
- Copiez les patterns dans d'autres repos, en ajustant images, tags, et clés de cache.
- Gardez les jobs pilotes comme templates que vous pouvez inclure à travers les projets.
Conclusion
Vous disposez maintenant d'un ensemble pratique de patterns pour reconnaître et corriger les erreurs GitLab CI/CD les plus courantes :
- Validez le YAML tôt et gardez les scripts simples.
- Assurez la disponibilité des runners et l'alignement des tags.
- Configurez Docker-in-Docker de manière prévisible.
- Produisez les artefacts fiablement et cachez ce qui est coûteux à reconstruire.
- Authentifiez correctement les sous-modules et registres.
- Déployez sur Kubernetes avec kubeconfig explicite, attentes, et rollbacks atomiques.
- Contrôlez les timeouts et parallélisez les tâches longues.
Prochaines étapes
- Implémentez le pipeline pilote et enregistrez les métriques de référence.
- Corrigez d'abord l'erreur la plus douloureuse dans votre environnement, puis étendez.
- Gardez les changements petits, observables, et faciles à annuler.