E-NO
Performances GitLab Runner 7 min de lecture

Optimiser les performances de GitLab Runner avec des exemples concrets

calendar_today Publié : 2026-09-03
update Dernière mise à jour : 2026-09-03
analytics Efficacité SEO : 100%
Illustration du guide technique pour « Optimiser les performances de GitLab Runner avec des exemples concrets ».

Intro

Une CI rapide et prévisible ne se résume pas à utiliser des machines plus puissantes. Elle demande une méthode claire : observer l’état actuel, apporter le plus petit changement justifié, vérifier le résultat, puis documenter comment revenir en arrière. Cet article propose un parcours de tuning des performances de GitLab Runner destiné aux développeurs et aux opérateurs, avec des exemples concrets adaptables aux exécuteurs Docker, Kubernetes ou shell.

Objectifs :

  • Réduire le temps d’attente en file et la durée des jobs sans sacrifier la fiabilité.
  • Identifier précisément les goulots d’étranglement (CPU, mémoire, E/S, pulls d’images, cache qui s’emballe).
  • Appliquer des changements de configuration sûrs et réversibles, avec vérification explicite.

Hypothèses : les exemples visent des hôtes Linux exécutant GitLab Runner 13+ (service géré par systemd). Remplacez les valeurs fictives comme YOUR_GITLAB_URL, RUNNER_NAME et S3_BUCKET par vos propres valeurs.

Inventaire des versions et de l’environnement

Avant toute modification, capturez un instantané factuel de l’existant. Gardez l’observation en lecture seule et horodatée.

  1. Identifier les versions et la topologie
  • Binaire runner et OS :
  date -Is
  gitlab-runner --version
  uname -a
  • Type d’exécuteur et runners enregistrés sur cet hôte :
  gitlab-runner list
  • État du service et logs récents (Linux/systemd) :
  systemctl status gitlab-runner --no-pager
  journalctl -u gitlab-runner -n 200 --no-pager
  • Pour l’exécuteur Kubernetes, notez aussi la version du cluster et le profil des nœuds :
  kubectl version --short
  kubectl get nodes -o wide
  1. Relever le matériel et la pression des ressources
  • CPU et mémoire :
  lscpu | egrep 'CPU\(s\)|Model name'
  free -h
  • Capacité disque et marge d’E/S :
  df -hT
  iostat -xz 1 3  # si sysstat est installé
  • Pression sur le cache Docker (exécuteur Docker) :
  docker system df
  1. Capturer la configuration du runner (lecture seule)
  • Fichier généralement situé sous /etc/gitlab-runner/config.toml :
  sudo sed -n '1,200p' /etc/gitlab-runner/config.toml | sed 's/\(token = \).*/\1\"REDACTED\"/'

Notez la valeur globale de concurrent, la limite par runner, l’exécuteur, la stratégie de pull, les paramètres de cache et d’éventuelles limites de ressources Kubernetes.

  1. Établir les symptômes CI de base
  • Depuis l’interface GitLab, ouvrez quelques pipelines récents et relevez pour chaque job :
  • Temps d’attente (de created_at à started_at)
  • Durée totale
  • Temps en "Preparing environment" (souvent lié aux pulls d’images) vs temps de script
  • Exportez des médianes approximatives pour le projet le plus chargé. Notez ce que « bon » signifie (ex. : attente < 30 s, job < 6 min).

Ne planifiez un changement qu’une fois l’existant compris, avec un périmètre contrôlé et une marche arrière connue.

Chemin de configuration sécurisé

Chaque étape de tuning suit le même schéma : observer -> changer un élément circonscrit -> vérifier -> consigner -> revenir en arrière si nécessaire. Adaptez les valeurs à votre matériel et à votre charge.

1) Dimensionner correctement la concurrence

