Skip to content

Commit 36bbc4e

Browse files
committed
Add a Node golden-image tier
The base tier ships no language toolchain, so setup-node downloads Node every run. Add a firerunner-node tier that bakes Node.js LTS into the golden rootfs from the official static tarball, mirroring GitHub's hosted tool cache. Fix the tiers table, which claimed the base tier shipped Node when the script never installed it.
1 parent 017fed3 commit 36bbc4e

2 files changed

Lines changed: 43 additions & 9 deletions

File tree

images/README.md

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,30 @@ milliseconds and is thrown away after the run.
2020
## Tiers
2121

2222
Different workloads need different images. Each tier is a separate golden rootfs
23-
selected by the runner labels a workflow requests.
23+
selected by the runner label a workflow requests (`runs-on: <tier>`). In the
24+
scale-set model GitHub routes a job to the scale set whose name matches that
25+
label, so each tier runs as its own firerunner instance/scale set.
2426

2527
| Tier | vCPU / RAM (suggested) | Contents | Use for |
2628
| ------------------------- | ---------------------- | ---------------------------------------------------- | ----------------------------------------------------------- |
27-
| `firerunner-4c8g` | 4 / 8 GiB | actions/runner, git, Node LTS + pnpm, build-essential | typical JS/TS builds, tests, lint |
29+
| `firerunner-4c8g` | 4 / 8 GiB | actions/runner, git, curl, jq, build-essential base | generic jobs; toolchains fetched by `setup-*` per workflow |
30+
| `firerunner-node` | 2 / 4 GiB | everything above **+ Node.js LTS + npm** (baked) | JS/TS builds where `setup-node` should hit a local toolchain |
2831
| `firerunner-8c16g-docker` | 8 / 16 GiB | everything above **+ Docker Engine (dind-capable)** | jobs using `container:`, service containers, `docker build` |
2932

30-
The Docker tier exists because some pipelines rely on `docker build`, job
31-
`container:` and service containers, which need a real Docker daemon inside the
32-
guest.
33+
The base tier deliberately ships no language toolchain — a workflow's `setup-go`
34+
/ `setup-node` fetches one per run. Baking a toolchain (the `firerunner-node`
35+
tier) removes that download, mirroring GitHub's hosted **tool cache**
36+
(`/opt/hostedtoolcache`). The Docker tier exists because some pipelines rely on
37+
`docker build`, job `container:` and service containers, which need a real
38+
Docker daemon inside the guest.
39+
40+
### Running several tiers on one host
41+
42+
Each tier is a distinct scale set, so a host running more than one firerunner
43+
instance must give each its own network identity or their nftables tables and
44+
guest subnets collide. Set, per extra instance: `FR_NAME` (the tier label),
45+
`FR_GOLDEN` (its rootfs), and non-overlapping `FR_TAP_PREFIX`, `FR_NET_BASE`
46+
(second IP octet, e.g. 17), `FR_NFT_TABLE` and `FR_WORKDIR`.
3347

3448
## What the boot service does (MMDS → JIT)
3549

@@ -58,13 +72,19 @@ sudo ./build-rootfs.sh \
5872
--tier firerunner-4c8g \
5973
--runner-version 2.320.0 \
6074
--out /var/lib/firerunner/golden-4c8g.ext4
75+
76+
# Node tier (bakes Node.js LTS); --node-version overrides the default:
77+
sudo ./build-rootfs.sh \
78+
--tier firerunner-node \
79+
--node-version 22.11.0 \
80+
--out /var/lib/firerunner/golden-node.ext4
6181
```
6282

6383
`build-rootfs.sh` creates/formats the ext4 image, debootstraps a minimal Debian
6484
base (systemd + git/curl/iproute2), installs `actions/runner` and runs its
6585
`installdependencies.sh`, drops in the boot service + a static resolv.conf,
66-
enables the service, and (for the docker tier) installs Docker. The result is an
67-
immutable file firerunner reflink-clones per job. Requires `debootstrap`,
86+
enables the service, and (per tier) installs Docker or bakes Node.js. The result
87+
is an immutable file firerunner reflink-clones per job. Requires `debootstrap`,
6888
`mkfs.ext4`, `curl` and `tar` on the host.
6989

7090
## Rebuild policy

images/build-rootfs.sh

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ ASSETS="$HERE/assets"
1818

1919
TIER="firerunner-4c8g"
2020
RUNNER_VERSION="" # empty => resolve latest from GitHub releases
21+
NODE_VERSION="22.11.0" # Node LTS baked into the firerunner-node tier
2122
OUT=""
2223
SIZE_MB=8192
2324
DNS_SERVERS="1.1.1.1 8.8.8.8"
@@ -30,6 +31,7 @@ while [[ $# -gt 0 ]]; do
3031
case "$1" in
3132
--tier) TIER="$2"; shift 2 ;;
3233
--runner-version) RUNNER_VERSION="$2"; shift 2 ;;
34+
--node-version) NODE_VERSION="$2"; shift 2 ;;
3335
--out) OUT="$2"; shift 2 ;;
3436
--size-mb) SIZE_MB="$2"; shift 2 ;;
3537
--dns-servers) DNS_SERVERS="${2//,/ }"; shift 2 ;;
@@ -44,8 +46,8 @@ done
4446
[[ -n "$OUT" ]] || die "--out is required"
4547

4648
case "$TIER" in
47-
firerunner-4c8g|firerunner-8c16g-docker) ;;
48-
*) die "unknown tier: $TIER (want firerunner-4c8g or firerunner-8c16g-docker)" ;;
49+
firerunner-4c8g|firerunner-8c16g-docker|firerunner-node) ;;
50+
*) die "unknown tier: $TIER (want firerunner-4c8g, firerunner-8c16g-docker or firerunner-node)" ;;
4951
esac
5052

5153
for t in mkfs.ext4 curl tar debootstrap; do
@@ -137,6 +139,18 @@ if [[ "$TIER" == "firerunner-8c16g-docker" ]]; then
137139
in_chroot systemctl enable docker.service
138140
fi
139141

142+
# 6b. (node tier) bake Node.js LTS so runs-on:firerunner-node jobs find node/npm
143+
# on PATH without a setup-node download (mirrors GitHub's hosted tool cache).
144+
# Installed from the official static tarball into /usr/local (no apt, no
145+
# nodesource) to keep the image minimal; --strip-components lands node in
146+
# /usr/local/bin.
147+
if [[ "$TIER" == "firerunner-node" ]]; then
148+
echo ">> installing Node.js v$NODE_VERSION for the node tier"
149+
node_url="https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64.tar.gz"
150+
curl -fsSL "$node_url" | tar -xz -C "$MNT/usr/local" --strip-components=1
151+
in_chroot /usr/local/bin/node --version
152+
fi
153+
140154
# Trim apt caches to keep the image lean.
141155
in_chroot apt-get clean || true
142156
rm -rf "$MNT/var/lib/apt/lists/"* "$MNT/var/cache/apt/archives/"*.deb

0 commit comments

Comments
 (0)