Intro
Ce guide explique des concepts avancés de GitLab Runner avec des procédures concrètes et à faible risque, prêtes pour la production. Il s’adresse aux ingénieurs qui exploitent des runners sur Docker et Kubernetes, et qui doivent passer d’un problème observé à un résultat vérifié.
Principes opératoires utilisés tout au long :
- Observer avant de changer : capturer d’abord la version, la topologie et l’état courant.
- Effectuer le plus petit changement justifié, avec périmètre d’impact connu et retour arrière documenté.
- Utiliser des espaces réservés à la place des secrets et éviter de copier des identifiants de production.
- Vérifier les résultats avec des commandes et signaux explicites ; documenter les étapes de reprise.
La suite se concentre sur le composant runner lui‑même : exécuteurs, isolation, capacité et concurrence, cache et artéfacts, réseau et options de sécurité, observabilité, modes de panne et reprise sécurisée.
Inventaire de version et d’environnement
Commencez toute investigation par un inventaire de la version et de la topologie. Séparez l’observation (lecture seule) de l’intervention (modifications).
Prérequis :
- Accès shell à l’hôte du runner ou au plan de contrôle
- Service runner installé et démarré
- Familiarité de base avec l’exécuteur choisi (shell, Docker ou Kubernetes)
Exemples d’inventaire en lecture seule (pas de changement) :
- Identifier la version du runner et la plateforme
$ gitlab-runner --version
$ uname -a
Signal : une version sémantique (par exemple, 16.11.x ou ultérieure) et l’OS/architecture. Si plusieurs hôtes sont utilisés, capturer chaque hôte et horodatage.
- Lister les runners enregistrés sur un hôte
$ sudo gitlab-runner list
Signal : noms de runners, IDs, portées (partagé/groupe/projet) et tags. Notez lesquels sont protégés et s’ils sont verrouillés sur des projets.
- Capturer la configuration active (lecture seule)
$ sudo cat /etc/gitlab-runner/config.toml
Signal : type d’exécuteur par runner ([runners.docker], [runners.kubernetes], [runners.machine] si encore présent), valeur de concurrent, paramètres de cache, volumes, configuration de l’image helper et tout listener de métriques.
- Service et journaux
$ systemctl status gitlab-runner
$ journalctl -u gitlab-runner -n 200 --no-pager
Pour les hôtes avec exécuteur Docker :
$ docker info --format '{{.ServerVersion}} {{.OperatingSystem}}'
$ docker ps --filter label=com.gitlab.gitlab-runner.job.id --format 'table {{.ID}}\t{{.Image}}\t{{.Status}}'
Pour l’exécuteur Kubernetes :
$ kubectl -n <RUNNER_NAMESPACE> get pods -l app=gitlab-runner
$ kubectl -n <JOB_NAMESPACE> get pods -l gitlab-job=true
Avant tout changement, définissez l’état final attendu (par exemple, réduire le temps d’attente des jobs, moins d’échecs de pull d’images, ou des hits de cache reproductibles) et le signal d’échec (par exemple, lignes d’erreur ou codes HTTP spécifiques).
Parcours de configuration sécurisé
N’effectuez qu’un seul changement circonscrit à la fois, puis vérifiez‑le. Ci‑dessous, des ajustements avancés fréquents avec leur périmètre d’impact et le retour arrière.
Exemple A : Contrôler la concurrence du runner sur un hôte unique
- Composant : concurrence globale
- Pris en charge : toutes les versions récentes
- Périmètre d’impact : tous les jobs planifiés sur cet hôte
- Prérequis : métriques actuelles de file d’attente de jobs ou pression CPU/RAM observée
Observation (valeur actuelle) :
$ grep -E '^concurrent' /etc/gitlab-runner/config.toml || echo 'concurrent not set (defaults to 1)'
Intervention (définir à 4) :
$ sudo sed -i 's/^concurrent = .*/concurrent = 4/' /etc/gitlab-runner/config.toml || echo 'concurrent = 4' | sudo tee -a /etc/gitlab-runner/config.toml
$ sudo systemctl reload gitlab-runner || sudo systemctl restart gitlab-runner
Vérification :
- Exécutez deux pipelines et confirmez que jusqu’à 4 jobs s’exécutent en parallèle sur cet hôte.
- Surveillez CPU et mémoire ; en cas de saturation, revenez à la valeur précédente.
Retour arrière :
- Restaurer la sauvegarde du fichier précédente ou remettre l’ancien entier, puis recharger.
Exemple B : Durcir l’isolation et la reproductibilité de l’exécuteur Docker
- Composant : [runners.docker]
- Périmètre d’impact : jobs sur ce runner spécifique
- Objectif : images prévisibles et moins de pulls réseau
Changement :
[runners.docker]
image = "alpine:3.19"
pull_policy = ["if-not-present"]
privileged = false
shm_size = 268435456
volumes = ["/cache"]
Prérequis et précautions :
- privileged = false améliore l’isolation ; les jobs nécessitant DinD (Docker-in-Docker) : exécuter Docker à l’intérieur d’un conteneur, peuvent échouer.
- shm_size aide Chrome/Playwright et d’autres navigateurs à éviter des arrêts OOM (Out Of Memory) : mémoire épuisée, dans /dev/shm.
Vérification :
- Relancez un job représentatif. Signaux : réutilisation d’image mise en cache dans les logs, pas d’échecs DinD si non requis.
Retour arrière :
- Restaurer la section docker précédente, recharger le runner.
Exemple C : Activer un cache compatible S3 pour des builds plus rapides
- Composant : [runners.cache]
- Périmètre d’impact : usage du cache pour les jobs sur ce runner
- Prérequis : le bucket de cache existe ; utiliser des identifiants lecture/écriture au périmètre minimal
Extrait de configuration avec espaces réservés uniquement (S3, Amazon Simple Storage Service : stockage objet compatible) :
[cache]
Type = "s3"
Shared = true
[cache.s3]
ServerAddress = "s3.example.com"
BucketName = "<CACHE_BUCKET>"
BucketLocation = "<REGION>"
Insecure = false
[cache.s3.access]
AccessKey = "<ACCESS_KEY>"
SecretKey = "<SECRET_KEY>"
Vérification :
- Ajoutez une section cache à votre fichier .gitlab-ci.yml (CI, Continuous Integration : intégration continue) et lancez un job :
cache:
key: "$CI_COMMIT_REF_SLUG"
paths:
- node_modules/
- Signaux : les logs du job affichent Creating cache puis Successfully uploaded cache ; les jobs suivants affichent Restoring cache.
Retour arrière :
- Commenter le bloc [cache] et recharger le runner.
Exemple D : Activer les métriques pour observer la capacité
- Composant : endpoint de métriques du runner
- Périmètre d’impact : aucun ; endpoint en lecture seule
[metrics]
listen_address = ":9252"
Vérification :
$ curl -s localhost:9252/metrics | grep gitlab_runner
Signaux : métriques telles que gitlab_runner_jobs_running, gitlab_runner_jobs_queued.
Vérification et diagnostic
Utilisez des vérifications ciblées pour valider la connectivité, l’enregistrement et la santé des exécuteurs.
- Valider l’enregistrement et l’accessibilité du runner
$ gitlab-runner verify
Signal : runners enregistrés imprimés avec OK ; en cas d’échec, erreurs HTTP ou d’auth. Si vous voyez Unauthorized, suspectez un token révoqué ou une URL incorrecte.
- Lancer un job en dry‑run local pour isoler les problèmes d’exécuteur
Pour l’exécuteur Docker, exécutez localement un job en vous appuyant sur votre .gitlab-ci.yml :
$ gitlab-runner exec docker <job_name> \
--docker-image alpine:3.19 \
--env CI_DEBUG_TRACE=true
Signal : le script du job s’exécute localement ; si l’échec se produit ici, le problème vient de la définition du job ou de l’image, pas du réseau GitLab.
- Inspecter les conteneurs de jobs en cours (Docker)
$ docker ps --filter label=com.gitlab.gitlab-runner.job.id -a
$ docker logs <CONTAINER_ID>
Signaux : erreurs de pull d’image, permissions, ou arrêts OOM.
- Inspecter les pods de jobs en cours (Kubernetes)
$ kubectl -n <JOB_NAMESPACE> get pods -l gitlab-job=true
$ kubectl -n <JOB_NAMESPACE> describe pod/<POD_NAME>
$ kubectl -n <JOB_NAMESPACE> logs <POD_NAME> --all-containers
Signaux : erreurs d’admission ou RBAC (Role-Based Access Control) : contrôle d’accès basé sur les rôles, ImagePullBackOff, ou échecs de planification de nœud.
- Confirmer le réseau et le comportement du proxy
Ajoutez une étape de diagnostic temporaire à un job non‑production :
script:
- apk add --no-cache curl
- curl -I --max-time 5 https://gitlab.com
Signal : 200/301/302 indique une connectivité sortante de base ; des timeouts suggèrent un pare‑feu ou un proxy bloquant.
Modes de panne et reprise
Voici des schémas de panne fréquents, leurs signaux, et des actions de reprise sécurisées.
- Jeton de runner invalide ou renouvelé
- Signaux : verify affiche Unauthorized ; jobs bloqués en pending avec Runner not found.
- Reprise : sur l’hôte runner, supprimez l’entrée obsolète et réenregistrez avec un nouveau token. Conservez les mêmes tags pour éviter de perturber les pipelines.
$ sudo gitlab-runner unregister --name <RUNNER_NAME>
$ sudo gitlab-runner register \
--url https://<GITLAB_URL>/ \
--token <RUNNER_TOKEN> \
--executor docker \
--docker-image alpine:3.19 \
--tag-list "linux,x86_64" \
--non-interactive
$ sudo systemctl restart gitlab-runner
- Hôte saturé ou concurrence mal réglée
- Signaux : longues files d’attente ; CPU de l’hôte à 100 % ; arrêts OOM dans les logs.
- Reprise : réduire concurrent dans config.toml, ajouter des limites de ressources (Docker : cpus, memory), ou déployer des runners supplémentaires.
[runners.docker]
cpus = "2"
memory = "4g"
- Échecs de pull d’images et limites de taux
- Signaux : Too Many Requests ou timeouts de pull.
- Reprise : pinner les images vers un miroir de registre interne, définir pull_policy = ["if-not-present"], ou pré‑télécharger les images critiques via un daemonset (Kubernetes) ou un cron (hôte Docker). Vérifiez en relançant un job et en confirmant l’absence de pulls externes.
- Le cache ne se restaure pas
- Signaux : les logs montrent No URL found for cache ou un cache miss à chaque exécution.
- Reprise : garantir une clé de cache identique, le bucket/région corrects, et Shared = true lorsque plusieurs runners partagent le même cache. Testez en exécutant deux jobs consécutifs sur des runners différents avec la même clé de cache.
- RBAC Kubernetes ou dérive de namespace
- Signaux : erreurs Forbidden à la création de pod ; ImagePullBackOff dû à des secrets manquants.
- Reprise : vérifier le service account, les role bindings et les imagePullSecrets dans la configuration du chart du runner. Revenir en arrière en réappliquant le dernier ConfigMap/Secret connu bon et en redémarrant le déploiement du runner.
- Pression disque et conteneurs résiduels
- Signaux : no space left on device ; nombreux conteneurs en état Exited ; /var/lib/docker volumineux.
- Reprise : mettre en place un nettoyage périodique :
$ docker system prune --volumes --filter "until=24h" -f
- Puis ajouter des tâches de cycle de vie en heures creuses. Vérifier via docker system df.
Liste de contrôle opérationnelle
Utilisez cette checklist reproductible pour les opérations courantes de runner. Adaptez‑la à votre environnement.
- Inventaire
- [ ] Noter gitlab-runner --version et l’OS/arch par hôte
- [ ] Lister les runners et tags ; confirmer portées et statut protégé
- [ ] Capturer config.toml avec horodatage et sauvegarde sécurisée
- Capacité et isolation
- [ ] Définir une valeur concurrent justifiée ; surveiller la saturation CPU/RAM
- [ ] Pour Docker : pinner l’image, définir pull_policy, shm_size et volumes
- [ ] Pour Kubernetes : confirmer namespaces, RBAC, node selectors et tolerations
- Cache et artéfacts
- [ ] Configurer un cache compatible S3 avec des clés de moindre privilège
- [ ] Vérifier une création de cache et une restauration sur des runners différents
- [ ] Aligner les artéfacts : quand, quoi et rétention
- Réseau et sécurité
- [ ] Tester la connectivité sortante et les règles de proxy depuis les jobs
- [ ] Éviter privileged sauf nécessité ; documenter la raison si activé
- [ ] Stocker les tokens dans des variables sécurisées ; ne jamais intégrer de secrets dans des fichiers
- Observabilité
- [ ] Activer l’endpoint de métriques ; scrapper et alerter sur les jobs en attente/en cours
- [ ] Centraliser les journaux du runner ; conserver des logs récents de jobs pour le diagnostic
- Gestion du changement
- [ ] Ne faire qu’un changement à la fois avec périmètre d’impact noté
- [ ] Vérifier immédiatement les signaux ; revenir vite en arrière si inattendu
- [ ] Garder un runner canari pour tester les mises à niveau avant déploiement large
Conclusion
Les opérations avancées de GitLab Runner deviennent prédictibles lorsque vous séparez observation et changement, réalisez de petites mises à jour ciblées, et vérifiez chaque étape avec des signaux clairs. Commencez par un inventaire propre de la version, de l’exécuteur et de la configuration. Apportez des améliorations ciblées à la concurrence, à l’isolation et au cache. Utilisez le diagnostic pour confirmer l’enregistrement, la santé des conteneurs ou pods, et la connectivité réseau. Préparez les échecs courants avec des retours arrière planifiés et un nettoyage régulier.
Choisissez dès maintenant une amélioration à faible risque, comme activer l’endpoint de métriques ou fixer une valeur concurrent conservatrice. Capturez l’état courant, appliquez le changement, vérifiez le résultat dans des pipelines réels, et documentez à la fois les critères de succès et le chemin de reprise. Ce mode opératoire rend les défaillances visibles, protège les valeurs sensibles et maintient des builds rapides et fiables.