Portée : concurrence globale du runner sur un hôte unique.

  • Observer :
  • Dans config.toml, recherchez :
    concurrent = 1
  • Aux heures de pointe, vérifiez le steal/wait CPU et la charge moyenne pendant que N jobs tournent.
  • Plus petit changement justifié :
  • Démarrez avec une valeur concurrent égale au nombre de cœurs physiques pour des tâches liées au CPU, jusqu’à 1,5× pour des tâches surtout E/S. Limitez chaque runner pour éviter qu’un runner ne sature tout.
  • Modifier et vérifier :
  sudo cp /etc/gitlab-runner/config.toml /etc/gitlab-runner/config.toml.bak.$(date +%s)
  sudo editor /etc/gitlab-runner/config.toml
  # Exemples de changements :
  # concurrent = 8
  # [[runners]]
  #   name = 'RUNNER_NAME'
  #   limit = 6

  sudo systemctl restart gitlab-runner
  gitlab-runner verify
  • Résultat attendu : le temps d’attente diminue, sans CPU bloqué > 90 % de façon prolongée ni événements OOM.
  • Signal d’échec : hausse des échecs de jobs avec des codes liés à l’OOM/aux timeouts ou pics de charge hôte. Rétablissement : restaurez le fichier de sauvegarde puis redémarrez le service.

2) Réduire la latence de pull des images Docker

Portée : avec l’exécuteur Docker, des pulls répétés d’images allongent "Preparing environment".

  • Observer : dans les logs de job, cherchez des lignes répétées Pulling docker image et des temps de téléchargement longs. Vérifiez le cache local :
  docker images --format '{{.Repository}}:{{.Tag}}\t{{.Size}}' | sort
  • Plus petit changement justifié : définir pull_policy sur if-not-present et standardiser une image de base légère.
  • Modifier et vérifier :
  # /etc/gitlab-runner/config.toml
  [[runners]]
    executor = 'docker'
    [runners.docker]
      image = 'alpine:3.19'
      pull_policy = 'if-not-present'
      shm_size = 134217728  # 128 Mo pour des tests de type Chrome/Playwright; ajustez au besoin

Puis redémarrez le runner et exécutez un pipeline utilisant l’image configurée.

  • Résultat attendu : les jobs suivants réutilisent les images locales; le temps de préparation baisse.
  • Signal d’échec : images obsolètes non rafraîchies. Si vous dépendez de mises à jour fréquentes, utilisez pull_policy = 'always' uniquement pour ces jobs ou tags. Rétablissement : revenir à la politique précédente ou épingler les digests d’image.

Conseil : si la bande passante du registre est un goulot, utilisez un miroir de registre local ou pré-téléchargez les images lourdes via cron hors des heures de pointe.

3) Optimiser le clone Git et la gestion du dépôt

Portée : surcharge réseau et disque liée à la récupération du code source.

  • Observer : contrôlez la durée du clone au début des jobs. Les historiques volumineux ou submodules ralentissent.
  • Plus petit changement justifié : utiliser des clones superficiels et des stratégies sélectives.
  • Ajouter au projet, au groupe ou au .gitlab-ci.yml :
  variables:
    GIT_DEPTH: '20'        # essayez 1 pour la plupart des projets; augmentez si votre build a besoin de plus d’historique
    GIT_SUBMODULE_STRATEGY: recursive
    GIT_STRATEGY: fetch     # évite de purger l’espace de travail quand le cache est chaud
  • Résultat attendu : transferts réseau plus légers et démarrages plus rapides.
  • Signal d’échec : builds nécessitant l’historique complet (ex. versionnement à partir des tags) cassés. Rétablissement : augmenter GIT_DEPTH ou définir des exceptions au niveau des jobs.

4) Tirer parti des caches (sans qu’ils se retournent contre vous)

