Rig>Workflows>Docker

Docker#

Rig ships the Docker image ghcr.io/brutasse/rig. The release job builds it for every release, tagged vX.Y.Z and latest. The image is multi-arch (linux/amd64, linux/arm64).

The image contains:

  • the rig binary at /usr/local/bin/rig. The resolver kernel jar, the rig.runner jar, and the vendored nREPL jar are embedded in it (go:embed) and pre-materialized into the state dir at their content-sha paths: first use reads the store and writes nothing, so the image works with a read-only root file system for the tool jars. Hot commands append the runner jar to the project classpath, so test and stage 3 of check need it. The artifact cache is still a runtime store — warm it in an earlier layer or mount a writable dir;
  • a Temurin 21 JDK, so the image is a standalone Clojure base.

As an app base#

In a dev container or CI job, rig must work from the first layer. The tool jars are embedded in the binary and pre-materialized in the image, so rig fetches nothing from GitHub. It fetches only from your artifact repositories.

FROM ghcr.io/brutasse/rig:latest
WORKDIR /app
COPY . .
RUN rig check && rig test

As an app entrypoint#

rig launch is the production entrypoint. It runs the built artifact with Rig's production JVM flag set: G1, exit-on-OOM, and loopback-only JMX on 10101. You can override the flags per module with :rig/launch-opts and per deployment with the RIG_LAUNCH_OPTS env var. rig launch replaces its own process with the JVM, so the app is the container's PID 1. It is offline by definition. rig build bakes the launch plan into the artifact. Production launch covers the full workflow: declaring launch opts, the Docker images (slim and workspace variants), process and lifecycle, and per-deployment overrides.

Multi-stage#

When your app image has its own base, copy the binary out of the image:

FROM eclipse-temurin:21-jdk-jammy
WORKDIR /app
COPY --from=ghcr.io/brutasse/rig:latest /usr/local/bin/rig /usr/local/bin/
COPY . .
RUN rig check && rig test

The binary carries its tool jars, so rig needs no GitHub access at runtime. It only talks to your artifact repositories. The build consumes the committed deps.lock: rig check fails when the lockfile is missing or stale. Locking is workstation work.

Pinned JVMs#

Base the image on the declared JDK. The :rig/jvm "21" pin in the root deps.edn becomes eclipse-temurin:21-jdk (the jammy variant above). Your build compiles with the JDK of the image. The state dir holds no rig-managed JDK for the pin, so Rig falls back to the system java, which satisfies the pin. There is no RUN rig jvm install step. The JDK of the image is the build JVM. When the base image carries no matching JDK, the build downloads the newest matching release on demand (--offline fails instead).

The runtime side of the same pin is in Production launch: the base of the app container must carry that JDK.

Non-root users#

The state dir is under /root. For a non-root build user, copy it to the home dir of that user, or point every invocation at a shared dir with --cache-dir /opt/rig-cache. The dir must be writable.

Offline builds#

The tool jars are pre-materialized in the image, but the artifact cache is cold. rig check in the Dockerfile fetches from your repositories and checks the hashes against the lockfile. For hermetic --offline builds, first warm the state dir in an earlier layer (or cache it across runs). See CI.