Author SHA1 Message Date
rock 038cf40fe5 ci: temporarily revert runners to public images to bootstrap custom image build 2026-09-07 09:17:04 -07:00
rock fcf60cc546 ci: improve runner image build workflow - always run + manual trigger + weekly schedule
Build & Push Runner Images / Build & Push All Runner Images (push) Canceled after 0s
2026-09-07 09:15:44 -07:00
rock 8f197fcc23 ci: update runner daemon images to custom runner images (enables Image Updater tracking) 2026-09-07 09:11:45 -07:00
rock f253731cb9 ci: add docker.io to custom runner images
Build Runner Images / Build and Push Runner Images (push) Failing after 1m0s
2026-09-07 09:09:59 -07:00
rock 32ef4eae0e ci: add custom runner images with Node.js pre-installed
Build Runner Images / Build and Push Runner Images (push) Failing after 58s
2026-09-07 09:08:10 -07:00
rock f521763292 docs: add unified CI workflow pattern to shareable template 2026-09-06 23:19:27 -07:00
rock 326be2e057 fix: always re-register runner to keep labels in sync (#2)
## Problem

Init container skips registration if `.runner` file exists on PVC:
```
test -f /data/.runner || forgejo-runner register ...
```

This means changing runner labels in `values.yaml` (e.g. the label image fix from PR #1) has **no effect** until PVCs are manually deleted — not GitOps-friendly.

## Fix

Always delete `.runner` and re-register on every pod start:
```
rm -f /data/.runner
forgejo-runner register --no-interactive ...
```

Labels now stay in sync with `values.yaml` automatically. ArgoCD syncs → pods restart → init re-registers with current labels.

## Files Changed

- `k8s/infra/forgejo-runner/templates/deployment.yaml` (init container logic)

## After Merge

ArgoCD syncs → deployment spec changes → pods restart → init re-registers with new labels from PR #1 → CI works across all repos.Reviewed-on: #2

Co-authored-by: rock <[email protected]>
2026-09-07 05:27:30 +00:00
6 changed files with 222 additions and 1 deletions
+93
View File
@@ -0,0 +1,93 @@
name: Build & Push Runner Images
on:
push:
branches: [main]
workflow_dispatch: # Manual trigger
schedule:
- cron: '0 2 * * 0' # Weekly on Sunday 2 AM UTC (ensure fresh images)
env:
REGISTRY: forgejo.riotpiao.com
jobs:
build-runner-images:
name: Build & Push All Runner Images
runs-on: golang
steps:
- name: Install Node.js and Docker
run: |
apt-get update
apt-get install -y nodejs docker.io
- name: Checkout code
uses: actions/checkout@v4
- name: Get short SHA
id: sha
run: |
SHORT_SHA=$(git rev-parse --short HEAD)
echo "short_sha=${SHORT_SHA}" >> $GITHUB_OUTPUT
- name: Registry login
run: |
echo "${REGISTRY_TOKEN}" | docker login "${REGISTRY}" \
--username "${REGISTRY_USER}" --password-stdin
env:
REGISTRY_USER: ${{ secrets.FORGEJO_REGISTRY_USER }}
REGISTRY_TOKEN: ${{ secrets.FORGEJO_REGISTRY_TOKEN }}
- name: Build and push Golang runner image
run: |
IMAGE="${REGISTRY}/rock/forgejo-runner-golang"
echo "Building: ${IMAGE}:${{ steps.sha.outputs.short_sha }}"
docker build --no-cache \
-f k8s/infra/forgejo-runner-images/Dockerfile.golang \
-t "${IMAGE}:${{ steps.sha.outputs.short_sha }}" \
-t "${IMAGE}:latest" \
.
docker push "${IMAGE}:${{ steps.sha.outputs.short_sha }}"
docker push "${IMAGE}:latest"
echo "✓ Pushed golang runner"
- name: Build and push Node runner image
run: |
IMAGE="${REGISTRY}/rock/forgejo-runner-node"
echo "Building: ${IMAGE}:${{ steps.sha.outputs.short_sha }}"
docker build --no-cache \
-f k8s/infra/forgejo-runner-images/Dockerfile.node \
-t "${IMAGE}:${{ steps.sha.outputs.short_sha }}" \
-t "${IMAGE}:latest" \
.
docker push "${IMAGE}:${{ steps.sha.outputs.short_sha }}"
docker push "${IMAGE}:latest"
echo "✓ Pushed node runner"
- name: Build and push Rust runner image
run: |
IMAGE="${REGISTRY}/rock/forgejo-runner-rust"
echo "Building: ${IMAGE}:${{ steps.sha.outputs.short_sha }}"
docker build --no-cache \
-f k8s/infra/forgejo-runner-images/Dockerfile.rust \
-t "${IMAGE}:${{ steps.sha.outputs.short_sha }}" \
-t "${IMAGE}:latest" \
.
docker push "${IMAGE}:${{ steps.sha.outputs.short_sha }}"
docker push "${IMAGE}:latest"
echo "✓ Pushed rust runner"
- name: Prune unused images
run: docker image prune -a --force 2>&1 | tail -3 || true
- name: Summary
run: |
echo "=== Runner Images Built and Pushed ==="
echo "✓ forgejo.riotpiao.com/rock/forgejo-runner-golang:latest"
echo "✓ forgejo.riotpiao.com/rock/forgejo-runner-node:latest"
echo "✓ forgejo.riotpiao.com/rock/forgejo-runner-rust:latest"
+92
View File
@@ -208,3 +208,95 @@ versions without warning in your own values file.
Grouping by layer (rather than by day or by "misc fixes") makes it much Grouping by layer (rather than by day or by "misc fixes") makes it much
easier to `git log --oneline -- <path>` your way back to *why* a given easier to `git log --oneline -- <path>` your way back to *why* a given
piece of config looks the way it does, months later. piece of config looks the way it does, months later.
## Unified Forgejo CI Workflow Pattern (Enforced 2026-09-07+)
All repositories MUST follow this exact structure. No variations.
```yaml
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
env:
REGISTRY: <your-registry-hostname>
IMAGE: <registry>/<org>/<service-name>
jobs:
test:
name: Test
runs-on: [golang|node|rust]
steps:
- name: Install Node.js for actions runtime
run: apt-get update && apt-get install -y nodejs
- name: Checkout code
uses: actions/checkout@v4
# Language-specific tests here (no docker, no registry)
# - name: Run tests
# run: npm test -- --run || true
build-push:
name: Build & Push Image
needs: test
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
runs-on: [golang|node|rust]
steps:
- name: Install Node.js and Docker
run: |
apt-get update
apt-get install -y nodejs docker.io
- name: Checkout code
uses: actions/checkout@v4
- name: Get short SHA
id: sha
run: |
SHORT_SHA=$(git rev-parse --short HEAD)
echo "short_sha=${SHORT_SHA}" >> $GITHUB_OUTPUT
- name: Registry login
run: |
echo "${REGISTRY_TOKEN}" | docker login "${REGISTRY}" \
--username "${REGISTRY_USER}" --password-stdin
env:
REGISTRY_USER: ${{ secrets.FORGEJO_REGISTRY_USER }}
REGISTRY_TOKEN: ${{ secrets.FORGEJO_REGISTRY_TOKEN }}
- name: Build Docker image
run: |
docker build --no-cache \
-t "${IMAGE}:${{ steps.sha.outputs.short_sha }}" \
-t "${IMAGE}:latest" \
.
- name: Push Docker image
run: |
docker push "${IMAGE}:${{ steps.sha.outputs.short_sha }}"
docker push "${IMAGE}:latest"
- name: Prune unused images
run: docker image prune -a --force 2>&1 | tail -3 || true
```
### Anti-Patterns (DO NOT USE)
-`container: image: golang:1.26` overrides — breaks docker socket sharing
- ❌ Conditional `if:` on individual steps — use separate jobs instead
- ❌ Installing docker.io in test job — only needed in build-push
- ❌ Monolithic job doing test + build + push — hard to debug
- ❌ Using `{{ github.sha }}` for image tag — use short commit SHA for readability
### How It Works
1. **PR to feature branch** → test job runs, build-push skipped, nothing pushed
2. **Push to main** → test runs, build-push runs after test passes, image pushed
3. Docker socket shared between dind sidecar and runner via emptyDir mount at `/run`
4. `docker_host: automount` in runner config injects socket into workflow containers
5. Secrets (FORGEJO_REGISTRY_USER, TOKEN) set in Forgejo repo settings, NOT in git
@@ -0,0 +1,12 @@
FROM golang:1.26-bookworm
# Install Node.js, npm, and Docker CLI
RUN apt-get update && apt-get install -y --no-install-recommends \
nodejs npm docker.io \
&& rm -rf /var/lib/apt/lists/*
# Verify installations
RUN go version && node --version && npm --version && docker --version
LABEL maintainer="homelab" \
description="Golang 1.26 + Node.js + Docker CLI pre-installed"
@@ -0,0 +1,12 @@
FROM node:22-bookworm
# Node.js already installed, add Docker CLI
RUN apt-get update && apt-get install -y --no-install-recommends \
docker.io \
&& rm -rf /var/lib/apt/lists/*
# Verify installations
RUN node --version && npm --version && docker --version
LABEL maintainer="homelab" \
description="Node.js 22 + Docker CLI pre-installed"
@@ -0,0 +1,12 @@
FROM rust:1-bookworm
# Add Node.js and Docker CLI
RUN apt-get update && apt-get install -y --no-install-recommends \
nodejs npm docker.io \
&& rm -rf /var/lib/apt/lists/*
# Verify installations
RUN rustc --version && cargo --version && node --version && npm --version && docker --version
LABEL maintainer="homelab" \
description="Rust 1 + Node.js + Docker CLI pre-installed"
+1 -1
View File
@@ -5,7 +5,7 @@ runner:
name: golang-runner name: golang-runner
# Label image is what workflow steps run in (NOT the runner daemon image). # Label image is what workflow steps run in (NOT the runner daemon image).
# golang:1.26-bookworm: Debian, root, apt-get, Go, git. # golang:1.26-bookworm: Debian, root, apt-get, Go, git.
# Install Node.js/docker in workflow steps as needed. # TODO: Switch to custom image once build-runner-images.yml pushes images
labels: "golang:docker://golang:1.26-bookworm" labels: "golang:docker://golang:1.26-bookworm"
forgejoUrl: http://forgejo-gitea-http.cicd.svc.cluster.local:3000 forgejoUrl: http://forgejo-gitea-http.cicd.svc.cluster.local:3000
tokenSecret: runner-token tokenSecret: runner-token