runpool README

The project's README from github.com/rhobuild/runpool. As one markdown file: README.md.

Runpool

CI CodeQL Go Docker Engine SQLite License Release

Runpool is a Docker-native control plane for autoscaling ephemeral CI runners on a single, capacity-bounded host. It translates provider demand into durable assignments, isolated per-job execution capsules, and optional repository-scoped cache lanes — without requiring Kubernetes.

Architecture

flowchart LR
    provider["GitHub Actions scale sets"] -->|"durable deliveries"| controller["Runpool controller"]
    controller -->|"Moby API"| host["Docker Engine 28+"]
    host --> capsule["Per-job capsule"]
    host --> gateway["Per-job egress gateway"]
    capsule -->|"DNS and HTTP proxy"| gateway
    capsule --> runtime["Runner + dockerd + job containers"]
    state[("SQLite state")] --- controller
    cache[("Repository cache lane")] -. "optional" .- capsule

The controller has no inbound service dependency. It maintains outbound provider sessions, reconciles durable state with Docker, and admits work only while scheduling and disk budgets are healthy. See the architecture guide for package boundaries, identity, recovery, and capacity semantics.

Why Runpool

Security boundary

Runpool is a resource-management, environment-hygiene, and network-policy boundary for CI workloads approved by the operator.

[!WARNING] Runpool is not a hostile code sandbox. It bounds and cleans up what an approved workload does; it does not contain code you would not have run.

Where that boundary ends:

Under public-internet-only, direct egress is denied. Proxy-aware HTTP clients can use absolute-form requests or CONNECT to allowed addresses on ports 80 and 443. CONNECT is an opaque tunnel; Runpool applies destination and port policy, not application-layer inspection. git+ssh, direct TCP, non-DNS UDP, IPv6, and other ports fail closed. Read the complete threat model before deployment.

Evaluate locally

Prerequisites are Go 1.26.0 or newer and a Linux host with rootful Docker Engine 28. The selected release-qualification target is documented in the support matrix.

git clone https://github.com/rhobuild/runpool.git
cd runpool
go build -trimpath -o runpool ./cmd/runpool
./runpool config validate --file internal/config/testdata/example.yaml
go test ./...

That builds the controller and checks a configuration. Reaching a job takes three more things: the two images, a target on GitHub, and a workflow that names the tier.

docker build -f build/capsule/Dockerfile -t runpool-capsule:dev .
docker build -f build/controller/Dockerfile -t runpool:dev .

[!NOTE] runpool-capsule:dev is the exact name a development build looks for. A release binary carries its capsule by digest and refuses to be pointed elsewhere; from source, this tag is the pairing.

Then a configuration, a credential, and the state directory:

RUNPOOL_GITHUB_URL=https://github.com/<owner>/<repo> \
RUNPOOL_GITHUB_TOKEN_FILE=/run/secrets/runpool/token \
RUNPOOL_HOST_TOPOLOGY=dedicated-daemon \
RUNPOOL_STATE_DIR="$PWD/state" \
./runpool doctor

RUNPOOL_STATE_DIR is $PWD/state here rather than the default /var/lib/runpool/state, which the deployed controller uses from inside its container and which a shell on the host cannot create without root.

doctor proves the host and the credential, and prints the runs-on label for every tier it would serve. Then ./runpool serve, and a workflow in that repository:

jobs:
  build:
    runs-on: runpool-standard

The complete example workflow shows what a job gets: its own Docker daemon, and egress through the relay. Deployment covers the GitHub side — which target shapes exist, what a runner group has to grant, and which credential to use — and the runbook covers operating it.

The reference Compose deployment asks for a released digest and refuses to start with no image at all; that it is a digest rather than a moving tag is yours to hold, and deployment covers verifying one. The images above are how a source checkout runs.

[!CAUTION] Do not use a production credential for local experimentation. A token that can reach real repositories reaches them from a host you are still testing.

Deployment

Runpool provides a canonical Docker Compose manifest for its headless controller: no domain, reverse-proxy route, or public port is required.

[!IMPORTANT] A version is release-qualified only after a no-skip qualification run on the exact platform frozen before its candidate in build/platform.lock.json. Each release carries the record that run produced, bound to its commit and to the image digests it publishes; release readiness lists the gates and the evidence each one leaves.

Platform Entry point
Docker Compose deploy/compose/compose.yaml
A Compose platform Deploy the canonical Compose file; a platform catalog entry, where the platform has one, derives its template from that same contract

Read the deployment guide before installing. The Compose contract reads an operator-managed configuration file; the example selects shared-daemon for a host shared with a platform, and illustrates an explicit reserve for colocated services. Measure that reserve before deployment. Choose dedicated-daemon only on an exclusive CI host.

Project documentation

Guide Purpose
Deployment Compose, platforms, credentials, and lifecycle
Product contract Guarantees, exclusions, and compatibility surfaces
Architecture Components, dependency direction, state, and recovery
Configuration Supported settings and validation rules
CLI reference Generated commands, flags, and exit-code behaviour
Support matrix Engine compatibility, release reference, and provider scope
Runbook Operations, recovery, backup, GC, and uninstall
Threat model Trust boundary, defences, one known weakness, and accepted exposure
ADRs Architectural decisions and measured constraints
Release readiness The objective gates a release must satisfy

Contributing and security

Read CONTRIBUTING.md before opening a pull request. Report security issues privately as described in SECURITY.md; never open a public issue for a suspected vulnerability.

Runpool is maintained by Rhobuild and licensed under the Apache License 2.0.

runpool (rhobuild/runpool)

Searching Database…

Что это такое?Плоскость управления в духе Docker, которая автоматически масштабирует временные CI-раннеры на одном хосте с ограниченной ёмкостью и без Kubernetes: потребность провайдера превращается в устойчивые назначения задач и изолированные капсулы выполнения для каждой задачи.
Как его запустить?Нужен хост с Linux, rootful Docker Engine 28 и Go 1.26.0+. Соберите контроллер, выполните ./runpool doctor, чтобы проверить хост и учётные данные, затем запустите ./runpool serve — или разверните через прилагаемый манифест Compose.
Что именно проверяет команда doctor?Она подтверждает, что с хостом и учётными данными всё в порядке, и печатает метку runs-on для каждого тира, который она обслуживает, так что ещё до подключения задачи вы знаете, что указать в своём workflow.
Что будет, если результат задачи неоднозначен, например после сбоя?Назначения сохраняются до подтверждения брокером, поэтому повторная доставка идемпотентна, а неоднозначные выполнения не перезапускаются молча, а откладываются на рассмотрение оператору.
Почему запускать это на одном хосте, а не в Kubernetes?В этом и замысел: автоматическое масштабирование временных раннеров на одном хосте с ограниченной ёмкостью. Раннер, внутренний демон, дочерние контейнеры и egress-шлюз делят общий лимит cgroup, и кластер Kubernetes обслуживать не нужно.
Creator
rhobuild
Size
7.6 MB
Stars
384
Age
2mo
Commits · 90 Days