Runners GitHub Actions : la moitié du prix, mesuré

Les runners GitHub Actions de FFxF sont ouverts à tous, en bêta. Le même workflow lancé chez GitHub et chez nous : compilation un peu plus rapide, facture divisée par deux, docker build plus lent à froid et 4 secondes avec le cache Docker.

Un workflow confie un job à une machine neuve, comptée au chronomètre, avec son cache à côté ; les machines des jobs précédents sont déjà parties

Les runners GitHub Actions de FFxF sont ouverts à tous les comptes, en bêta. Sur le papier, l'argument tient en une ligne : 0,004 CAD la minute en 2 vCPU, soit 0,003 USD, contre 0,006 USD pour le runner Linux de GitHub. Il restait à voir ce que cela donne sur un vrai workflow, en temps comme en argent.

Le 22 octobre 2026, nous avons lancé le même fichier de workflow sur ubuntu-latest chez GitHub et sur ffxf-2vcpu-ubuntu-2404 chez nous, deux machines de 2 vCPU, deux fois de suite. Voici les chiffres, y compris là où nous sommes plus lents.

1. Le workflow d'essai

Deux jobs indépendants, choisis parce qu'ils ressemblent à une CI ordinaire :

  • go compile GitHub CLI (cli/cli, version 2.63.0) et lance les tests des commandes pr et issue, avec le cache de actions/setup-go. C'est surtout du calcul.
  • docker construit l'image de l'application d'exemple de Docker (docker/getting-started-app) sur node:22-slim, avec npm ci. C'est surtout du téléchargement.

D'un essai à l'autre, seule change l'étiquette passée à runs-on :

yaml
on:
  workflow_dispatch:
    inputs:
      label:
        default: ffxf-2vcpu-ubuntu-2404

jobs:
  go:
    runs-on: ${{ inputs.label }}
    steps:
      - uses: actions/checkout@v4
        with:
          repository: cli/cli
          ref: v2.63.0
      - uses: actions/setup-go@v5
        with:
          go-version-file: go.mod
      - run: go build -o bin/gh ./cmd/gh
      - run: go test ./pkg/cmd/pr/... ./pkg/cmd/issue/...

  docker:
    runs-on: ${{ inputs.label }}
    steps:
      - run: |
          git clone https://github.com/docker/getting-started-app.git app
          cd app
          # Dockerfile : FROM node:22-slim, npm ci --omit=dev, COPY . .
          docker build -t todo-app .

Les machines, telles que le job les décrit : un AMD EPYC (7763 au premier passage, 9V74 au second) chez GitHub, un Intel Xeon Gold 6252 chez nous, 2 vCPU des deux côtés. Un détail compte pour la comparaison : ubuntu-latest désigne maintenant Ubuntu 26.04 chez GitHub, alors que nos runners suivent l'image ubuntu-24.04.

2. Premier passage, sans cache

MesureGitHubFFxF
Attente avant le job docker2 s7 s
Attente avant le job go2 s30 s
Compilation de GitHub CLI97 s88 s
Tests24 s21 s
Job go complet152 s145 s
docker build12 s39 s
Job docker complet14 s49 s
Minutes facturées44
Prix du passage0,024 USD0,016 CAD (0,012 USD)

Sur le calcul, notre Xeon compile GitHub CLI 9 secondes plus vite et passe les tests 3 secondes plus tôt. Les deux services arrondissent chaque job à la minute supérieure : 4 minutes de part et d'autre, et une facture deux fois plus petite chez nous.

L'attente du job go vient du démarrage. Nous gardons des runners prêts selon le nombre de jobs que le compte lance en même temps ; ce dépôt n'en lançait qu'un à la fois jusque-là. Le job docker a pris le runner prêt, le job go a attendu qu'une machine neuve démarre : 30 secondes. Ces secondes ne sont pas facturées, la minute ne court qu'une fois le job commencé.

Le docker build, lui, est trois fois plus lent chez nous. Le temps part dans deux téléchargements : l'image node:22-slim (9,9 s contre 2,7 s) et les paquets de npm ci (9,8 s contre 3,7 s). Nos runners sortent en IPv6 ; Docker Hub n'a que l'IPv4, et les conteneurs d'un build sortent eux aussi en IPv4, si bien que ces téléchargements passent par une traduction d'adresses. Chez GitHub, ils restent dans un réseau voisin des registres. C'est aujourd'hui notre point faible, et la raison d'être du cache Docker, plus bas.

L'étape Set up runner (6 à 8 s dans nos jobs) branche le cache Docker du dépôt ; elle compte dans les minutes du job.

3. Deuxième passage, caches chauds

MesureGitHubFFxF
Restauration du cache Go25 s23 s
Compilation3 s3 s
Tests6 s6 s
Job go complet46 s50 s
docker build19 s43 s
Job docker complet24 s54 s
Minutes facturées22
Prix du passage0,012 USD0,008 CAD (0,006 USD)

