API

Runners GitHub Actions

Vos jobs GitHub Actions sur une machine neuve à Montréal, payés à la minute : lier GitHub, étiquettes, facturation, suivi par l'API.

FFxF fait tourner vos jobs GitHub Actions à Montréal : chaque job a sa machine virtuelle, neuve, tirée d'une image qui suit ubuntu-24.04 de GitHub, et détruite à la fin du job. Vous payez les minutes de vos jobs, sur votre crédit ; le démarrage du runner ne compte jamais. Les runners GitHub sont en bêta, ouverte à tous les comptes. La page des runners GitHub compare nos prix à ceux de GitHub.

Lier GitHub

Dans la console, ouvrez Runners GitHub et cliquez sur Connecter GitHub. GitHub demande où installer l'app FFxF Runners (une organisation ou votre compte perso) et quels dépôts elle peut servir ; vous revenez dans la console avec ce compte déjà lié. Si l'app est déjà installée, L'app est déjà installée ? La lier fait la même chose sans réinstaller.

La console demande à GitHub qui vous êtes avant de lier quoi que ce soit. Une organisation se lie par la personne qui y a installé l'app, ou qui a changé ses dépôts en dernier (il faut pour cela en être propriétaire ou gestionnaire d'apps) ; un compte perso, par son titulaire. Une installation est liée à un seul compte FFxF, qui paie ses minutes. Délier arrête la prise des nouveaux jobs ; désinstallez l'app sur GitHub pour la retirer complètement.

Étiquettes

Une seule étiquette dans runs-on, celle de la taille voulue :

ÉtiquettevCPUMémoireLa minute
ffxf-2vcpu-ubuntu-240428 Go0,004 CAD (0,003 USD)
ffxf-4vcpu-ubuntu-2404416 Go0,008 CAD (0,006 USD)
ffxf-8vcpu-ubuntu-2404832 Go0,016 CAD (0,012 USD)
yaml
jobs:
  build:
    runs-on: ffxf-2vcpu-ubuntu-2404
    steps:
      - uses: actions/checkout@v4
      - run: make test

Un job qui demande une autre étiquette en plus (self-hosted, linux…) est refusé : nos runners ne portent que la leur, GitHub ne leur confierait jamais ce job. L'image a ce qu'a ubuntu-24.04 chez GitHub : le cache d'outils (actions/setup-python, setup-node, setup-java… trouvent leurs versions sur place), Docker sans sudo, les conteneurs de service, et sudo sans mot de passe. Le trafic sortant passe en IPv6 et en IPv4, conteneurs compris ; aucune connexion entrante n'atteint le runner.

Cache des actions