Portée : réduire les téléchargements/reconstructions redondants; éviter les tempêtes de cache.

  • Observer : comparez la durée des jobs avec et sans cache chaud; inspectez la croissance de la taille du cache. Si vous utilisez le cache local par défaut, surveillez l’usage disque sous /var/lib/gitlab-runner.
  • Plus petit changement justifié : passer à un cache partagé compatible S3 pour plusieurs runners; définir des clés de cache précises.
  • Configuration du cache runner (exemple) :
  # /etc/gitlab-runner/config.toml
  [runners.cache]
    Type = 's3'
    Path = 'cache/'
    Shared = true
    [runners.cache.s3]
      ServerAddress = 'https://s3.YOUR_REGION.example.com'
      AccessKey = 'REDACTED'
      SecretKey = 'REDACTED'
      BucketName = 'S3_BUCKET'
      Insecure = false
  • Exemple de cache au niveau du job (Node.js) :
  cache:
    key:
      files:
        - package-lock.json
    paths:
      - node_modules/
    policy: pull-push
  • Résultat attendu : taux de hit cohérents entre runners; baisse du temps total de pipeline.
  • Signal d’échec : cache corrompu (obsolète ou conflits inter-branches) ou coûts de stockage qui dérapent. Rétablissement : inclure la branche dans la clé pour les chemins risqués, limiter les paths, ou passer temporairement policy: pull sur la branche par défaut.

5) Sanité des ressources pour l’exécuteur Kubernetes

Portée : éviter le throttling CPU et les évictions mémoire dans les pods K8s.

  • Observer :
  kubectl get pods -n YOUR_NS
  kubectl describe pod YOUR_POD -n YOUR_NS | egrep 'Reason|Limits|Requests'
  • Plus petit changement justifié : définir des requests/limits alignées sur l’usage typique; préférez des requests proches de la médiane et des limits proches du p95.
  • Extrait de configuration du runner :
  [[runners]]
    executor = 'kubernetes'
    [runners.kubernetes]
      image = 'alpine:3.19'
      poll_timeout = 600
      cpu_request = '500m'
      memory_request = '512Mi'
      cpu_limit = '2'
      memory_limit = '2Gi'
      pull_policy = 'IfNotPresent'
  • Résultat attendu : moins de pods Pending (ressources insuffisantes), durées de job stables.
  • Signal d’échec : pods Pending/Failed avec pression de nœud ou OOMKilled. Rétablissement : baisser limits/requests, ajouter des nœuds, ou répartir les runners sur plusieurs groupes de nœuds.

Vérification et diagnostics

Utilisez les mêmes contrôles à chaque ajustement pour rendre vos améliorations mesurables et reproductibles.

  1. Connectivité et santé
gitlab-runner verify           # tous les runners du config; affiche is alive pour chacun
systemctl is-active gitlab-runner && echo OK
  1. Tendances du temps d’attente et des durées
  • Dans l’interface GitLab, comparez les médianes du temps d’attente et de la durée totale avant/après votre changement sur au moins 20 jobs récents.
  • Pour automatiser, exportez les données de job via l’API GitLab et calculez les deltas par étape.
  1. Logs du runner et niveau de debug
  • Augmentez temporairement la verbosité :
  # /etc/gitlab-runner/config.toml
  log_level = 'debug'

Puis redémarrez et suivez les logs pendant un pipeline isolé. Revenez à info une fois terminé.

  1. Endpoint de métriques (si pris en charge par votre version)
  • Activez l’endpoint Prometheus intégré sur l’hôte runner et vérifiez en local :
  # /etc/gitlab-runner/config.toml
  listen_address = ':9252'
  sudo systemctl restart gitlab-runner
  curl -s http://127.0.0.1:9252/metrics | head
  • Suivez les builds actifs, la profondeur de file et les erreurs d’exécuteur dans votre stack de supervision.
  1. Contrôles de l’environnement Docker/Kubernetes
  • Cache Docker et performance des pulls :
  /usr/bin/time -f '%E %C' docker pull alpine:3.19
  docker system df
  • Pression de planification Kubernetes :
  kubectl top nodes
  kubectl describe node YOUR_NODE | egrep 'Allocatable|Pods:|CPU|memory'

Modes de défaillance et rétablissement

