Aller au contenu principal

Runners CI

fremforge fournit des runners hébergés, inclus dans chaque formule facturée par utilisateur, et prend en charge les runners fournis par vous (BYO) pour les équipes qui ont besoin d’un hébergement sur site, de matériel spécifique ou d’un placement réseau particulier. Les deux types de runners exécutent des workflows Forgejo Actions avec la même syntaxe YAML que GitHub Actions.

Runners hébergés

Les runners hébergés sont des machines virtuelles par commit sur T Cloud Public, dans la région eu-de (Biere/Magdebourg). Une VM est provisionnée à partir d’une image debian personnalisée avec Docker préinstallé, exécute les jobs d’un commit d’un dépôt, puis est détruite une fois les jobs de ce commit terminés. Rien ne persiste d’un commit à l’autre.

Libellés disponibles

LibelléOS / architectureRemarques
fremforgedebian 13 (« trixie », glibc), x86_64Libellé par défaut des runners hébergés. À utiliser pour presque tous les workflows. Voir Contenu de l’image de runner pour ce qui est préinstallé.
linux/amd64debian 13 (« trixie », glibc), x86_64Synonyme de fremforge. Cible la même image.
dind-privilegeddebian 13, x86_64, imbrication KVMÀ ajouter à côté de fremforge (runs-on: [fremforge, dind-privileged]) pour les workflows qui ont besoin d’invités KVM imbriqués : clusters kind, fonctionnalités de testcontainers nécessitant des capacités de création d’espaces de noms. Planifié sur un type de VM dédié avec la virtualisation imbriquée activée. Même isolation par VM et par commit.

Faites référence à un libellé dans votre workflow :

jobs:
  build:
    runs-on: fremforge

Les builds de conteneurs fonctionnent de deux façons sans configuration supplémentaire ; voir Contenu de l’image de runner § Builds de conteneurs ci-dessous pour le détail :

  • Docker natif (par défaut) : docker build, docker compose, docker pull fonctionnent tout simplement. Le démon Docker tourne nativement sur la VM (pas de sidecar Docker-in-Docker) : docker se comporte donc comme sur un runner hébergé par GitHub. Convient à 90 % des workflows.
  • kaniko : sans démon, démarrage à froid plus rapide, meilleur cache des couches avec les registres distants. À utiliser quand vous n’avez pas besoin des fonctionnalités propres à BuildKit.
jobs:
  build-image:
    runs-on: fremforge
    steps:
      - uses: actions/checkout@v4
      - run: docker build -t registry.example.com/$GITHUB_REPOSITORY:$GITHUB_SHA .
      - run: docker push registry.example.com/$GITHUB_REPOSITORY:$GITHUB_SHA 2>&1 | stdbuf -oL tr '\r' '\n' | grep -vE '^(Waiting|)$'

Les runners hébergés ARM64 et d’autres variantes d’OS (Ubuntu, Fedora, …) figurent dans la feuille de route (voir le changelog) ; fremforge ne cible aujourd’hui que Linux x86_64. En attendant, les runners fournis par vous (voir plus bas) sont la solution pour les workflows ARM64 ou non Linux.

Modèle d’isolation

Les jobs s’exécutent sur des machines virtuelles dédiées, avec leur propre noyau. La plateforme surveille la file d’attente de Forgejo Actions et démarre une VM neuve pour un job en attente. Un démarrage à froid prend environ 40 secondes avant la première étape du job ; il n’y a pas de pool de VM prédémarrées.

Un commit, un domaine de confiance. Une VM n’exécute jamais que des jobs du commit et du dépôt pour lesquels elle a été démarrée. Quand un job se termine, la VM attend jusqu’à 60 secondes un autre job du même commit, dans n’importe quel workflow, et l’exécute sans nouveau démarrage (environ 5 secondes pour démarrer). Ensuite, elle s’éteint et est supprimée. Aucune VM n’exécute de jobs de deux commits, de deux dépôts ou de deux organisations : considérez donc tous les jobs d’un même commit comme un seul domaine de confiance. Les identifiants connus de la plateforme (connexions Docker et npm, fichiers d’identifiants usuels) sont réinitialisés entre les jobs, mais les caches d’outils et les images récupérées restent sur la VM. Voir Modèle de sécurité des runners hébergés pour la conception complète.

