- Dockerfile 100%
|
All checks were successful
Build Nix runner image / Build and push nix:latest plus immutable tag (push) Successful in 8m4s
- invoke shell version checks without nested command strings - keep smoke commands compatible with argument-based Docker execution |
||
|---|---|---|
| .forgejo | ||
| go | ||
| nix | ||
| pnpm | ||
| python | ||
| rust | ||
| uv | ||
| README.md | ||
Forgejo Actions runner images
This repository builds CI-ready job container images for a self-hosted Forgejo Actions runner at:
https://git.hayshin.dev
The images are published under one package namespace:
git.hayshin.dev/infra/runner-images
Images
Expected tags include both moving convenience tags and immutable commit-pinned tags:
git.hayshin.dev/infra/runner-images/nix:latest
git.hayshin.dev/infra/runner-images/nix:latest-<git-sha>
git.hayshin.dev/infra/runner-images/rust:1
git.hayshin.dev/infra/runner-images/rust:1-<git-sha>
git.hayshin.dev/infra/runner-images/go:1
git.hayshin.dev/infra/runner-images/go:1-<git-sha>
git.hayshin.dev/infra/runner-images/python:3.14
git.hayshin.dev/infra/runner-images/python:3.14-<git-sha>
git.hayshin.dev/infra/runner-images/pnpm:22
git.hayshin.dev/infra/runner-images/pnpm:22-<git-sha>
git.hayshin.dev/infra/runner-images/uv:latest
git.hayshin.dev/infra/runner-images/uv:latest-<git-sha>
Use the immutable -<git-sha> tags for runner labels after testing. The moving tags are retained for manual convenience and discovery only.
Each image includes:
- Node.js 22
- git
- bash
- ca-certificates
- coreutils and common POSIX tools
- curl
- the target toolchain
The Debian-based images install and verify Node.js 22.22.2. The nix image installs nodejs_22, devenv, actionlint, action-validator, and yamllint from the pinned nixpkgs revision and verifies the resulting Node.js version, currently v22.22.3.
The language bases are upstream images:
nixusesnixos/nix:2.24.11@sha256:4bfe741027f0bfbef745862cbf3b5f424ee99801c04138146c0000a28759636drustusesrust:1-bookwormgousesgolang:1-bookwormpythonusespython:3.14-bookwormpnpmusesnode:22.22.2-bookworm@sha256:62e4daa6819762bbd3072af77cc282ab72c631c4aed30dd7980192babaf385b3uvusesastral/uv:python3.14-bookworm
Runtime user
All images intentionally run as root by default. These are CI job-container images for Forgejo Actions/act, where workflows commonly need to install OS packages, populate language/tool caches, or write to workspace-mounted paths without extra permission setup.
Treat workflow code as trusted, prefer immutable -<git-sha> runner labels, and avoid using these images as general-purpose application runtime bases. If a specific job does not need elevated permissions, override the user at run time or create a derived image with a non-root user.
Why Node is included
Forgejo Actions is compatible with the GitHub Actions model and, through act, runs JavaScript actions inside the job container. A workflow step such as:
- uses: actions/checkout@v4
does not run as a shell script. It runs the bundled JavaScript action with Node, roughly equivalent to:
node dist/index.js
That means every job image intended for normal Actions workflows needs Node available in the container. Raw language images such as rust:1-bookworm, golang:1-bookworm, and python:3.14-bookworm are useful for simple run: steps, but they can fail as soon as a JavaScript action is used.
Build locally
Build all images with moving and immutable tags:
SHA=$(git rev-parse HEAD)
docker build -t git.hayshin.dev/infra/runner-images/nix:latest -t git.hayshin.dev/infra/runner-images/nix:latest-$SHA nix
docker build -t git.hayshin.dev/infra/runner-images/rust:1 -t git.hayshin.dev/infra/runner-images/rust:1-$SHA rust
docker build -t git.hayshin.dev/infra/runner-images/go:1 -t git.hayshin.dev/infra/runner-images/go:1-$SHA go
docker build -t git.hayshin.dev/infra/runner-images/python:3.14 -t git.hayshin.dev/infra/runner-images/python:3.14-$SHA python
docker build -t git.hayshin.dev/infra/runner-images/pnpm:22 -t git.hayshin.dev/infra/runner-images/pnpm:22-$SHA pnpm
docker build -t git.hayshin.dev/infra/runner-images/uv:latest -t git.hayshin.dev/infra/runner-images/uv:latest-$SHA uv
Quick checks:
docker run --rm git.hayshin.dev/infra/runner-images/nix:latest node --version
docker run --rm git.hayshin.dev/infra/runner-images/nix:latest devenv --version
docker run --rm git.hayshin.dev/infra/runner-images/rust:1 rustc --version
docker run --rm git.hayshin.dev/infra/runner-images/go:1 go version
docker run --rm git.hayshin.dev/infra/runner-images/python:3.14 python --version
docker run --rm git.hayshin.dev/infra/runner-images/pnpm:22 pnpm --version
docker run --rm git.hayshin.dev/infra/runner-images/uv:latest uv --version
Push manually
Log in to the Forgejo package registry:
docker login git.hayshin.dev
Push all tags:
SHA=$(git rev-parse HEAD)
docker push git.hayshin.dev/infra/runner-images/nix:latest
docker push git.hayshin.dev/infra/runner-images/nix:latest-$SHA
docker push git.hayshin.dev/infra/runner-images/rust:1
docker push git.hayshin.dev/infra/runner-images/rust:1-$SHA
docker push git.hayshin.dev/infra/runner-images/go:1
docker push git.hayshin.dev/infra/runner-images/go:1-$SHA
docker push git.hayshin.dev/infra/runner-images/python:3.14
docker push git.hayshin.dev/infra/runner-images/python:3.14-$SHA
docker push git.hayshin.dev/infra/runner-images/pnpm:22
docker push git.hayshin.dev/infra/runner-images/pnpm:22-$SHA
docker push git.hayshin.dev/infra/runner-images/uv:latest
docker push git.hayshin.dev/infra/runner-images/uv:latest-$SHA
Use a Forgejo user and a token with package write access if password login is disabled.
CI workflows
Each image has its own Forgejo workflow, scoped to its image folder:
.forgejo/workflows/build-nix.yml
.forgejo/workflows/build-rust.yml
.forgejo/workflows/build-go.yml
.forgejo/workflows/build-python.yml
.forgejo/workflows/build-pnpm.yml
.forgejo/workflows/build-uv.yml
On pushes to main, each workflow runs only when its Dockerfile folder or workflow file changes. Each workflow can also be started manually with workflow_dispatch.
The jobs use:
runs-on: ubuntu-latest
That runner label must resolve to an act-compatible image with Docker access and Node installed, because the workflows use actions/checkout@v4.
Create repository secrets for registry push access:
REGISTRY_USER
REGISTRY_TOKEN
REGISTRY_TOKEN should be a Forgejo token that can push packages to infra/runner-images.
Each workflow pushes both the moving tag configured in IMAGE and an immutable tag formed as ${IMAGE}-${GITHUB_SHA}.
The workflows also set OCI metadata using Forgejo/Gitea-compatible environment variables:
GITHUB_SERVER_URL
GITHUB_REPOSITORY
GITHUB_SHA
GITHUB_REF_NAME
Runner labels
After the images are published and tested, configure the Forgejo runner labels in NixOS with immutable tags like this:
[
"nix:docker://git.hayshin.dev/infra/runner-images/nix:latest-<tested-sha>"
"rust:docker://git.hayshin.dev/infra/runner-images/rust:1-<tested-sha>"
"go:docker://git.hayshin.dev/infra/runner-images/go:1-<tested-sha>"
"python-3.14:docker://git.hayshin.dev/infra/runner-images/python:3.14-<tested-sha>"
"pnpm:docker://git.hayshin.dev/infra/runner-images/pnpm:22-<tested-sha>"
"uv:docker://git.hayshin.dev/infra/runner-images/uv:latest-<tested-sha>"
]
Workflows can then target the labels directly:
jobs:
test:
runs-on: rust
steps:
- uses: actions/checkout@v4
- run: rustc --version