Files
roc-lang-tools/docs/specs/2026-06-04-roc-oci-images-design.md
T

171 lines
5.8 KiB
Markdown

# 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