Dimensionner les jobs pour les runners hébergés

Chaque VM neuve coûte environ 40 secondes de démarrage avant votre première étape, et souvent les 60 secondes d’attente après la dernière. Un job qui fait 15 secondes de travail occupe donc une VM pendant environ deux minutes. Par conséquent :

  • Ne donnez une VM propre à un job que si son travail prend environ 2 minutes ou plus. Les vérifications plus courtes (lint, petite suite de tests, script de garde) sont moins coûteuses et plus rapides sous forme d’étapes supplémentaires dans un job existant.
  • Parallélisez les travaux longs et indépendants (fragments de tests, builds d’images, suites de bout en bout) sur plusieurs jobs. C’est à cela que sert la concurrence.
  • Parallélisez les travaux courts au sein d’un seul job plutôt que sur plusieurs jobs, par exemple plusieurs exécutions de tofu plan dans des processus d’arrière-plan d’une même étape. Elles attendent surtout des API, pas le CPU.
  • Les chaînes réutilisent les VM automatiquement. Un job needs: qui devient prêt pendant que la VM de son prédécesseur attend encore (dans les 60 secondes) s’exécute sur cette VM sans démarrage. Un large éventail de jobs qui démarrent tous en même temps ne peut rien réutiliser : chacun a besoin de sa propre VM.
  • Restez dans votre concurrence. Une matrice plus large que la part garantie de votre organisation s’exécute par vagues, et la dernière vague attend qu’un job entier se termine. Dimensionnez les fragments pour qu’une exécution tienne en une seule vague.

Mémoire

Une VM de runner hébergé dispose de 4 Gio de mémoire, sans swap (2 vCPU). Il n’existe pas aujourd’hui de taille de runner hébergé plus grande.

Un job qui manque de mémoire échoue en une minute environ. Lorsque la mémoire disponible descend sous environ 4 % (environ 130 Mio), le runner arrête le plus gros processus du job, en privilégiant les outils de build comme node, tsc, java et les workers de vitest. Il envoie d’abord SIGTERM, puis SIGKILL si la mémoire continue de baisser. L’étape échoue avec le code de sortie 143 ou 137, et le journal de l’étape en donne la raison :

earlyoom: killed node (pid 4242) because the runner VM ran out of memory. ...

Le runner lui-même n’est jamais le processus arrêté : le résultat et les journaux du job sont donc toujours remontés. Avant ce changement, un job qui dépassait la capacité de la VM pouvait se bloquer en silence jusqu’à son timeout-minutes.

Si vous voyez cette ligne, réduisez le pic de mémoire du job :

  • Répartissez le travail sur plusieurs jobs. Lancer un gros build à côté de ses tests d’intégration, ou un docker build à côté de conteneurs de test, additionne les deux pics sur une même VM.
  • Bornez la mémoire de l’outil. Par exemple NODE_OPTIONS=--max-old-space-size=2048 pour Node, --checkers 1 et GOMEMLIMIT pour TypeScript 7 (tsc écrit en Go), -Xmx pour Java, moins de workers de test (--maxWorkers / --pool-options).
  • Traitez en flux plutôt que de tout charger. Pour l’analyse de grandes images, voir Analyser de grandes images avec Trivy.

Si un job ne peut pas tenir dans 4 Gio, contactez support@frem.sh, ou exécutez-le sur un runner fourni par vous dimensionné en conséquence.

Minutes incluses et concurrence

