# Roc Language OCI Images **Date:** 2026-06-04 **Status:** Design — approved ## Overview Build and publish OCI container images for the [Roc language](https://roc-lang.org/) compiler/development environment. Three images (base, dev, ci) defined in a single multi-stage `Containerfile`, published to a self-hosted Gitea container registry (`git.roo.lol`). ## Image Architecture ``` debian:bookworm-slim └── roc-tools-base — Roc compiler binary + lib/wasi-libc.a + LICENSE ├── roc-tools-dev — Base + LSP + git + curl + bash + ca-certificates └── roc-tools-ci — Base + ca-certificates (minimal runner) ``` ## Repository Structure ``` roc-lang-tools/ ├── Containerfile # Multi-stage: base / dev / ci targets ├── Makefile # Build & push convenience commands ├── scripts/ │ └── download-roc.sh # Download & extract a specific Roc release tarball ├── docs/ │ └── specs/ │ └── 2026-06-04-roc-oci-images-design.md └── .gitea/ └── workflows/ └── build.yaml # Gitea Actions CI: build & push on version tags ``` ## Image Registry All images published to `git.roo.lol/jbrechtel/` with the following naming: | Image | Repository | Tags | |----------|------------------------------------------|-------------------------------| | base | `git.roo.lol/jbrechtel/roc-tools-base` | `:X.Y.Z`, `:X.Y.Z-alphaN` | | dev | `git.roo.lol/jbrechtel/roc-tools-dev` | `:X.Y.Z`, `:X.Y.Z-alphaN` | | ci | `git.roo.lol/jbrechtel/roc-tools-ci` | `:X.Y.Z`, `:X.Y.Z-alphaN` | Tags mirror Roc release tags (e.g., `0.0.0-alpha2`). The `:latest` tag follows the most recently built version tag. ## Build Arguments The `Containerfile` accepts two build arguments: | Argument | Description | Default | |----------------|------------------------------------------|----------------| | `ROC_VERSION` | Roc GitHub release tag to download | `0.0.0-alpha2` | | `TARGETARCH` | Target CPU architecture (set by buildx) | `amd64` | Multi-arch is supported via `docker buildx` — the download script maps `TARGETARCH` to Roc tarball names (`x86_64` / `aarch64`). ## Image Details ### Base (`roc-tools-base`) The base image provides just the Roc compiler and its runtime library. **Installed:** - `/opt/roc/bin/roc` — Roc compiler binary - `/opt/roc/lib/wasi-libc.a` — WASI libc runtime library (required by some platforms) - `/opt/roc/LICENSE` — Roc license file - `ca-certificates` (build-time only, removed from final layer) - `roc` user/group (UID 1000) - `PATH` includes `/opt/roc/bin` **Entrypoint:** `roc` ### Dev (`roc-tools-dev`) Full interactive development environment. **Inherits:** Base image **Additional packages:** `git`, `curl`, `bash`, `ca-certificates` **Additional files:** - `/opt/roc/bin/roc_language_server` — Roc LSP server (included in the release tarball) **Entrypoint:** `bash` **Use case:** ```bash docker run -it --rm -v $(pwd):/work -w /work git.roo.lol/jbrechtel/roc-tools-dev ``` ### CI (`roc-tools-ci`) Minimal image for CI/CD runner pipelines (Gitea Actions, GitLab CI, etc.). **Inherits:** Base image **Additional packages:** `ca-certificates` **Entrypoint:** `roc` **Use case:** ```yaml - run: docker run --rm git.roo.lol/jbrechtel/roc-tools-ci roc build ``` ## Release Download Strategy The `scripts/download-roc.sh` script: 1. Accepts `ROC_VERSION` and `TARGETARCH` arguments 2. Constructs the GitHub release URL: ``` https://github.com/roc-lang/roc/releases/download/{ROC_VERSION}/roc-linux_{ARCH}-{ROC_VERSION}.tar.gz ``` Where `ARCH` is `x86_64` (for amd64) or `aarch64` (for arm64). 3. Downloads and extracts the tarball 4. Copies the `roc` and `roc_language_server` binaries to `/opt/roc/bin/` 5. Copies `lib/wasi-libc.a` to `/opt/roc/lib/` 6. Copies `LICENSE` to `/opt/roc/` The tarball contains a top-level directory with a nightly-derived name (e.g., `roc_nightly-linux_x86_64-2025-09-09-d73ea109/`), so the script uses a glob/wildcard rather than assuming a fixed directory name. ## Build Workflow ### Local Development ```bash # Build all three images make build-all ROC_VERSION=0.0.0-alpha2 # Build a specific target make build-dev ROC_VERSION=0.0.0-alpha2 # Build and push make push-all ROC_VERSION=0.0.0-alpha2 # Override registry make build-base ROC_VERSION=0.0.0-alpha2 REGISTRY=localhost:5000 ``` ### CI/CD (Gitea Actions) The `.gitea/workflows/build.yaml` workflow triggers on Git tags matching `v*` (e.g., `v0.0.0-alpha2`). It: 1. Extracts the Roc version from the tag (`v0.0.0-alpha2` → `0.0.0-alpha2`) 2. Sets up Docker Buildx with multi-arch support (linux/amd64, linux/arm64) 3. Logs into the Gitea container registry using the Gitea Actions token 4. Builds and pushes all three image targets in a single build command 5. Tags each image with both the version and `:latest` ## Makefile Targets | Target | Description | |--------------|-----------------------------------------| | `build-base` | Build the base image | | `build-dev` | Build the dev image | | `build-ci` | Build the ci image | | `push-all` | Build all images and push to registry | | `build-all` | Build all three images (no push) | Variables: `ROC_VERSION` (default `0.0.0-alpha2`), `REGISTRY` (default `git.roo.lol/jbrechtel`). ## Security Considerations - Images run as non-root `roc` user (UID 1000) - `debian:bookworm-slim` base receives regular security patches - Only `ca-certificates` and essential packages are added beyond the binary - The base image has no shell or package manager in the final stage - Dev image has a shell (bash) by design for interactive use