No description
- Go Template 42.7%
- Shell 42.2%
- Dockerfile 15.1%
| templates | ||
| .dockerignore | ||
| Chart.yaml | ||
| Dockerfile | ||
| entrypoint.sh | ||
| forgejo-runner-dind-0.1.0.tgz | ||
| README.md | ||
| values.yaml | ||
Forgejo Runner DinD
Custom container image and Helm chart for running Forgejo Actions runners on Kubernetes with rootful Docker-in-Docker support.
Overview
This project provides:
- Custom container image combining Forgejo Runner with rootful Docker-in-Dind (DinD) in a single container.
- Helm chart for deploying the runner as a Kubernetes Deployment.
The image is designed for docker build / docker push workflows where the runner needs its own Docker daemon.
Architecture
┌─────────────────────────────────────────────┐
│ Kubernetes Pod (privileged) │
│ │
│ ┌───────────────────────────────────────┐ │
│ │ Custom Image: forgejo-runner-dind │ │
│ │ │ │
│ │ ┌─────────────┐ ┌────────────────┐ │ │
│ │ │ forgejo- │ │ dockerd │ │ │
│ │ │ runner │ │ (rootful DinD) │ │ │
│ │ │ daemon │ │ │ │ │
│ │ │ │ │ :2375 (127.0.0.1)│ │ │
│ │ └─────────────┘ └────────────────┘ │ │
│ │ │ │
│ │ DOCKER_HOST=tcp://127.0.0.1:2375 │ │
│ └───────────────────────────────────────┘ │
└─────────────────────────────────────────────┘
Components
| Component | Source |
|---|---|
forgejo-runner |
Official Forgejo Runner image (data.forgejo.org/forgejo/runner:12.7.3) |
| Docker daemon | docker:27-dind |
| Runtime | tini (init system) |
| Tools | git, bash, curl, jq, coreutils, ca-certificates |
Container Image
Building
docker build -t git.home-net.work/sjenkins/forgejo-runner-dind:12.7.3 .
Base image
- Final stage:
docker:27-dind - Source stage:
data.forgejo.org/forgejo/runner:12.7.3
The multi-stage build copies the forgejo-runner binary from the official runner image into the DinD base.
Entrypoint
The entrypoint script (entrypoint.sh):
- Starts
dockerdontcp://127.0.0.1:2375with the configured storage driver - Waits for Docker daemon readiness
- Registers the runner with Forgejo (if not already registered)
- Starts
forgejo-runner daemon
Helm Chart
Prerequisites
- Kubernetes 1.25+
- Helm 3.x
- A Forgejo instance with Actions enabled
- A runner registration token from your Forgejo instance
Installation
Using an existing secret
helm install forgejo-runner ./ \
--set forgejo.instanceUrl=https://git.home-net.work \
--set forgejo.existingSecret=my-forgejo-secret \
--set runner.labels="docker:docker://node:20-bookworm" \
--set image.repository=git.home-net.work/sjenkins/forgejo-runner-dind \
--set image.tag=12.7.3 \
--namespace forgejo-runners \
--create-namespace
Using chart-generated secret
helm install forgejo-runner ./ \
--set forgejo.instanceUrl=https://git.home-net.work \
--set forgejo.registrationToken="your-registration-token-here" \
--set runner.labels="docker:docker://node:20-bookworm" \
--set image.repository=git.home-net.work/sjenkins/forgejo-runner-dind \
--set image.tag=12.7.3 \
--namespace forgejo-runners \
--create-namespace
Configuration
See values.yaml for all available options. Key configuration:
| Parameter | Description | Default |
|---|---|---|
image.repository |
Container image repository | git.home-net.work/sjenkins/forgejo-runner-dind |
image.tag |
Container image tag | 12.7.3 |
forgejo.instanceUrl |
Forgejo instance URL | https://git.home-net.work |
forgejo.existingSecret |
Existing secret name for registration token | "" |
forgejo.registrationToken |
Registration token (if no existing secret) | "" |
runner.labels |
Runner labels for job matching | docker:docker://node:20-bookworm |
runner.name |
Runner name (empty = pod hostname) | "" |
docker.storageDriver |
Docker storage driver | overlay2 |
persistence.docker.enabled |
Use PVC for Docker graph | false |
persistence.runner.enabled |
Use PVC for runner data | false |
nodeSelector |
Node selector for pod placement | {} |
tolerations |
Tolerations for pod placement | [] |
Example workflow
name: build
on:
push:
branches:
- main
jobs:
docker-build:
runs-on: docker
steps:
- uses: actions/checkout@v4
- name: Docker info
run: docker info
- name: Login
run: echo "$REGISTRY_PASSWORD" | docker login git.home-net.work -u "$REGISTRY_USERNAME" --password-stdin
- name: Build
run: docker build -t git.home-net.work/sjenkins/example:latest .
- name: Push
run: docker push git.home-net.work/sjenkins/example:latest
Security considerations
- Privileged pods: The container runs with
privileged: truefor rootful DinD. - Docker daemon: Bound to
127.0.0.1:2375, not exposed externally. - TLS disabled:
DOCKER_TLS_CERTDIR=""disables DinD TLS (set a directory to enable). - Dedicated namespace: Recommended to isolate runners in a separate namespace.
- Dedicated nodes: Use
nodeSelector/tolerationsto pin runners to worker nodes. - Ephemeral storage: By default uses
emptyDir; use PVC-backed/var/lib/dockerfor large builds.
Troubleshooting
Runner not picking up jobs
- Verify labels match:
kubectl exec <pod> -- forgejo-runner list-labels - Check registration:
kubectl exec <pod> -- cat /data/.runner - Verify Forgejo instance URL:
kubectl exec <pod> -- env | grep FORGEJO
Docker not ready
- Check dockerd logs:
kubectl logs <pod> - Verify storage driver:
kubectl exec <pod> -- docker info | grep Storage - Check node supports overlay2:
kubectl exec --privileged <node-pod> -- modprobe overlay
Consuming the Chart
The chart is published to the Forgejo Helm package registry.
Add the repository
helm repo add forgejo-runner-dind --username <user> --password <token> \
https://git.home-net.work/api/packages/sjenkins/helm
Update and install
helm repo update
helm search repo forgejo-runner-dind
helm install forgejo-runner forgejo-runner-dind/forgejo-runner-dind \
--set forgejo.instanceUrl=https://git.home-net.work \
--set forgejo.registrationToken=<token> \
--namespace forgejo-runners \
--create-namespace
Repository Structure
.
├── Chart.yaml # Helm chart metadata
├── Dockerfile # Multi-stage Docker image definition
├── entrypoint.sh # Container entrypoint script
├── values.yaml # Helm chart default values
├── templates/
│ ├── _helpers.tpl # Helm template helpers
│ ├── deployment.yaml # Kubernetes Deployment
│ ├── secret.yaml # Registration token secret
│ ├── configmap.yaml # Optional ConfigMap
│ └── serviceaccount.yaml # Optional ServiceAccount
└── README.md