No description
  • Shell 66.8%
  • Go Template 24.3%
  • Dockerfile 8.9%
Find a file
2026-06-07 22:22:57 -05:00
templates Fix: use host-gateway for Docker access in DinD job containers 2026-06-04 23:35:07 -05:00
.dockerignore Initial commit: Forgejo Runner DinD image and Helm chart 2026-06-04 12:18:50 -05:00
Chart.yaml Initial commit: Forgejo Runner DinD image and Helm chart 2026-06-04 12:18:50 -05:00
Dockerfile Fix: add runner.envs.DOCKER_HOST to enable Docker access in job containers 2026-06-04 22:23:12 -05:00
entrypoint.sh Fix: bind dockerd to 0.0.0.0:2375 for host-gateway access 2026-06-05 00:27:30 -05:00
forgejo-runner-dind-0.1.0.tgz Fix: add runner.envs.DOCKER_HOST to enable Docker access in job containers 2026-06-04 22:23:12 -05:00
index.yaml Fix: add runner.envs.DOCKER_HOST to enable Docker access in job containers 2026-06-04 22:23:12 -05:00
README.md Fix: use host-gateway for Docker access in DinD job containers 2026-06-04 23:35:07 -05:00
values.yaml chore: update runner image tag to 12.7.5 2026-06-07 22:22:57 -05:00

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 release (v12.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

  • Base: docker:27-dind

The image extends docker:27-dind with the forgejo-runner binary downloaded directly from the official releases.

Entrypoint

The entrypoint script (entrypoint.sh):

  1. Starts dockerd on tcp://127.0.0.1:2375 with the configured storage driver
  2. Waits for Docker daemon readiness
  3. Registers the runner with Forgejo (if not already registered)
  4. 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

Docker access in job containers

The runner config uses a two-part approach for DinD in a single container:

container:
  docker_host: tcp://127.0.0.1:2375         # runner connects to Docker locally
  privileged: true
  options: "--add-host=host-gateway:host-gateway"  # DNS for job containers

runner:
  envs:
    DOCKER_HOST: tcp://host-gateway:2375   # passed into job containers
  • container.docker_host: tcp://127.0.0.1:2375 — the runner process connects to Docker on its own loopback
  • runner.envs.DOCKER_HOST: tcp://host-gateway:2375 — job containers reach the DinD daemon via Docker's host-gateway special DNS
  • options: --add-host=host-gateway:host-gateway — ensures host-gateway resolves inside job containers

Why not automount? In DinD, the Docker socket is inside the container, not on the host. automount only works when the socket is on the actual host filesystem. Why not tcp://127.0.0.1:2375 for job containers? 127.0.0.1 in a job container points to itself, not the runner pod.

Security considerations

  • Privileged pods: The container runs with privileged: true for 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/tolerations to pin runners to worker nodes.
  • Ephemeral storage: By default uses emptyDir; use PVC-backed /var/lib/docker for large builds.

Troubleshooting

Runner not picking up jobs

  1. Verify labels match: kubectl exec <pod> -- forgejo-runner list-labels
  2. Check registration: kubectl exec <pod> -- cat /data/.runner
  3. Verify Forgejo instance URL: kubectl exec <pod> -- env | grep FORGEJO

Docker not ready

  1. Check dockerd logs: kubectl logs <pod>
  2. Verify storage driver: kubectl exec <pod> -- docker info | grep Storage
  3. Check node supports overlay2: kubectl exec --privileged <node-pod> -- modprobe overlay

Jobs fail with "Cannot connect to the Docker daemon"

Verify the config has both parts:

container:
  docker_host: tcp://127.0.0.1:2375
  options: "--add-host=host-gateway:host-gateway"

runner:
  envs:
    DOCKER_HOST: tcp://host-gateway:2375
  • Check the runner can reach Docker: kubectl exec <pod> -- docker info
  • Check job container env: kubectl exec <pod> -- cat /data/config.yaml | grep DOCKER_HOST
  • 127.0.0.1 in a job container = itself, host-gateway = the pod's network interface

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