Runner group, larger runner, scale set e rete

Quando Actions smette di essere una cosa di pochi repository e diventa infrastruttura condivisa, la domanda non è più quale runner usare, ma chi può usare quale flotta e con quale capacità di crescere. Le leve sono tre: i runner group per l’accesso, le label per l’instradamento dei job, l’autoscaling per la capacità. La rete arriva subito dopo, perché una pipeline che deve raggiungere un database interno pone un problema di indirizzi che i runner standard non risolvono.

Runner group: il confine di accesso

Un runner group è un confine di sicurezza che raccoglie runner self-hosted e larger runner e stabilisce quali repository possono eseguirvi job. Ogni organizzazione ne ha uno predefinito, il default group: un runner registrato senza specificare il gruppo finisce lì. Un runner appartiene a un solo gruppo alla volta, ma lo si può spostare da Settings > Actions > Runners agendo sul menu Runner group.

L’asimmetria dei default fra i due livelli è esattamente il dettaglio che l’esame verifica. Un gruppo creato a livello di organizzazione nasce aperto: per impostazione predefinita tutti i repository dell’organizzazione hanno accesso ai runner group di quel livello, e sta all’owner restringere il perimetro a una lista esplicita. Un gruppo creato a livello di enterprise nasce chiuso: per impostazione predefinita le organizzazioni non hanno accesso ai gruppi enterprise, e il permesso va concesso a mano. Chi memorizza solo “i gruppi servono a limitare” sbaglia le domande che chiedono che cosa accade subito dopo la creazione.

Una terza regola riguarda i self-hosted: di norma solo i repository privati possono usare i runner di un gruppo. L’impostazione è sovrascrivibile, ma la documentazione lo sconsiglia, perché il fork di un repository pubblico può far eseguire codice ostile sulla tua macchina tramite una pull request.

Label, group e la sintassi di runs-on

L’accesso dice chi può; le label dicono dove finisce il singolo job. I runner self-hosted portano label di default come sistema operativo e architettura, più quelle personalizzate assegnate con il parametro labels in fase di configurazione; sono case-insensitive e quelle non più usate vengono ripulite da sole. In runs-on le label elencate valgono in AND: il runner deve averle tutte. I larger runner ricevono in automatico una label uguale al proprio nome, quindi conviene chiamarli in modo parlante, ad esempio ubuntu-24.04-16core.

Quando serve sia il perimetro sia l’hardware si combinano le chiavi group e labels, e il runner deve soddisfare entrambi i requisiti per essere eleggibile.

jobs:
  build:
    runs-on:
      group: ubuntu-runners
      labels: ubuntu-24.04-16core

Confusione tipica: group da solo manda il job a un runner qualunque del gruppo, labels da sola ignora il perimetro. Se l’amministratore ha disabilitato i runner standard ospitati da GitHub, resta solo l’instradamento per gruppo.

Scalare: larger runner e runner scale set

I larger runner sono macchine virtuali gestite da GitHub con più risorse di quelle standard. Si creano da Settings > Actions > Runners con New runner, poi New GitHub-hosted runner, scegliendo piattaforma (Linux x64, Linux ARM64, Windows x64), immagine GitHub, partner o custom, taglia, comprese quelle nella scheda GPU-powered, e infine il runner group. L’autoscaling si governa con Maximum concurrency, che è il tetto di job paralleli. Nota utile per il dominio enterprise: i larger runner non attingono ai minuti inclusi nei repository privati.

Sul versante self-hosted l’autoscaling si ottiene con i runner scale set e Actions Runner Controller (ARC) su Kubernetes. Uno scale set è un insieme di runner omogenei, e i suoi due vincoli sono materia d’esame: può avere una sola label e appartenere a un solo runner group alla volta. Non esiste quindi la combinazione di label a cui sei abituato con i runner classici: il job si instrada mettendo il nome dello scale set in runs-on. ARC si installa con due chart Helm, gha-runner-scale-set-controller per l’operatore e gha-runner-scale-set per la flotta; l’INSTALLATION_NAME diventa il valore di runs-on, runnerScaleSetName deve essere unico dentro il gruppo, minRunners e maxRunners definiscono la forbice, containerMode sceglie fra dind e kubernetes per i container job, runnerGroup collega il tutto al perimetro di accesso. Per l’autenticazione la GitHub App è preferita al personal access token.

Rete privata, allow list e diagnosi

I runner standard ospitati da GitHub escono con indirizzi dinamici. Gli intervalli sono pubblicati dalla REST API meta sotto la chiave actions e aggiornati periodicamente, ma la documentazione sconsiglia esplicitamente di usarli come allow list per risorse interne: sono condivisi e cambiano. Le alternative corrette sono due, larger runner con intervalli IP statici oppure runner self-hosted dentro la tua rete.

Gli IP statici si attivano nella sezione Networking del larger runner, con l’opzione che assegna intervalli pubblici univoci e statici a quel pool. Richiede GitHub Enterprise Cloud, non è disponibile su macOS ed esiste un tetto predefinito al numero di pool configurabili, elevabile contattando il supporto. In alternativa il traffico resta privato: runner ospitati dentro una Azure virtual network, un overlay WireGuard fra runner e servizio interno, oppure un API gateway che accetta il token OIDC del workflow al posto di un segreto statico.

Per il troubleshooting, un runner appare Idle, Active oppure Offline, e Offline copre tanto la macchina spenta quanto l’applicazione ferma o il blocco di rete. Le prove stanno nella cartella _diag, con i file Runner_ per gli avvii dell’applicazione e Worker_ per i singoli job; ./config.sh --check verifica la connettività verso GitHub e su Linux journalctl segue il servizio in tempo reale.