ÉlémentValeur
Minutes incluses1 000 minutes de runner par utilisateur et par mois, mutualisées au sein de l’organisation
Concurrence2 jobs simultanés garantis par utilisateur (au moins 10, au plus 60) ; jusqu’à 60 tant que la plateforme dispose de capacité libre. Essai : 2.
Durée maximale par job60 min par défaut (via --timeout) ; plafond absolu de 6 h imposé sur la VM. Un timeout-minutes: au niveau du job dans votre YAML de workflow impose des valeurs plus courtes ; le timeout-minutes: au niveau de l’étape est déjà respecté.
Facturation à la minute dans le forfaitAucune, inclus dans la formule forfaitaire à 30 € par utilisateur
Quand le forfait est épuiséLes nouveaux jobs sont refusés avec une vérification de statut de commit fremforge/runner-minutes-cap explicite ; les jobs en cours se terminent normalement. La facturation du dépassement est sur activation, voir ci-dessous.
Réinitialisation des minutesLe 1er de chaque mois ; les minutes non utilisées ne sont pas reportées

Les jobs qui dépassent la limite de votre organisation attendent dans la file au lieu d’échouer. Contactez support@frem.sh si vous avez besoin d’une part garantie plus élevée.

Facturation du dépassement (sur activation) : par défaut, les nouveaux jobs sont mis en file d’attente lorsque le forfait est épuisé. Les propriétaires de l’organisation peuvent activer le dépassement facturé à l’usage dans Administration de l’organisation → Facturation → Consommation de minutes runner. Une fois activé, les minutes au-delà du forfait sont facturées 0,01 €/min sur la facture suivante. Le dépassement peut être désactivé à tout moment depuis la même page.

Tableau de bord d’utilisation

Suivez la consommation de minutes de runner dans Administration de l’organisation → Facturation → Consommation de minutes runner.

Le tableau de bord d’utilisation affiche :

VueContenu
Récapitulatif mensuelTotal des minutes utilisées sur la période de facturation en cours, comparé au forfait inclus (1 000 min × nombre d’utilisateurs)
Détail par dépôtMinutes consommées par chaque dépôt, triables par utilisation
Détail par workflowMinutes consommées par chaque fichier de workflow au sein d’un dépôt
ChronologieGraphique de l’utilisation quotidienne pour la période de facturation en cours et la précédente

Les minutes sont comptées du début à la fin du job, arrondies à la seconde supérieure. Le temps d’attente dans la file (en attente d’un runner) n’est pas compté.

La période mensuelle se réinitialise le 1er de chaque mois (UTC). Les minutes non utilisées ne sont pas reportées.

Les minutes des runners fournis par vous sont suivies séparément dans le même tableau de bord et ne sont pas décomptées du forfait hébergé.

Les seuils d’alerte d’utilisation réglables par le client ne sont pas encore proposés : fremforge envoie un e-mail d’avertissement par défaut lorsque l’organisation atteint 80 % du forfait mensuel. Contactez support@frem.sh pour ajuster le seuil.

Contenu de l’image de runner

L’image du runner hébergé est reconstruite chaque semaine (lundi 06:00 UTC) à partir des versions amont des outils suivies par Renovate. Chaque téléchargement effectué au moment du build est épinglé par sha256 (le build échoue en cas de dérive). Un contrôle des CVE par Trivy s’exécute au moment du build : toute image présentant des résultats HIGH ou CRITICAL est bloquée jusqu’à sa correction.

Avant qu’une image reconstruite soit mise en service sur la flotte de runners, elle est de nouveau vérifiée par rapport aux listes de vulnérabilités activement exploitées (ENISA EUVD et CISA KEV). Une image contenant une CVE activement exploitée pour laquelle un correctif existe n’est pas déployée, quelle que soit sa sévérité, sauf si une exception validée d’au plus 30 jours couvre cette CVE. Les runners continuent d’utiliser l’image précédente jusqu’à ce qu’une image corrigée soit construite.

