Les runners self-hosted nécessitent une maintenance régulière pour rester performants et sécurisés. Ce guide couvre les opérations essentielles : mises à jour, monitoring, nettoyage et scaling.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Maintenir à jour le runner, l'OS et les outils
- Superviser les runners avec des health checks et Prometheus
- Nettoyer Docker, le répertoire de travail et les caches locaux
- Faire évoluer le parc, manuellement ou par auto-scaling
- Assurer la haute disponibilité pour éviter les points de défaillance
Mises à jour
Section intitulée « Mises à jour »Trois éléments demandent une attention différente : le runner (géré par GitHub), l'OS et les outils de build (à votre charge).
Mises à jour automatiques du runner
Section intitulée « Mises à jour automatiques du runner »Le runner se met à jour automatiquement quand GitHub déploie une nouvelle version. Lors d'un job, si une mise à jour est disponible, elle s'applique avant l'exécution.
Vérifier la version :
./run.sh --version# oucat /opt/actions-runner/.runner | jq '.agentVersion'Mises à jour de l'OS
Section intitulée « Mises à jour de l'OS »Le système de l'hôte, lui, n'est mis à jour par personne : c'est votre travail.
Le risque n'est pas la mise à jour elle-même mais le redémarrage qu'elle
peut exiger au milieu d'un job. unattended-upgrades applique les correctifs de
sécurité automatiquement ; dpkg-reconfigure ouvre un dialogue interactif où
vous choisissez si les mises à jour s'installent seules.
# Ubuntu/Debiansudo apt update && sudo apt upgrade -y
# Avec redémarrage planifiésudo apt install unattended-upgradessudo dpkg-reconfigure -plow unattended-upgradesMises à jour des outils
Section intitulée « Mises à jour des outils »Un runner hébergé par GitHub repart d'une image reconstruite régulièrement. Un runner self-hosted, lui, garde les versions installées le jour de sa mise en service : l'écart avec ce que supposent vos workflows se creuse en silence. Node.js, Docker et kubectl sont les trois outils qui décrochent le plus vite.
# Node.js via nvmnvm install --ltsnvm alias default lts/*
# Dockersudo apt updatesudo apt install docker-ce docker-ce-cli containerd.io
# kubectl : télécharger le binaire ET sa somme de contrôle officielleKUBECTL_VERSION="$(curl -L -s https://dl.k8s.io/release/stable.txt)"curl -LO "https://dl.k8s.io/release/${KUBECTL_VERSION}/bin/linux/amd64/kubectl"curl -LO "https://dl.k8s.io/release/${KUBECTL_VERSION}/bin/linux/amd64/kubectl.sha256"
# Refuser l'installation si l'empreinte ne correspond pasecho "$(cat kubectl.sha256) kubectl" | sha256sum --checksudo install kubectl /usr/local/bin/La vérification sha256sum --check affiche kubectl: OK quand l'empreinte
correspond. Si elle affiche FAILED, le binaire téléchargé n'est pas celui
publié par le projet : ne l'installez pas.
Monitoring
Section intitulée « Monitoring »Un runner qui tombe sans alerte bloque toute la CI silencieusement. Le monitoring rend visibles l'état de la machine et la disponibilité du runner.
Métriques système
Section intitulée « Métriques système »Ces commandes donnent l'état de la machine à l'instant présent. La dernière est
la plus révélatrice : Runner.Listener est le processus qui maintient la
connexion avec GitHub et attend les jobs. S'il n'apparaît pas, le runner est
affiché hors ligne dans l'interface, même si la machine répond parfaitement
au reste.
# CPU, mémoire, disquetop -bn1 | head -20free -hdf -h
# Processus du runnerps aux | grep Runner.ListenerScript de health check
Section intitulée « Script de health check »Ce script contrôle les trois causes de panne les plus fréquentes : le processus arrêté, le disque plein et la connexion à l'API GitHub coupée. Ses codes de sortie suivent la convention des sondes de supervision (0 pour sain, 1 pour avertissement, 2 pour critique), ce qui permet de le brancher tel quel sur la plupart des superviseurs.
#!/bin/bashRUNNER_DIR="/opt/actions-runner"
# Vérifier que le runner tourneif ! pgrep -f "Runner.Listener" > /dev/null; then echo "CRITICAL: Runner not running" exit 2fi
# Vérifier l'espace disqueDISK_USAGE=$(df -h / | awk 'NR==2 {print $5}' | sed 's/%//')if [ "$DISK_USAGE" -gt 90 ]; then echo "WARNING: Disk usage at ${DISK_USAGE}%" exit 1fi
# Vérifier la connexion à GitHubif ! curl -s --connect-timeout 5 https://api.github.com > /dev/null; then echo "CRITICAL: Cannot reach GitHub API" exit 2fi
echo "OK: Runner healthy"exit 0Prometheus + Grafana
Section intitulée « Prometheus + Grafana »Le health check répond par oui ou non ; Prometheus conserve l'historique et
permet de voir arriver une saturation avant qu'elle ne bloque un job.
node_exporter est l'agent qui expose les métriques système de la machine sur
le port 9100, que Prometheus vient ensuite collecter. Lancé en conteneur, il
ne voit par défaut que le conteneur : les répertoires /proc et /sys de
l'hôte sont donc montés en lecture seule, et les options --path.procfs et
--path.sysfs lui indiquent où les lire.
services: node-exporter: image: prom/node-exporter:v1.12.1@sha256:1b4e4438faca4dd7e001dd445d161a4a2091b0fededa84093b3a8dfeae1f1be0 ports: - "9100:9100" volumes: - /proc:/host/proc:ro - /sys:/host/sys:ro command: - "--path.procfs=/host/proc" - "--path.sysfs=/host/sys"Métriques utiles à surveiller :
node_cpu_seconds_total: utilisation CPUnode_memory_MemAvailable_bytes: mémoire disponiblenode_filesystem_avail_bytes: espace disque- Métriques custom sur les jobs exécutés
Alerting
Section intitulée « Alerting »Deux alertes couvrent l'essentiel : le runner injoignable et le disque proche de
la saturation. Le for: 5m évite de réveiller quelqu'un pour un simple
redémarrage du service, et le seuil 5e9 correspond à 5 Go d'espace libre
restant, soit environ un gros build d'avance.
# alertmanager rulesgroups: - name: runner-alerts rules: - alert: RunnerDown expr: up{job="runner"} == 0 for: 5m labels: severity: critical annotations: summary: "Runner {{ $labels.instance }} is down"
- alert: RunnerDiskFull expr: node_filesystem_avail_bytes{mountpoint="/"} < 5e9 for: 10m labels: severity: warning annotations: summary: "Runner disk space low"Nettoyage
Section intitulée « Nettoyage »Sur un runner persistant, builds et images s'accumulent jusqu'à saturer le disque. Un nettoyage planifié maintient la machine saine.
Nettoyage Docker
Section intitulée « Nettoyage Docker »Chaque prune vise une ressource différente et aucun n'est réversible. Le
filtre until=24h épargne les images créées dans les dernières 24 heures, donc
le cache de build de la journée. La dernière ligne est volontairement laissée en
commentaire : docker system prune -af --volumes supprime en plus tous les
volumes inutilisés, y compris les volumes nommés, et donc les données des
services de test qui tournent sur la machine.
#!/bin/bash# Images non utiliséesdocker image prune -af --filter "until=24h"
# Containers arrêtésdocker container prune -f
# Volumes orphelinsdocker volume prune -f
# Networks inutilisésdocker network prune -f
# Tout d'un coup (agressif)# docker system prune -af --volumesPlanifier avec cron :
0 3 * * * root /opt/scripts/docker-cleanup.sh >> /var/log/docker-cleanup.log 2>&1Nettoyage du work directory
Section intitulée « Nettoyage du work directory »Le répertoire _work contient un sous-répertoire par dépôt cloné et n'est
jamais purgé par le runner. _diag accumule les journaux d'exécution, un
fichier par job. Programmez ce nettoyage à une heure creuse : supprimer _work
pendant qu'un job tourne fait échouer ce job.
#!/bin/bashRUNNER_DIR="/opt/actions-runner"WORK_DIR="$RUNNER_DIR/_work"
# Supprimer les répertoires de travail vieux de plus de 7 joursfind "$WORK_DIR" -type d -mtime +7 -exec rm -rf {} \;
# Supprimer les logs anciensfind "$RUNNER_DIR/_diag" -name "*.log" -mtime +30 -deleteNettoyage du cache actions
Section intitulée « Nettoyage du cache actions »Attention à ne pas confondre deux choses. Le cache géré par l'action
actions/cache est stocké chez GitHub, pas sur votre machine, et se purge
depuis l'interface du dépôt. Les répertoires ci-dessous sont les caches locaux
des gestionnaires de paquets npm, pip et Maven : les effacer ne
casse rien, le prochain build les reconstruit au prix d'un téléchargement
complet.
# Le cache actions/cache est géré par GitHub# Mais le cache local (npm, pip, etc.) peut s'accumuler
rm -rf ~/.npm/_cacacherm -rf ~/.cache/piprm -rf ~/.m2/repositoryQuand la file d'attente s'allonge, il faut ajouter des runners, à la main pour un petit parc, automatiquement dès que le volume grandit.
Scaling manuel
Section intitulée « Scaling manuel »Un runner supplémentaire se configure exactement comme le premier. Deux détails comptent : le token d'enregistrement récupéré dans les paramètres du dépôt ou de l'organisation expire au bout d'une heure, et les labels décident seuls des jobs que la machine acceptera.
# Sur une nouvelle machine./config.sh --url https://github.com/ORG/REPO \ --token TOKEN \ --labels linux,x64,docker \ --name runner-$(hostname)./run.shAuto-scaling avec Actions Runner Controller
Section intitulée « Auto-scaling avec Actions Runner Controller »Actions Runner Controller (ARC) est un opérateur Kubernetes qui crée et
détruit des pods runners à la demande. Le HorizontalRunnerAutoscaler réagit
aux événements workflowJob envoyés par GitHub : un job entre en file, un
runner apparaît. Le scaleDownDelaySecondsAfterScaleOut impose 300 secondes
avant toute réduction, ce qui évite de détruire une machine qui vient d'être
créée. L'exemple s'appuie sur l'API actions.summerwind.dev, celle du mode
historique d'ARC.
apiVersion: actions.summerwind.dev/v1alpha1kind: HorizontalRunnerAutoscalermetadata: name: runner-autoscalerspec: scaleTargetRef: name: runner-deployment minReplicas: 2 maxReplicas: 20 scaleUpTriggers: - githubEvent: workflowJob: {} duration: "30m" scaleDownDelaySecondsAfterScaleOut: 300Scaling cloud (AWS)
Section intitulée « Scaling cloud (AWS) »Sans Kubernetes, le parc devient un groupe d'autoscaling classique. Tout
repose sur le launch_template : c'est lui qui doit contenir l'enregistrement
du runner au démarrage, sinon l'instance créée ne s'annoncera jamais à GitHub et
restera facturée pour rien. Le cooldown de 300 secondes empêche la politique
de rajouter deux instances coup sur coup avant d'avoir vu l'effet de la
première.
resource "aws_autoscaling_group" "runners" { name = "github-runners" desired_capacity = 2 min_size = 1 max_size = 10 vpc_zone_identifier = var.subnet_ids
launch_template { id = aws_launch_template.runner.id version = "$Latest" }
tag { key = "Name" value = "github-runner" propagate_at_launch = true }}
resource "aws_autoscaling_policy" "scale_up" { name = "scale-up" scaling_adjustment = 2 adjustment_type = "ChangeInCapacity" cooldown = 300 autoscaling_group_name = aws_autoscaling_group.runners.name}Haute disponibilité
Section intitulée « Haute disponibilité »Un runner unique est un point de défaillance : s'il tombe, la CI s'arrête. Plusieurs réflexes éliminent ce risque.
Multi-runners
Section intitulée « Multi-runners »GitHub attribue un job au premier runner libre dont les labels couvrent ceux demandés. En désignant un jeu de labels plutôt qu'une machine précise, vous laissez le service arbitrer : la perte d'un runner ralentit la file, elle ne la bloque plus.
jobs: build: runs-on: [self-hosted, linux] # GitHub choisira un runner disponible parmi ceux qui matchentRépartition géographique
Section intitulée « Répartition géographique »Des labels de région permettent de rapprocher un job des ressources qu'il manipule : registre d'images, cluster cible ou base de données. Gardez en tête qu'un label est une simple chaîne déclarée à l'enregistrement du runner : GitHub ne vérifie pas qu'elle corresponde à une zone réelle.
jobs: build-eu: runs-on: [self-hosted, linux, eu-west-1]
build-us: runs-on: [self-hosted, linux, us-east-1]Fallback sur GitHub-hosted
Section intitulée « Fallback sur GitHub-hosted »runs-on accepte une expression, ce qui autorise une bascule sans toucher
au fichier de workflow. Il suffit de basculer la variable USE_SELF_HOSTED dans
les paramètres du dépôt : le temps d'une maintenance du parc, les jobs repartent
sur les runners hébergés par GitHub, facturés à la minute.
jobs: build: # Essayer self-hosted d'abord, fallback sur GitHub-hosted runs-on: ${{ vars.USE_SELF_HOSTED == 'true' && 'self-hosted' || 'ubuntu-24.04' }}Checklist de maintenance
Section intitulée « Checklist de maintenance »Pour ne rien oublier, voici les opérations à mener, réparties selon leur fréquence, du quotidien automatisé à la revue trimestrielle.
Quotidien (automatisé)
Section intitulée « Quotidien (automatisé) »Aucune de ces trois tâches ne doit dépendre d'une présence humaine : elles tournent en cron ou en timer systemd, sinon elles sautent le jour où vous êtes en congés.
- Health checks toutes les 5 minutes
- Nettoyage Docker la nuit
- Rotation des logs
Hebdomadaire
Section intitulée « Hebdomadaire »Une revue de dix minutes suffit à repérer une dérive avant qu'elle ne devienne une panne : un disque qui se remplit régulièrement ou une alerte qui se répète méritent une correction, pas un acquittement.
- Vérifier les mises à jour de l'OS
- Vérifier l'espace disque
- Revoir les alertes de la semaine
Le rendez-vous mensuel traite ce qui bouge lentement : versions d'outils, droits d'accès et durée des builds. Un temps de build qui double sur trois mois passe inaperçu au quotidien mais saute aux yeux dans une comparaison mensuelle.
- Mises à jour des outils (Node, Python, etc.)
- Audit des accès aux runners
- Revue des performances (temps de build)
- Vérifier la rotation des tokens
Trimestriel
Section intitulée « Trimestriel »À ce rythme, il ne s'agit plus de corriger mais de décider : l'architecture actuelle tient-elle encore la charge, et le coût du parc reste-t-il justifié face aux runners hébergés ? C'est aussi le moment de vérifier qu'une remise en service complète fonctionne réellement.
- Mise à jour majeure de l'OS si nécessaire
- Revue de l'architecture des runners
- Test de disaster recovery
- Optimisation des coûts
Contrôle de connaissances
Section intitulée « Contrôle de connaissances »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
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
Vérification
(0/0)Profil de compétences
Quoi faire maintenant
Ressources pour progresser
Des indices pour retenter votre chance ?
Nouveau quiz complet avec des questions aléatoires
Retravailler uniquement les questions ratées
Retour à la liste des certifications
À retenir
Section intitulée « À retenir »- Le runner se met à jour seul ; à votre charge : l'OS et les outils utilisés par vos workflows.
- Un health check régulier (processus, disque, connexion GitHub) détecte les pannes avant qu'elles ne bloquent la CI.
- Le nettoyage Docker et du
_workest indispensable : sans lui, le disque sature en quelques jours. - L'auto-scaling (ARC ou cloud) ajuste le parc à la charge, pas de runners inactifs facturés pour rien.
- Plusieurs runners par label évitent le point de défaillance unique ; un fallback GitHub-hosted sécurise les pics.