Skip to content

Multi-tenant runner platform for Kubernetes

Self-hosted GitHub Actions with zero idle compute

An Actions Runner Controller (ARC) alternative for multi-tenant Kubernetes. Free up GPU nodes the moment a job finishes, keep critical jobs scheduling even on a full cluster, and let tenants self-manage runners under safe per-tenant quotas.

Get started Watch the demo Why GAG? View on GitHub

Drop-in for your existing setup — jobs target the same runner labels, so nothing in your .github/workflows changes.

helm install gag \
  oci://ghcr.io/actions-gateway/charts/actions-gateway \
  --version 1.0.0 \
  --namespace gmc-system --create-namespace \
  --set gmc.image.digest=sha256:<gmc> \
  --set agc.image.digest=sha256:<agc> \
  --set proxy.image.digest=sha256:<proxy> \
  --set wrapper.image.digest=sha256:<wrapper>

What GAG gives you

Most of these ladder up to one outcome — lower cost: no idle GPUs, fewer always-on resources, and guaranteed throughput instead of blocked critical jobs. Estimate your savings vs ARC →

  • Tenant self-service under quotas


    Quotas you can safely enforce:

    • Platform-owned quota cap
    • Blocked jobs auto-recover
    • Zero manual reruns
    • Tenants manage their runners
  • No blocked critical jobs


    Reserve capacity for key runners:

    • Reserve N slots per runner type
    • CPU tests can't starve GPU jobs
    • Critical tests always schedule
  • No idle GPUs


    Pods live only for the job:

    • Created on acquire
    • Deleted on completion
    • GPU freed the instant a job ends
    • Scale-to-zero by default
  • Isolated egress IPs


    Each tenant's own proxy pool:

    • Allow-list runners on GitHub Enterprise Managed Users (EMU)
    • No shared cluster allow-list
    • Flagged tenants stay isolated
    • v2: proxy optional
  • Lower listener overhead


    Listeners are goroutines, not pods:

    • ~60 KiB per runner group
    • One shared pod per tenant
    • 600 KiB vs 2.5 GiB for ten groups
  • Per-tenant observability


    Scoped visibility, no cluster access:

    • Prometheus per tenant + group
    • Grafana dashboards + alerts, as code
    • Job counts in kubectl get
    • K8s Events on job transitions
  • Shared runner templates v2


    Define once, reference by name:

    • RunnerTemplate per many sets
    • Platform ClusterRunnerTemplate
    • Identical templates collapse
    • Migrate v1→v2 with gag-migrate
  • Secure by default


    Hardening reconciled by default:

    • baseline Pod Security Admission (PSA) per namespace
    • Default-deny NetworkPolicies
    • Credentials never in env vars
    • Signed images + Software Bill of Materials (SBOM) + SLSA
  • Tenant runner self-service v2


    Self-managed runners, one setup:

    • Self-serve ActionsGateway CRs
    • Tune maxRunners per group
    • Multiple gateways per namespace
    • No platform ticket per change

Who GAG is for

GAG targets a specific audience: teams that must self-host runners and run them for many tenants on one cluster. If that's you, here's the value per segment.

  • Platform & developer-experience teams


    Multi-tenant CI on a shared cluster:

    • Enforce a per-team quota without stranding jobs
    • Tenants self-serve from one ActionsGateway
    • No ticket queue for every runner change
  • Orgs that must self-host


    Driven by a hard constraint, not preference:

    • Compliance or data-residency requirements
    • EMU or firewalled-service IP allow-lists
    • Per-tenant egress IPs you allow-list directly
  • GPU / ML platform teams


    Done paying for accelerators between jobs:

    • Workers scale to zero — no idle GPU
    • GPU nodes return to the scheduler on completion
    • Priority tiers keep critical GPU jobs scheduling

Not your setup? If you're happy running on a vendor's infrastructure, a managed-SaaS runner is the better fit. GAG competes with Actions Runner Controller (ARC) for self-hosted, multi-tenant clusters — not on raw build speed.

How it fits together

A four-tier system: a cluster-scoped manager gives each tenant an isolated gateway from its ActionsGateway. Jobs are acquired with the same single-acquirer runner-scale-set protocol ARC uses — the shipped default — so GAG is a strict superset of ARC's model, not a different-architecture trade-off.

Tenant input ActionsGateway resource one per tenant · namespace-scoped
Tier 1 Gateway Manager Controller cluster-scoped · installed once
Tier 2 Actions Gateway Controller goroutine multiplexer
Tier 3 Egress proxy pool per-tenant egress IPs
Tier 4 Ephemeral worker pods one per job · GC'd on completion

Read the architecture overview for the full breakdown, jump to why GAG over ARC, or see the public roadmap for what's shipped and what's next.