Modèle en deux couches, toutes deux résidant dans l’UE :

  • Couche système (~300 Mo) : base debian + outils système en une seule version (Node 24 LTS, outils de compilation essentiels, scanners, outils IaC et CLI cloud, navigateurs, clients de bases de données). Fait partie du disque de démarrage de la VM ; aucun téléchargement par job.
  • Couche hostedtoolcache (~7 Go) : chaînes d’outils des langages en plusieurs versions (Node, Go, Python, .NET, Java, Ruby) + Android SDK + Miniconda3 + R (depuis le 2026-06-06). Intégrée au même disque de démarrage de la VM, dans /opt/hostedtoolcache. Les actions setup-* s’y résolvent, sans téléchargement par job.

Comment nous offrons une couverture complète en ~7 Go au total quand l’ubuntu-latest de GitHub fait ~50 Go : voir la comparaison de taille ci-dessous.

Préinstallé dans la couche système :

CatégorieContenu
Basedebian 13 (« trixie ») slim (glibc, nécessaire aux binaires à parité ubuntu des actions setup-*)
Shell + GNU coreutilsbash, coreutils, util-linux, findutils, grep, sed, gawk, diffutils, tzdata, locale
Réseau + cryptographieca-certificates, curl, wget, openssl, openssh-client, gnupg
Gestion de versionsgit, git-lfs (initialisé pour tout le système), tea (CLI Forgejo)
Archivestar, gzip, xz, bzip2, unzip, zip, zstd
Outils de compilation essentielsbuild-essential (gcc + make), clang, lld, ninja, cmake, pkg-config, autoconf, automake, libtool
Environnement JS (système)Node 24 LTS + npm + pnpm et yarn gérés par corepack
Autres langages (système)Rust (rustup stable), PowerShell 7, PHP 8.3 + Composer
Build JVMMaven 3.9, Gradle 9.8 (les SDK Java proviennent du hostedtoolcache)
IaCOpenTofu, Bicep, Pulumi, Ansible (via pipx), AWS SAM CLI
CLI cloudAWS CLI v2, Azure CLI, Google Cloud CLI (gcloud + gsutil + bq)
ConteneursCLI Docker + démon Docker natif (pas de sidecar DinD ; voir Builds de conteneurs), kaniko, skopeo, kind
K8skubectl, helm, kustomize
Sécurité + lintgitleaks, trivy, osv-scanner, cosign, syft, opengrep, scorecard, checkov, cfn-lint, actionlint, hadolint, shellcheck, shfmt, yamllint
Manipulation de donnéesjq, yq
Clients de bases de donnéespostgresql-client, default-mysql-client, sqlite3
Navigateurs + tests de bout en boutChromium + chromedriver, Firefox ESR + geckodriver, Selenium Server
Inittini en PID 1 (gestion propre des signaux et récupération des processus zombies)
Exécuteurforgejo-runner (act_runner amont, épinglé) exécute nativement les étapes Forgejo Actions sur la VM

Préinstallé dans le hostedtoolcache (résolu par les actions setup-*, sans téléchargement par job) :

OutilVersions / contenu
Node.js26.x, 24.x, 22.x (LTS)
Go1.27.x, 1.26.x
Python3.14, 3.13, 3.12
SDK .NET10.0, 8.0
Java (Temurin)25, 21, 17
Ruby4.0.x, 3.4.x, 3.3.x
Android SDKcmdline-tools + plateforme 34 + build-tools 34.0.0 + platform-tools ; ANDROID_HOME=/usr/local/lib/android/sdk ; plateformes / NDK supplémentaires par job via setup-android@v3
Miniconda3conda + python 3.11 ; CONDA=/opt/hostedtoolcache/Miniconda3/latest/x64 ; environnements créés par job via setup-miniconda@v3
R (CRAN)r-base + r-base-dev 4.3.x ; résolu par r-lib/actions/setup-r@v2 ; paquets CRAN installés par job

La liste de référence des versions, avec les versions exactes résolues, le condensat de l’image, le résumé de l’analyse Trivy et le SBOM CycloneDX, est publiée à chaque reconstruction hebdomadaire ; consultez la référence de l’image de runner pour la pile d’outils actuelle.