actions/cache, l'option cache des actions setup-* (setup-node, setup-python, setup-java…) et docker buildx avec un cache type=gha gardent leur cache à Montréal, à côté des runners, sans rien changer à vos workflows : le runner leur donne l'adresse du cache de FFxF au lieu de celle de GitHub. Les règles sont celles de GitHub : un job lit le cache de sa branche, puis celui de la branche de base ou par défaut, et n'écrit que dans celui de sa branche ; un dépôt ne voit jamais le cache d'un autre.

  • Prix : 0,30 CAD (0,21 USD) par Go et par mois, compté à l'heure sur ce qui est gardé, prélevé sur le crédit avec les minutes.
  • Limite : celle du dépôt chez GitHub (10 Go d'office), 50 Go au plus ; au-delà, les entrées les moins récemment utilisées partent.
  • Une entrée sans usage depuis 7 jours est effacée ; Vider, dans la console, efface tout le cache d'un dépôt.
  • Sans crédit pour payer l'heure, les caches du compte sont vidés.
  • Les jobs en conteneur (container:) se servent du cache de GitHub.

Cache Docker

Activé dépôt par dépôt dans la console (Runners GitHub, carte Cache Docker), il garde le /var/lib/docker du dernier job réussi du dépôt qui a changé Docker : images tirées, couches de docker build, builders et volumes de buildx. Le job suivant les retrouve, sans rien changer au workflow : un docker build ne refait que les couches qui ont changé.

  • Le disque du cache est branché au début du job, avant la première étape, en quelques secondes comptées dans ses minutes ; le journal du job le signale (Set up runner).
  • Seul un job réussi qui a changé Docker (images, cache de BuildKit, volumes nommés) met le cache à jour. Un job qui ne s'en sert pas, ou qui lance seulement des conteneurs d'images déjà là, le laisse tel quel : le journal le dit à la fin du job (Complete runner).
  • La mise à jour prend une dizaine de secondes après la fin du job. 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.
  • 100 Go par dépôt au plus ; seul ce qui reste à la fin du job compte, au prix du cache des actions (0,30 CAD par Go et par mois).
  • Un cache sans job depuis 7 jours est effacé ; Vider repart de l'image, Couper efface le cache et l'option.

Pendant la bêta

  • Dépôts privés seulement : le job d'un dépôt public est refusé.
  • Dans une organisation, les dépôts doivent pouvoir utiliser le groupe de runners Default, ce que GitHub permet d'office aux dépôts privés.
  • Linux x64 seulement : ni Windows, ni macOS, ni ARM, ni GPU, et pas de virtualisation imbriquée.
  • Jusqu'à 32 vCPU de jobs en même temps par compte ; au-delà, les jobs attendent leur tour dans la file de GitHub.

Facturation

Un job se facture du moment où GitHub le dit démarré au moment où il le dit terminé, à la minute entamée, au prorata des vCPU : un job de 3 min 10 s sur 4 vCPU coûte 4 × 0,008 = 0,032 CAD. Le crédit est prélevé pendant le job ; la fin du job règle le reste. Chaque mois, les 500 premières minutes de 2 vCPU (250 sur 4 vCPU, 125 sur 8) sont offertes dès que le compte a fait un paiement, et passent avant le crédit.

  • Pas assez de crédit pour les cinq premières minutes d'un job : il attend dans la file de GitHub, sans runner, et part dans la minute qui suit une recharge. GitHub abandonne un job resté 24 heures en file.
  • Crédit épuisé pendant un job : le job est arrêté, GitHub l'affiche en échec.
  • Budget du mois dépassé de 20 % : les nouveaux jobs attendent qu'il soit relevé ; ceux qui tournent vont au bout.

La console prévient le compte par courriel quand un job est arrêté ou retenu, au plus une fois par jour. Les minutes figurent sur le relevé de consommation et dans votre budget, comme tout autre service.

Suivre vos jobs par l'API

bash
curl -s https://api.ffxf.net/v1/runners -H "Authorization: Bearer $FFXF_TOKEN"

curl -s "https://api.ffxf.net/v1/runners/jobs?status=queued" -H "Authorization: Bearer $FFXF_TOKEN"
json
{ "data": [ { "id": 812, "repository": "acme/app", "workflow": "CI", "job": "build", "label": "ffxf-2vcpu-ubuntu-2404",
    "status": "queued", "waiting_reason": "credit", "minutes": null, "amount": null,
    "url": "https://github.com/acme/app/actions/runs/12345678901" } ],
  "meta": { "next_cursor": null, "has_more": false } }

Les deux appels demandent la portée billing.read. GET /runners rend les étiquettes et leur prix, la concurrence du compte, les organisations et comptes liés, les minutes du mois par dépôt et le cache de chaque dépôt (octets, entrées, dernier usage). GET /runners/jobs liste les jobs du plus récent au plus ancien, filtrés par repository ou status (queued, running, succeeded, failed, cancelled, refused). Dans GET /usage, les minutes des runners portent "kind": "github_runners", une ligne par heure. Lier GitHub passe par GitHub dans un navigateur : cela reste dans la console.

Support & discussions

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