Extend the harness image
The harness image is where your project is built, timed and changed: the judge’s builds and timed runs and the agents’ commands all run inside it. If your project needs a tool the image lacks, such as another compiler or a library, build your own image FROM Thermite’s harness image and add it.
The image already has a C and C++ toolchain (gcc, g++, make), CMake, Ninja, ccache, Python 3 with numpy, git, Node.js, OpenCode and the Codex CLI. A CUDA image also has what its base carries, such as nvcc. The CPU image is Debian bookworm; a CUDA image has its base’s system. The harness image reference lists it in full.
Before you start
Section titled “Before you start”- Thermite’s harness image: a published one, such as
ghcr.io/iammrduncan/thermite-harness:0.1.0for CPU rigs orghcr.io/iammrduncan/thermite-harness:0.1.0-cudafor GPU rigs (Published images), or one you built (Push the images to your own registry). Extend the CPU image for CPU rigs and the CUDA image for GPU rigs. - A registry your rigs can pull from without signing in, for your image.
1. Write a Containerfile
Section titled “1. Write a Containerfile”Start from the harness image and install with apt-get. This example adds a Fortran compiler and OpenBLAS:
FROM ghcr.io/iammrduncan/thermite-harness:0.1.0RUN apt-get update \ && apt-get install -y --no-install-recommends gfortran libopenblas-dev \ && rm -rf /var/lib/apt/lists/*ENV THERMITE_IMAGE_ID=0.1.0-fortran-1The last line gives your image a name of its own. The harness puts THERMITE_IMAGE_ID in the key of every build it makes, so a rig on your image builds afresh, and never reuses a build made without your tools. Change it with each new build of your image.
Keep these as they are, or the rig won’t start or won’t be safe to judge on:
| Keep | Why |
|---|---|
Root. Add no USER line | The harness starts as root and runs each kind of work as its own user. As another user it stops with fatal: not root, so roles cannot be separated |
ENTRYPOINT and CMD. Don’t set them | They start the harness |
| Thermite’s users and groups. Don’t remove, renumber or reuse them | Their ids are fixed in Thermite’s code. The harness image reference lists them |
/outbox, owned by user 10010 and group 10001, mode 2750 | The harness writes exports there and the supervisor reads them |
/opt/thermite | Thermite itself, and in /opt/thermite/checks the kits and projects of the smoke check |
2. Put tools where every user finds them
Section titled “2. Put tools where every user finds them”Builds, timed runs and the agents’ commands run as Thermite’s own users, not as root. They don’t get the image’s environment: only PATH (the image’s), LANG, their own HOME, TMPDIR and USER, and a few settings Thermite gives them itself.
- Install tools where every user can run them, such as
/usr/binor/usr/local/bin, not under/root. ENV PATH=…in your Containerfile reaches them. OtherENVlines, such asLD_LIBRARY_PATH, do not: register library folders with the system’s linker (ldconfig) instead.- Don’t rely on files in a home folder: each process’s home is its own working folder.
3. Build and push it
Section titled “3. Build and push it”Give it a name and a tag of its own, and use a new tag for every build: a machine never pulls a tag it already has.
docker build -t registry.example.com/thermite/thermite-harness-fortran:1a2b3c4d5e6f-1 -f Containerfile .docker push registry.example.com/thermite/thermite-harness-fortran:1a2b3c4d5e6f-1With Podman, use podman build and podman push.
4. Use it for new rigs
Section titled “4. Use it for new rigs”Set control’s harness image to yours, then restart control (with the compose stack: in .env, then docker compose up -d with your -f options):
THERMITE_RIG_HARNESS_IMAGEfor CPU rigs;THERMITE_RIG_HARNESS_CUDA_IMAGEfor GPU rigs.
Rigs › Add a rig shows it under Images, and every rig you add from then on runs it.
A rig you already have keeps the image it runs:
- A rig that control set up on a cluster can move onto your image. Its page then offers Update to these images (Move a rig onto new images). Every such rig whose image differs from control’s offers it, so press it only on the rigs that should have your tools.
- A rig you joined yourself can’t move to a new image from control yet (goal 035), so add a new rig. A rig control set up on a machine moves with Update to control’s version on its page only when its Thermite version is behind control’s.
Thermite doesn’t know which rigs carry your tools. A kit names only its target (cpu or cuda-gpu), and on a rig without the tools the judge’s builds of your project fail. Start campaigns that need them only on rigs added from your image; a name that says so, such as rig-fortran-1, helps.
On the local stack
Section titled “On the local stack”A release’s compose.yaml names the harness image itself and has no setting for another one (goal 061). Give its rig your image with an override file next to compose.yaml:
services: harness: image: registry.example.com/thermite/thermite-harness-fortran:1a2b3c4d5e6f-1Then start the stack with it, and name it in every later up, with your other -f options:
docker compose -f compose.yaml -f compose.harness.yaml up -d # or: podman compose -f … -f … up -dIn a checkout of the source code, the stack builds its harness from your clone instead. Add the packages to the first apt-get install line in your clone’s containers/harness/Containerfile (the one that lists gcc), then rebuild with docker compose up -d --build harness. The change stays in your clone, so a later git pull may ask you to merge it.
Check that it worked
Section titled “Check that it worked”On the new rig’s page (on the local stack, the page of local-1, from step 2 on):
- The Set up by control block’s Images names your image. (A rig you joined yourself shows it under You run it yourself.)
- Run Isolation and Judge smoke (Check a rig). Both must pass, as on Thermite’s own image.
- Run your kit with no agents, so the judge builds your project with the new tools: see Test a kit with known candidates.