Builds de conteneurs : Docker natif ou kaniko

Deux voies, à choisir selon la charge de travail :

Docker natif (par défaut) : la VM est livrée avec le démon Docker installé et en cours d’exécution sur l’hôte. Votre CLI docker communique avec lui via le socket local standard, sans indirection par DOCKER_HOST ni sidecar. Fonctionne pour docker build, docker compose, docker pull, les builds multi-étapes et les fonctionnalités BuildKit. Parité directe avec le docker des runners hébergés par GitHub.

- run: docker build -t myapp:${{ github.sha }} .
- run: docker push myapp:${{ github.sha }} 2>&1 | stdbuf -oL tr '\r' '\n' | grep -vE '^(Waiting|)$'

Analyser de grandes images avec Trivy

trivy image <ref> (via le démon) conserve en mémoire les métadonnées des couches de toute l’image pendant qu’il parcourt le système de fichiers : avec des images de plusieurs Go, la consommation peut dépasser largement la limite de mémoire de la VM du runner et provoquer un arrêt pour manque de mémoire en pleine analyse. La méthode fiable, quelle que soit la taille de l’image, consiste à transmettre l’image en flux via docker save :

- run: docker build -t myapp:${{ github.sha }} .
- run: |
    docker save myapp:${{ github.sha }} | trivy image \
      --severity HIGH,CRITICAL --ignore-unfixed \
      --scanners vuln --pkg-types os \
      --offline-scan --no-progress --quiet \
      --input -

Pourquoi cela fonctionne : docker save lit les couches depuis le disque et transmet l’archive tar en flux sur l’entrée standard de trivy, une couche à la fois. Trivy analyse dans chaque couche les métadonnées des paquets de l’OS (quelques dizaines de Ko par couche) et les libère avant la suivante. Le pic de RSS cumulé reste autour de 500 Mo quelle que soit la taille totale de l’image : l’analyse tient donc largement dans le budget mémoire de la VM du runner. Placer GOGC=10 devant trivy (par ex. GOGC=10 trivy ...) resserre encore le tas si vous approchez de la limite.

Le filtre tr '\r' '\n' sur docker push est recommandé : Docker écrit la progression de l’envoi des couches avec des retours chariot qui écrasent la ligne, et le journal d’étape de Forgejo Actions les traite comme une seule ligne qui grandit sans cesse et la tronque sans prévenir. Sans le filtre, un push qui se bloque ou échoue en plein envoi n’affiche que <layer>: Preparing dans le journal, sans détail sur l’échec : au moment où l’étape expire, l’erreur réelle a été écrasée. Passer par tr transforme chaque mise à jour de progression en ligne distincte, capturée intégralement, et grep -vE '^(Waiting|)$' supprime les lignes vides ou d’attente. Le débit d’envoi des couches n’est pas affecté.

Les registres des clients (ghcr.io, dockerhub, quay.io, les vôtres) sont joignables via la sortie réseau des runners ; le proxy applique un délai de 30 min par requête pour que les PUT de couches de plusieurs Go aboutissent proprement. Budget de taille d’image : 50 Go par build (la limite du disque de travail de la VM) ; ouvrez un ticket si vous avez besoin de plus.

kaniko : outil de build OCI sans démon et sans privilèges root. Démarrage à froid plus rapide que le démon Docker complet, meilleure gestion du cache des couches avec les registres distants. À utiliser quand le build n’a pas besoin des fonctionnalités propres à BuildKit.

- run: |
    /usr/local/bin/kaniko \
      --context=$GITHUB_WORKSPACE \
      --dockerfile=Dockerfile \
      --destination=registry.example.com/$GITHUB_REPOSITORY:$GITHUB_SHA

Pour les charges de travail kind / testcontainers qui ont besoin d’invités KVM imbriqués, ajoutez le libellé dind-privileged à runs-on. fremforge dirige ces jobs vers un type de VM avec la virtualisation imbriquée activée.

