Les runners éphémères sont créés à la demande et détruits après chaque job. Ce pattern élimine les risques de persistence de données entre jobs et garantit un environnement propre à chaque exécution.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Comprendre pourquoi un runner jetable est plus sûr qu'un runner persistant
- Activer le mode
--ephemeraldu runner GitHub - Mettre en place l'auto-scaling avec ARC (Kubernetes) ou des VM cloud
- Conteneuriser un runner éphémère avec Docker
- Gérer le pool et compenser l'absence de cache local
Pourquoi des runners éphémères ?
Section intitulée « Pourquoi des runners éphémères ? »Problèmes des runners persistants
Section intitulée « Problèmes des runners persistants »- Données résiduelles : fichiers, caches, credentials d'un job précédent
- Drift de configuration : l'environnement change au fil du temps
- Surface d'attaque : un job malveillant peut compromettre les suivants
Avantages des runners éphémères
Section intitulée « Avantages des runners éphémères »- Isolation parfaite : comme les runners GitHub-hosted
- Reproductibilité : même environnement à chaque exécution
- Sécurité : pas de persistence entre jobs
L'option --ephemeral
Section intitulée « L'option --ephemeral »Le runner GitHub supporte nativement le mode éphémère :
./config.sh --url https://github.com/OWNER/REPO \ --token TOKEN \ --ephemeralComportement :
- Le runner accepte un seul job
- Après exécution, il se désenregistre automatiquement
- La VM/container peut être détruite
Architecture avec auto-scaling
Section intitulée « Architecture avec auto-scaling »Créer un runner à la main pour chaque job n'est pas tenable. L'auto-scaling provisionne et détruit les runners automatiquement selon la charge.
Avec Actions Runner Controller (ARC)
Section intitulée « Avec Actions Runner Controller (ARC) »ARC est la solution officielle pour Kubernetes :
apiVersion: actions.summerwind.dev/v1alpha1kind: RunnerDeploymentmetadata: name: ephemeral-runnersspec: replicas: 1 template: spec: ephemeral: true repository: owner/repo labels: - self-hosted - linux - ephemeral---apiVersion: actions.summerwind.dev/v1alpha1kind: HorizontalRunnerAutoscalermetadata: name: ephemeral-runners-autoscalerspec: scaleTargetRef: name: ephemeral-runners minReplicas: 0 maxReplicas: 10 metrics: - type: TotalNumberOfQueuedAndInProgressWorkflowRuns repositoryNames: - owner/repoAvec des VMs cloud
Section intitulée « Avec des VMs cloud »Script de scaling avec AWS :
#!/bin/bash# Créer une VMINSTANCE_ID=$(aws ec2 run-instances \ --image-id ami-xxxxx \ --instance-type t3.medium \ --user-data file://runner-init.sh \ --query 'Instances[0].InstanceId' \ --output text)
echo "Launched: $INSTANCE_ID"Script d'initialisation :
#!/bin/bash# runner-init.sh (user-data)
# Télécharger le runnercd /optcurl -o runner.tar.gz -L https://github.com/actions/runner/releases/download/v2.xxx.x/actions-runner-linux-x64-2.xxx.x.tar.gztar xzf runner.tar.gz
# Obtenir un token d'enregistrement (via API GitHub)TOKEN=$(curl -s -X POST \ -H "Authorization: token $GITHUB_PAT" \ https://api.github.com/repos/OWNER/REPO/actions/runners/registration-token \ | jq -r '.token')
# Configurer en mode éphémère./config.sh --url https://github.com/OWNER/REPO \ --token $TOKEN \ --ephemeral \ --unattended \ --labels ephemeral,linux
# Exécuter (va s'arrêter après un job)./run.sh
# Auto-destructionaws ec2 terminate-instances --instance-ids $(curl -s http://169.254.169.254/latest/meta-data/instance-id)Avec Docker
Section intitulée « Avec Docker »Sans Kubernetes, Docker suffit à obtenir des runners jetables : un conteneur par job, détruit à la fin de l'exécution.
Runner dans un container
Section intitulée « Runner dans un container »FROM ubuntu:22.04
RUN apt-get update && apt-get install -y \ curl jq git \ && rm -rf /var/lib/apt/lists/*
# Télécharger le runnerRUN curl -o /tmp/runner.tar.gz -L \ https://github.com/actions/runner/releases/download/v2.xxx.x/actions-runner-linux-x64-2.xxx.x.tar.gz \ && mkdir /runner \ && tar xzf /tmp/runner.tar.gz -C /runner \ && rm /tmp/runner.tar.gz
WORKDIR /runner
COPY entrypoint.sh /entrypoint.shENTRYPOINT ["/entrypoint.sh"]#!/bin/bash./config.sh --url $REPO_URL \ --token $RUNNER_TOKEN \ --ephemeral \ --unattended \ --labels docker,ephemeral
./run.sh# Le container s'arrête après un jobOrchestration avec docker-compose
Section intitulée « Orchestration avec docker-compose »version: '3.8'services: runner: build: context: . dockerfile: Dockerfile.runner environment: - REPO_URL=https://github.com/owner/repo - RUNNER_TOKEN=${RUNNER_TOKEN} restart: "no" # Ne pas redémarrer (éphémère) deploy: replicas: 3Gérer le pool de runners
Section intitulée « Gérer le pool de runners »Un pool de runners éphémères se pilote : trouver l'équilibre entre réactivité (éviter les cold starts) et coût (ne pas garder trop de runners inactifs).
Stratégie de pré-chauffage
Section intitulée « Stratégie de pré-chauffage »Pour éviter les cold starts, maintenez un pool minimum :
# Kubernetes HPAspec: minReplicas: 2 # Toujours 2 runners prêts maxReplicas: 20 # Scale jusqu'à 20 si nécessaireMonitoring du pool
Section intitulée « Monitoring du pool »# Prometheus metrics avec ARC- job_name: 'actions-runner-controller' static_configs: - targets: ['actions-runner-controller-metrics:8080']Métriques utiles :
actions_runner_controller_running_runners: runners actifsactions_runner_controller_pending_runners: en attente de jobactions_runner_controller_registered_runners: total enregistrés
Workflow utilisant les runners éphémères
Section intitulée « Workflow utilisant les runners éphémères »name: Build with Ephemeral Runner
on: push: branches: [main]
# Aucun droit par défaut : chaque job demande le minimumpermissions: {}
jobs: build: runs-on: [self-hosted, ephemeral, linux] permissions: contents: read steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: persist-credentials: false
- name: Build run: | npm ci npm run build
# Pas besoin de cleanup : le runner sera détruit
deploy: needs: build runs-on: [self-hosted, ephemeral, linux] permissions: contents: read # Nouveau runner frais pour le déploiement steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: persist-credentials: false - run: ./deploy.shConsidérations
Section intitulée « Considérations »Le modèle éphémère a un prix : pas de cache local, des cold starts, un coût d'infrastructure variable. Voici les points à anticiper.
Temps de démarrage
Section intitulée « Temps de démarrage »| Méthode | Cold start |
|---|---|
| Container Docker | 5-15s |
| VM cloud | 30-90s |
| Kubernetes pod | 10-30s |
Cache et dépendances
Section intitulée « Cache et dépendances »Avec des runners éphémères, le cache local n'existe pas. Options :
- actions/cache : cache sur GitHub Storage
- uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 with: path: ~/.npm key: npm-${{ hashFiles('package-lock.json') }}- Registry de cache : images Docker avec dépendances pré-installées
container: image: myregistry.com/node-with-deps:latest- Volume partagé : NFS ou EFS monté sur les runners
- Plus de VMs créées/détruites = plus de coût si facturation à l'heure
- Optimiser avec des instances spot/preemptible
- Équilibrer entre pool minimum et coût
À retenir
Section intitulée « À retenir »- Un runner éphémère accepte un seul job puis se désenregistre — l'isolation des runners hosted, sur votre infra.
- Le mode natif s'active avec
./config.sh --ephemeral: pas d'outil tiers requis. - En Kubernetes, Actions Runner Controller gère création, scaling et destruction automatiquement.
- Sans cache local, compensez avec
actions/cache, des images pré-garnies ou un volume partagé. - Gardez un pool minimum chaud pour absorber les cold starts sans exploser le coût.