Ayez un plan de retour arrière avant tout changement. Voici des écueils fréquents et comment les résoudre en sécurité.

  1. Sur-concurrence (thrash de l’hôte)
  • Symptômes : CPU > 95 % pendant plusieurs minutes, hausse des timeouts, OOM ou tempêtes de swap.
  • Rétablissement immédiat : réduire concurrent et la limit par runner, puis redémarrer le service.
  • Long terme : scaler horizontalement avec des runners supplémentaires ou des instances plus grandes; séparer les jobs lourds/légers avec des tags.
  1. Goulots sur les pulls d’images
  • Symptômes : long "Preparing environment" avec pulls fréquents, erreurs 429/5xx du registre.
  • Rétablissement immédiat : passer à pull_policy = 'if-not-present'; épingler temporairement les images par digest; pré-puller via cron ou DaemonSet (K8s).
  • Long terme : ajouter un miroir de registre local, affiner vos images, consolider les couches de base.
  1. Tempêtes de cache et caches obsolètes
  • Symptômes : chute soudaine du taux de hit, fort egress depuis le backend de cache, artefacts incohérents.
  • Rétablissement immédiat : resserrer les clés (inclure la branche ou le lockfile), marquer les caches risqués en policy: pull jusqu’à stabilisation.
  • Long terme : séparer les caches par chaîne d’outils, imposer des limites de taille, documenter les conventions d’invalidation.
  1. Saturation E/S disque ou espace insuffisant
  • Symptômes : jobs lents, extraction de couches Docker qui stagnent, erreurs ENOSPC.
  • Rétablissement immédiat : nettoyer les artefacts et images sûrs hors des heures de pointe :
  docker system prune -af --volumes

Déplacer le cache du runner vers un disque plus grand/rapide et ajuster [runners.cache].Path en conséquence.

  • Long terme : provisionner plus d’IOPS, utiliser un stockage plus rapide pour /var/lib/docker et les répertoires de cache, et dimensionner correctement les caches.
  1. Runners bloqués ou hors ligne
  • Symptômes : jobs en attente; runner affiché hors ligne dans GitLab.
  • Rétablissement immédiat :
  gitlab-runner verify
  systemctl restart gitlab-runner

Si nécessaire, réenregistrer :

  gitlab-runner register \
    --url https://YOUR_GITLAB_URL \
    --registration-token REG_TOKEN \
    --name RUNNER_NAME \
    --executor docker \
    --tag-list default,docker \
    --non-interactive
  • Long terme : automatiser des contrôles de santé et des alertes sur la vivacité des runners.

Liste de contrôle opérationnelle

Exécutez régulièrement cette liste légère pour garder une CI rapide et sûre.

Quotidien

  • Examiner les médianes de temps d’attente et de durée pour les projets principaux.
  • Vérifier la santé des runners : gitlab-runner verify et systemctl is-active.
  • Surveiller l’usage disque pour Docker et les répertoires de cache.

Hebdomadaire

  • Réévaluer concurrent et la limit par runner selon la marge CPU/mémoire réelle.
  • Examiner les logs de pulls d’images; pré-puller ou mettre en miroir les bases lourdes.
  • Valider les taux de hit du cache et ajuster clés/paths si dérive.

Mensuel ou après des changements majeurs

  • Re-baseliner les métriques de performance et mettre à jour vos seuils « bons ».
  • Auditer la configuration des runners pour détecter la dérive; comparer à un gabarit de référence.
  • Pour Kubernetes, vérifier l’alignement requests/limits avec les profils de jobs actuels; scaler les nœuds si besoin.

Conclusion

Un tuning efficace de GitLab Runner est discipliné et incrémental. Commencez par un inventaire, changez un seul élément bien circonscrit, puis vérifiez avec des signaux clairs : attente réduite, durées plus courtes et stables, et utilisation saine des ressources. Évitez d’exposer des secrets dans les logs et configs, privilégiez les modifications réversibles et documentez les étapes de retour avant d’en avoir besoin.

À mesure que votre charge évolue, réévaluez la concurrence, la stratégie d’images, le caching et les ressources des exécuteurs. L’alliance de mesures concrètes, de changements minimaux et d’une vérification fiable maintiendra vos pipelines rapides sans compromettre la fiabilité.

Score de qualité de l’article

Utilité pour le lecteur 100%
  • check_circle Guide prêt à lire
  • check_circle Exemples pratiques inclus
  • check_circle URL d’article optimisée pour le SEO