Comparaison de taille avec les runners hébergés par GitHub

L’ubuntu-latest de GitHub fait ~50 Go parce qu’il intègre :

  • Plusieurs versions par langage : 3 séries récentes pour Node, Python, Java et Ruby ; 2 pour Go et .NET (~3 Go au total). Le tableau ci-dessus est l’ensemble de référence.
  • Android SDK + NDK (~10 Go sur les runners hébergés par GitHub) : nous intégrons le SDK de base (plateforme 34 + build-tools + platform-tools, ~3 Go) ; les niveaux d’API supplémentaires, le NDK et les émulateurs s’installent par job via setup-android@v3 (sans nouveau téléchargement de ce qui est intégré).
  • Des images de conteneurs de services Docker prérécupérées (postgres, mysql, mongo, redis, mssql, ~5 Go) : non intégrées ; un docker pull les récupère depuis Docker Hub, ou via le proxy de dépendances de votre organisation (voir caches de paquets).
  • Le navigateur Microsoft Edge : non intégré (Chromium utilise le même moteur pour les tests headless en CI).
  • Mono / Julia / Swift / Haskell / Lua / Crystal / Nim / Elixir : non intégrés (spécialisés, à installer par job via setup-* ou apt).
  • Plusieurs versions de GCC et d’anciennes chaînes d’outils conservées pour la compatibilité : nous livrons un seul ensemble à jour.

Il ne nous manque aucun des outils qu’utilise un workflow courant : tous les langages courants, toutes les grandes CLI cloud, tous les scanners courants, les deux principaux navigateurs, Docker (natif, et root via le libellé dind-privileged), Android (SDK de base) et la data science (Miniconda3 + R). iOS / Xcode est incompatible avec Linux et suivi séparément ; les langages spécialisés (Julia/Swift/Haskell/Mono) s’installent par job. Dites-nous si votre équipe a besoin d’un outil que nous n’intégrons pas, et nous l’évaluerons pour la prochaine reconstruction hebdomadaire de l’image.

Pour le détail complet outil par outil, voir docs.frem.sh/build/actions/runner-image/.

Runners fournis par vous (BYO)

Enregistrez vos propres runners sur n’importe quelle organisation fremforge (serveurs sur site, VM cloud, Mac mini, Raspberry Pi). Les minutes des runners fournis par vous ne sont pas décomptées du forfait hébergé.

Enregistrement

  1. Dans les paramètres Forgejo de l’organisation, allez dans Paramètres → Actions → Exécuteurs → Créer un nouvel exécuteur (frem.sh/org/<org>/settings/actions/runners).
  2. Copiez le jeton d’enregistrement.
  3. Téléchargez le binaire du runner Forgejo. La version stable actuelle est publiée sur code.forgejo.org/forgejo/runner/releases ; épinglez un tag récent lors de l’installation :
# Linux x86_64 — replace <version> with the tag from the releases page (e.g. v6.4.0)
curl -sSL https://code.forgejo.org/forgejo/runner/releases/download/<version>/forgejo-runner-<version>-linux-amd64 \
  -o forgejo-runner && chmod +x forgejo-runner

# macOS arm64
curl -sSL https://code.forgejo.org/forgejo/runner/releases/download/<version>/forgejo-runner-<version>-darwin-arm64 \
  -o forgejo-runner && chmod +x forgejo-runner

fremforge suit les versions actuelles de Forgejo ; les runners utilisant des binaires plus anciens continuent de fonctionner, mais devraient être mis à jour au cours d’un cycle de versions pour bénéficier des correctifs de CVE.

  1. Enregistrez le runner :
./forgejo-runner register \
  --instance https://frem.sh \
  --token <registration-token> \
  --name my-runner \
  --labels linux,self-hosted,my-custom-label
  1. Démarrez le runner :
./forgejo-runner daemon

Plateformes prises en charge

PlateformeArchitectures
Linuxx86_64, ARM64, ARMv7
macOSx86_64, Apple Silicon (ARM64)
Windowsx86_64

