Files
trx-rs/container/README.md
T
sjg 8b72573521 [chore](trx-rs): add sccache compilation cache
Bake sccache into the SDK image and enable it via RUSTC_WRAPPER in CI and
the devcontainer (not repo-wide, so non-SDK builds are unaffected).

- container/Containerfile: install the sccache musl binary.
- ci.yml: RUSTC_WRAPPER=sccache, CARGO_INCREMENTAL=0, SCCACHE_DIR=/sccache,
  cache size cap, plus a `sccache --show-stats` step per job.
- runner-config.example.yaml: bind-mount /var/cache/sccache into job
  containers so the cache persists across runs and is shared between jobs.
- .devcontainer: enable sccache with a named cache volume.

Assisted-By: Claude Code (claude-opus-4)
Claude-Session: https://claude.ai/code/session_01NFpGtGTWUEYXLwZeZs2RAV
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-08-02 11:27:42 +02:00

4.8 KiB

trx-rs SDK image

A single container image that is the canonical build environment for trx-rs, used both by CI and by developers. It bakes in the pinned Rust toolchain (matching rust-toolchain.toml) and every build dependency, so the compiler and clippy are identical everywhere — no "works on my machine".

File Purpose
Containerfile The SDK image (Debian + build deps + pinned Rust + Node + git).
runner-config.example.yaml Example act_runner config for the CI VM (Docker executor).

Build and publish

# from the repo root
podman build -t git.haxx.space/sjg/trx-rs/sdk:latest container
podman login git.haxx.space
podman push git.haxx.space/sjg/trx-rs/sdk:latest

Tag with the Rust version too (e.g. :1.97.1) if you want reproducible pins. Make the package public (Gitea → Packages → the image → Settings) so the CI runner and developers can pull it without credentials. If you keep it private, add credentials: under the workflow's container: and log the runner into the registry.

Developer use

Reproducible one-off build, no local toolchain needed:

podman run --rm -it -v "$PWD":/work -w /work \
  git.haxx.space/sjg/trx-rs/sdk:latest \
  cargo build --release

Or open the repo in the image via VS Code / JetBrains "Reopen in Container" (.devcontainer/devcontainer.json points at the same image).

Building outside the container? rust-toolchain.toml pins the same rustc, so rustup installs the matching toolchain automatically.

CI use

.gitea/workflows/ci.yml runs the lint and test jobs inside this image via the container: key, so they skip all setup and go straight to cargo. The reuse job stays on the upstream fsfe/reuse-action (a Docker action the Docker executor launches as a sibling container) — nothing REUSE-related is baked into the SDK.

Compilation cache (sccache)

The SDK image ships sccache. It is enabled via RUSTC_WRAPPER=sccache in CI and the devcontainer (not repo-wide, so plain cargo builds outside the SDK are unaffected).

  • CI persists the cache on the runner host — create the dir once: mkdir -p /var/cache/sccache. It is bind-mounted into each job container at /sccache (see runner-config.example.yaml), so cache survives across runs and is shared between the lint/test jobs and both projects.
  • Devcontainer uses a named volume (trx-rs-sccache).
  • Check effectiveness with sccache --show-stats (the CI jobs print it).

CARGO_INCREMENTAL=0 is set wherever sccache is on, since sccache cannot cache incremental artifacts.

CI runner (Alpine / OpenRC)

The runner uses the Docker executor (not the host executor): per-job container isolation and standard ubuntu-latest semantics. act_runner runs as an OpenRC service. Files provided:

File Purpose
act_runner.openrc OpenRC init script (supervise-daemon, depends on docker).
act_runner.confd.example Per-instance conf.d settings for multi-runner hosts.

Cap the thread budget. In a VM, pin its vCPUs to specific host threads (libvirt/KVM):

<vcpu placement='static'>2</vcpu>
<cputune>
  <vcpupin vcpu='0' cpuset='4'/>
  <vcpupin vcpu='1' cpuset='5'/>
</cputune>

On bare metal, the container.options: "--cpus=2" and capacity: 1 in runner-config.example.yaml already bound each runner.

Set it up:

# 1. Docker + a dedicated user with socket access
apk add docker docker-cli
rc-update add docker default && rc-service docker start
adduser -S -D -H -h /var/lib/act_runner act
addgroup act docker

# 2. act_runner binary (static Go build, works on musl)
curl -fsSL -o /usr/local/bin/act_runner \
  https://gitea.com/gitea/act_runner/releases/download/v0.2.11/act_runner-0.2.11-linux-amd64
chmod +x /usr/local/bin/act_runner

# 3. Config + register one runner per project (scope keeps their jobs apart)
install -Dm644 container/runner-config.example.yaml /etc/act_runner/trx-rs.yaml
install -d -o act /var/lib/act_runner/trx-rs
su act -s /bin/sh -c 'cd /var/lib/act_runner/trx-rs && \
  act_runner register --no-interactive \
    --instance https://git.haxx.space --token <TOKEN> \
    --name trx-rs-ci \
    --labels "ubuntu-latest:docker://catthehacker/ubuntu:act-latest"'

# 4. OpenRC service (repeat the symlink+conf.d for the second project)
install -m755 container/act_runner.openrc /etc/init.d/act_runner
ln -s act_runner /etc/init.d/act_runner.trx-rs
install -m644 container/act_runner.confd.example /etc/conf.d/act_runner.trx-rs
rc-update add act_runner.trx-rs default
rc-service act_runner.trx-rs start

Check it with rc-service act_runner.trx-rs status and tail -f /var/log/act_runner.trx-rs.log.