Le cache de setup-go (461 Mo) se restaure aussi vite des deux côtés. Chez nous, il est gardé à Montréal, à côté des runners, sans rien changer au workflow, et facturé 0,30 CAD par Go et par mois. Avec ce cache, la compilation tombe à 3 secondes partout.

Côté Docker, GitHub repart d'une machine vide à chaque job, donc sans couche en cache : 19 secondes. Chez nous, le cache Docker aurait dû servir, et il n'a pas servi. La règle de l'époque l'explique : le cache Docker d'un dépôt était celui du dernier job réussi. Ici, le job go a fini après le job docker, et c'est son état qui a été gardé, alors qu'il n'avait pas touché à Docker. C'est corrigé depuis le 22 octobre.

4. Le cache Docker, quand il sert

Depuis le correctif, seul un job réussi qui a changé Docker met le cache à jour. Le runner relève l'état de Docker au début du job (images, cache de BuildKit, volumes nommés) et le compare à la fin. Le même workflow à deux jobs, relancé une seconde fois, donne ceci :

docker
FFxF: Docker cache of this repository attached (1.9 GB, saved 119 s ago), replaced only if this job changes Docker and succeeds.
#6 CACHED
#7 CACHED
#8 CACHED
docker build : 4 s (code 0)
FFxF: Docker changed by this job (images or build cache): if the job succeeded, its Docker state becomes the cache of this repository.
go
FFxF: Docker unchanged by this job: the Docker cache of this repository stays as it is.

Quatre secondes, contre 39 à 43 secondes sans cache chez nous et 12 à 19 secondes chez GitHub. Le job entier dure 14 secondes, dont 8 pour brancher le cache. L'image node:22-slim n'est plus téléchargée, et npm ci ne repasse que quand package-lock.json change. Le job go n'a pas touché à Docker : il laisse le cache tel quel, même s'il finit après.

Pour en profiter :

  • activez le cache Docker sur les dépôts qui construisent des images (console, Runners GitHub, carte Cache Docker), sans rien changer à vos workflows ;
  • la mise à jour se fait à la fin du job, en une dizaine de secondes. Un job qui démarre pendant ce temps, comme celui d'un needs:, l'attend (30 secondes au plus) ;
  • deux jobs qui changent Docker en même temps partent du même cache, et le dernier qui réussit l'emporte.

5. Quand c'est intéressant

À minutes égales, la facture est divisée par deux en 2 et 4 vCPU, et un peu plus en 8 vCPU (0,012 USD la minute contre 0,022 USD chez GitHub). Les forfaits de GitHub incluent un quota de minutes chaque mois ; les jobs qui tournent sur nos runners ne l'entament pas, et le gain commence dès que vos workflows le dépassent ou demandent plus de 2 vCPU.

Les jobs de calcul (compilation, tests) vont au moins aussi vite que chez GitHub. Les jobs qui téléchargent beaucoup depuis Docker Hub à chaque passage sont plus lents chez nous tant que le cache Docker ne les couvre pas.

6. Essayer

  • Dans la console, ouvrez Runners GitHub et cliquez sur Connecter GitHub : installez l'app FFxF Runners sur une organisation ou sur votre compte, et choisissez ses dépôts.
  • Remplacez ubuntu-latest par ffxf-2vcpu-ubuntu-2404 (ou 4vcpu, 8vcpu) dans un workflow.
  • Les minutes de chaque dépôt s'affichent dans la console et dans l'API. Chaque mois, 500 minutes de 2 vCPU sont offertes dès que le compte a fait un paiement.

Pendant la bêta, seuls les dépôts privés de GitHub.com sont servis, sous Linux x64. Les tailles, les prix et les limites sont sur la page des runners GitHub, et le détail technique dans le guide.

Trois couches empilées : le disque a grandi, la partition et le système de fichiers s'étirent à sa suite

Agrandir un disque Linux à chaud : ext4, XFS, LVM

Après un passage à une formule plus grande, df affiche souvent l'ancienne taille : le disque a grandi, pas la partition ni le système de fichiers. ext4, XFS et LVM, agrandis à chaud sur une machine de test, sorties réelles à l'appui.

Lire l'article 7 min de lecture

Des images disque empilées, dont une marquée d'un signal d'alerte

Images cloud de 28 systèmes : 8 pièges corrigés

28 systèmes, chacun tiré de l'image cloud de sa distribution, chacun avec ses habitudes. Les pièges qui nous ont coûté du temps, ce que vous voyez quand ils vous tombent dessus, et le correctif que portent maintenant nos images.

Lire l'article 7 min de lecture

Support & discussions

Questions techniques, retours d'incidents ou discussions d'infrastructure, l'équipe est présente sur Discord, Telegram, X, Instagram, Reddit et IRC.