Libellés personnalisés

Les libellés attribués à l’enregistrement sont ceux que vous indiquez dans runs-on: :

jobs:
  deploy:
    runs-on: [self-hosted, my-custom-label]

Plusieurs libellés dans une liste signifient « trouver un runner qui possède TOUS ces libellés ». Le libellé self-hosted est conventionnel. Incluez-le pour éviter qu’un job destiné à un runner fourni par vous parte par erreur vers un runner hébergé.

N’utilisez pas les libellés réservés. Les libellés fremforge et linux/amd64 dirigent vers notre pool de runners hébergés (les anciens alias fremforge-cci et cci sont obsolètes et dirigent au même endroit). Choisissez des libellés distincts pour vos runners (par ex. self-hosted, on-prem, my-team-runner) afin que les workflows puissent les désigner sans ambiguïté.

Exigences réseau pour l’hôte du runner

Le binaire du runner ouvre des connexions HTTPS à interrogation longue vers https://frem.sh et clone les dépôts en HTTPS. Du point de vue de l’hôte, les exigences de connectivité sont les suivantes :

DestinationPortRôle
frem.sh443Protocole de runner Connect-RPC (/api/actions/runner.v1.RunnerService/*), API d’exécution Actions, git clone en HTTPS
*.frem.sh443Réservé aux sous-domaines des organisations, aux téléchargements de pièces jointes et de fichiers bruts
Miroir d’actions (indirect)443Lorsqu’un workflow utilise uses: actions/<name>@<ref>, le runner récupère l’action depuis frem.sh/<owner>/<repo>, soit le même hôte que ci-dessus
Cibles des workflows du clientvariableToutes les destinations que visent vos workflows (cibles de déploiement, registres de paquets, etc.)

Aucune connectivité entrante n’est nécessaire : le runner initie toutes les connexions en sortie. Un runner derrière un NAT ou un pare-feu fonctionne très bien, tant qu’il peut joindre frem.sh:443.

Responsabilité en matière de sécurité et d’isolation

Pour les runners hébergés, fremforge fournit une isolation au niveau du noyau entre les commits et entre les clients (chaque commit s’exécute dans une VM ECS éphémère neuve ; les jobs d’un même commit peuvent la partager). Pour les runners fournis par vous, l’isolation relève de votre responsabilité. Un runner auto-hébergé qui traite des workflows de plusieurs dépôts partage son état entre les jobs, sauf si vous limitez chaque runner à un seul dépôt ou à une seule organisation.

Si vous exécutez des workflows de plusieurs équipes ou de plusieurs domaines de confiance, traitez votre runner comme on traite les runners auto-hébergés de GitHub Actions :

  • Un runner par dépôt (ou par frontière de confiance) lorsque les secrets sont sensibles.
  • N’enregistrez pas de runner sur un dépôt public : toute personne ayant le droit de fusionner pourrait introduire une modification de workflow qui exécute du code arbitraire sur l’hôte de votre runner.
  • Traitez l’hôte du runner comme un hôte de production : durcissez l’OS, maintenez le binaire du runner à jour, et faites passer sa sortie réseau par vos propres contrôles SSRF / de sortie.

Le proxy sortant SSRF de fremforge ne s’applique PAS aux runners fournis par vous, uniquement aux runners hébergés. La politique réseau de votre runner est celle que vous configurez sur l’hôte.

Trafic sortant et réseau

RègleDétail
HTTP/HTTPS sortantAutorisé (ports 80 et 443)
Autres ports sortantsBloqués par défaut
Connexions entrantesBloquées : les runners n’acceptent pas de connexions entrantes
Point de terminaison de métadonnées de T Cloud Public (169.254.x.x)Bloqué par le proxy sortant SSRF
Plages privées RFC-1918Bloquées par le proxy sortant SSRF

Liste d’autorisation de sortie au niveau de l’organisation : pour autoriser l’accès sortant à d’autres CIDR ou ports depuis les jobs des runners, contactez support@frem.sh. Les règles de sortie sont configurées au niveau de la plateforme.

Le proxy SSRF est un socle de la plateforme. Il ne peut pas être désactivé. Il empêche les jobs des runners d’atteindre les métadonnées d’instance de T Cloud Public ou l’infrastructure interne.

Secrets dans les jobs

Les secrets sont injectés sous forme de variables d’environnement et masqués dans les journaux des jobs. Toute ligne de journal contenant la valeur d’un secret est remplacée par ***.

Syntaxe de référence :

steps:
  - name: Deploy
    env:
      API_KEY: ${{ secrets.MY_API_KEY }}
    run: ./deploy.sh

Portées des secrets

PortéeOù la définirDisponible pour
Secrets d’organisationAdministration de l’organisation → SecretsTous les dépôts de l’organisation
Secrets de dépôtDépôt → Paramètres → Actions → SecretsCe dépôt uniquement
Secrets d’environnementAdministration de l’organisation → Environnements → <env> → Secrets d’environnementLes jobs qui font référence à cet environnement nommé

Les secrets d’environnement exigent que le job déclare un environnement :

jobs:
  deploy:
    runs-on: fremforge
    environment: production
    steps:
      - run: echo ${{ secrets.PROD_API_KEY }}

Pour les identifiants des fournisseurs cloud, préférez la fédération de jetons OIDC aux secrets à longue durée de vie. Aucun secret à stocker, aucun secret à faire tourner.

Dépannage

Une étape échoue avec earlyoom: killed <process> ... ran out of memory.

Le job a utilisé plus que les 4 Gio de mémoire de la VM du runner : le runner a donc arrêté son plus gros processus au lieu de laisser la VM se bloquer. Voir Mémoire pour réduire le pic du job.

Le job reste bloqué dans la file d’attente.

La cause la plus fréquente est l’atteinte du plafond de concurrence par organisation (2 jobs simultanés garantis par utilisateur, au moins 10 et au plus 60 ; voir Minutes incluses et concurrence). Consultez Administration de l’organisation → Facturation → Consommation de minutes runner pour connaître le nombre de jobs actifs. Si vous êtes au plafond, attendez la fin d’un job en cours, ou contactez support@frem.sh pour une augmentation Enterprise-on-Demand.

La commande docker fonctionne, mais une opération privilégiée échoue (par ex. création d’un cluster kind avec imbrication KVM).

La VM par défaut runs-on: fremforge exécute Docker nativement avec les paramètres par défaut d’un utilisateur sans privilèges root : docker build / docker compose / docker pull fonctionnent d’emblée, mais pas les opérations qui nécessitent des capacités supplémentaires (imbrication KVM, accès brut à /dev pour un invité imbriqué, certains modes réseau des clusters kind). Ajoutez le libellé dind-privileged à runs-on (runs-on: [fremforge, dind-privileged]) : fremforge dirige alors le job vers un type de VM avec la virtualisation imbriquée activée. Même isolation par VM et par commit ; même image ; seulement des capacités élevées.

Pour une simple copie / ré-étiquetage d’images entre registres (sans build), le skopeo préinstallé fonctionne sans avoir besoin du démon Docker.

Le secret est masqué dans les journaux, mais l’étape se comporte comme s’il était vide.

Le secret existe dans l’environnement d’exécution (le masquage le confirme), mais la valeur n’est pas définie dans la bonne portée. Vérifiez :

  1. Le secret est-il défini au niveau de l’organisation, du dépôt ou de l’environnement ?
  2. S’il s’agit d’un secret d’environnement, le job déclare-t-il un environment: <name> correspondant à l’environnement du secret ?
  3. Le nom du secret est-il orthographié exactement (sensible à la casse) ?

L’interface des secrets de la portée concernée affiche le nom du secret et la date de sa dernière mise à jour. Utilisez-la pour confirmer que le secret existe avant d’examiner le workflow.

Voir aussi