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 »# 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 »Maintenez à jour les outils utilisés par vos workflows :
# Node.js via nvmnvm install --ltsnvm alias default lts/*
# Dockersudo apt updatesudo apt install docker-ce docker-ce-cli containerd.io
# kubectlcurl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"sudo install kubectl /usr/local/bin/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 »# 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 »#!/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 »Exposez des métriques avec node_exporter :
services: node-exporter: image: prom/node-exporter:latest ports: - "9100:9100" volumes: - /proc:/host/proc:ro - /sys:/host/sys:roMé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 »# 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 »#!/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 »#!/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 »# 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 »Ajouter un runner :
# 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 »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) »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 »Toujours avoir plusieurs runners pour éviter les SPOF :
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 »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 »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é) »- Health checks toutes les 5 minutes
- Nettoyage Docker la nuit
- Rotation des logs
Hebdomadaire
Section intitulée « Hebdomadaire »- Vérifier les mises à jour de l'OS
- Vérifier l'espace disque
- Revoir les alertes de la semaine
- 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 »- Mise à jour majeure de l'OS si nécessaire
- Revue de l'architecture des runners
- Test de disaster recovery
- Optimisation des coûts
À 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.