Skip to content

2026-11-03 — Retire repo-scoped runners

TL;DR

Forty-two unpinned repository-scoped general and docker runners are gone from GitHub and from the Hyper-V guests. The 24 organization pool runners stay, as do homelab-ci-02, homelab-lan-01, homelab-mgmt-01, and homelab-ephemeral-canary-01. Tiktooker DEPLOY_RUNS_ON now uses the same pool CI labels as CI_RUNS_ON, and HomelabHyperVRunnerScaler is running again so idle guests stop after the 900 second timeout.

Phase status

Item State
Pool runners online 24 in the Default group. Kept
Fleet CI_RUNS_ON / DOCKER_RUNS_ON pool,ci and pool,docker on all 12 repositories
Tiktooker DEPLOY_RUNS_ON Moved to ["self-hosted","Linux","X64","pool","ci"]
Homelab protected variables Unchanged. They still pin homelab-ci-02, homelab-lan-01, and homelab-mgmt-01
Phase 6 retirement Live removal done for the unpinned general and docker instances. allow_remove stays false
Scaler schedule HomelabHyperVRunnerScaler is Running

What shipped

The retired set is every repository-scoped general or docker instance except homelab-ci-02. That includes homelab-ci-01, homelab-ci-03 through homelab-ci-06, both homelab docker runners, the extra telegram-companion-docker-03, and all four Tiktooker runners (tiktooker-ci-01, tiktooker-ci-02, tiktooker-docker-01, tiktooker-docker-02). Each one was disabled on its guest, its container and instance env were removed, and the GitHub registration was deleted. Nothing still named in a live runs-on variable was removed.

fleet.yml and infra/ansible/inventory/github-runners.yml match that live set. target_cap is 28 (4 repository-scoped runners plus 24 pool runners). The guests do not ansible-pull this manifest on a timer, so the live removal is what frees the memory. The manifest has to match so a later apply does not recreate them.

Tiktooker rollback value, the previous DEPLOY_RUNS_ON:

["self-hosted", "Linux", "X64", "tiktooker", "ci"]

No other repository variable was changed. Homelab DEPLOY_RUNS_ON, RUNNER_FLEET_API_RUNS_ON, and RUNNER_FLEET_MAINTENANCE_RUNS_ON are the same.

Running github-runner@ units after the removal, before the scaler stopped idle guests: gha-general-a 21 to 9, gha-general-b 20 to 8, gha-docker-a 13 to 4, gha-docker-b 13 to 4. Assigned memory while those guests were still up fell from about 11.8 / 14.6 / 16.3 / 10.5 GiB to about 8.2 / 9.5 / 10.9 / 6.4 GiB on gha-docker-a, gha-general-b, gha-general-a, and gha-docker-b. The scaler then stopped gha-docker-a, gha-docker-b, and gha-canary-a. gha-general-a, gha-general-b, and gha-mgmt were still running at the end of this pass.

Known gaps

The installed scaler still uses its existing ProgramData checkout. This change does not refresh that checkout, and last_needed was not rewritten by hand. Non-elevated Enable-ScheduledTask returned access denied. The existing task is Running as renjamin with the S4U principal, boot, logon, and 5-minute keep-alive triggers.

infra-services still has its ansible-pull apply timer disabled and /etc/homelab/MAINTENANCE in place. /opt/homelab was not fast-forwarded. Docker guests still use a 6 GiB per-runner ceiling against a 16 GiB maximum.

What remains

Merge this manifest so the retired instances stay out of the next apply. An elevated scaler reinstall from the merged tree can refresh the pinned runtime map. The docker memory-limit decision is still open. Do not remove the pool, the LAN runner, the management runner, the canary, or homelab-ci-02 while RUNNER_FLEET_API_RUNS_ON names it.

flowchart LR
  subgraph kept [Kept online or on demand]
    pool[24 pool runners]
    ci02[homelab-ci-02]
    lan[homelab-lan-01]
    mgmt[homelab-mgmt-01]
    canary[homelab-ephemeral-canary-01]
  end
  subgraph removed [Removed]
    old[42 repo-scoped general and docker runners]
  end
  scaler[HomelabHyperVRunnerScaler]
  idle[Idle Hyper-V guests]
  scaler --> idle