## Summary - Reorder CI/CD bootstrap phases to address chicken-and-egg problem - P2 is now "Custom Runner Image" (stock runner lacks Node.js) - Add P3 for "Mirror Forgejo & Build from Source" - Rename P3 -> P4 (Self-Deploy), P4 -> P5 (Container Builds) - Add Dockerfile for custom runner with Node.js, npm, docker, build tools - Update overview with new phase structure, host mode notes, and cross-compilation challenge ## Key Changes ### Phase Reordering | Old | New | Name | |-----|-----|------| | P1 | P1 | Enable Actions (complete) | | P2 | P2 | **Custom Runner Image** (new focus) | | - | P3 | **Mirror Forgejo & Build** (new) | | P3 | P4 | Self-Deploy | | P4 | P5 | Container Builds | ### Custom Runner Dockerfile The stock `forgejo/runner:3.5.1` image lacks Node.js, so `actions/checkout@v4` doesn't work. The new Dockerfile adds: - Node.js + npm (for GitHub Actions) - Docker CLI (for container builds) - Build tools (gcc, make, curl, jq) ### Bootstrap Strategy 1. Build custom runner image manually on gilbert (podman build) 2. Push to zot registry 3. Update deployment to use custom image 4. Then enable auto-build workflow for runner ## Deployment and Testing - [x] Review plan changes - [x] Build custom runner image manually and verify - [x] Update runner deployment - [x] Test `actions/checkout@v4` works 🤖 Generated with [Claude Code](https://claude.com/claude-code) Reviewed-on: https://forge.tail8d86e.ts.net/eblume/blumeops/pulls/50
8.7 KiB
Phase 2: Custom Runner Image
Goal: Build a custom forgejo-runner image with necessary tools, enabling standard GitHub Actions
Status: Complete (2026-01-23)
Prerequisites: Phase 1 complete (Actions enabled, runner deployed in host mode)
Problem Statement
The stock code.forgejo.org/forgejo/runner:3.5.1 image lacks tools needed for standard GitHub Actions:
- Node.js - Required by most actions (checkout, setup-*, etc.)
- Git - For repository operations (present but minimal)
- Common build tools - make, gcc, curl, jq, etc.
In host mode, jobs run directly in the runner container, so these tools must be pre-installed.
Chicken-and-Egg Problem
We can't use actions/checkout@v4 to build the custom runner because that action requires Node.js, which we don't have yet. Solution: Bootstrap manually, then automate.
Step 1: Create Dockerfile for Custom Runner
Create argocd/manifests/forgejo-runner/Dockerfile:
FROM code.forgejo.org/forgejo/runner:3.5.1
# The base image is Debian-based
# Install tools needed for GitHub Actions and builds
RUN apt-get update && apt-get install -y --no-install-recommends \
# Required for actions/checkout and other Node-based actions
nodejs \
npm \
# Build essentials
git \
curl \
wget \
jq \
make \
gcc \
g++ \
# For container builds (if we add Docker-in-Docker later)
ca-certificates \
&& rm -rf /var/lib/apt/lists/*
# Verify Node.js is available
RUN node --version && npm --version
Step 2: Bootstrap - Build Image Manually
Since we can't use CI yet, build the image manually on gilbert and push to zot.
2.1 Build with Podman
cd ~/code/personal/blumeops/argocd/manifests/forgejo-runner
# Build for linux/arm64 (minikube on M1 Mac)
podman build --platform linux/arm64 -t registry.tail8d86e.ts.net/blumeops/forgejo-runner:latest .
# Push to zot (no auth required)
podman push registry.tail8d86e.ts.net/blumeops/forgejo-runner:latest
2.2 Verify Image in Registry
curl -s https://registry.tail8d86e.ts.net/v2/blumeops/forgejo-runner/tags/list | jq .
Step 3: Update Runner Deployment
3.1 Update deployment.yaml
Change the image from stock to custom:
# Before
image: code.forgejo.org/forgejo/runner:3.5.1
# After
image: registry.tail8d86e.ts.net/blumeops/forgejo-runner:latest
3.2 Update kustomization.yaml
Add Dockerfile to resources (for reference, not deployed):
# Note: Dockerfile is for building, not k8s deployment
# It lives here for co-location with the runner manifests
3.3 Sync Deployment
argocd app sync forgejo-runner
# Verify new image is running
kubectl --context=minikube-indri -n forgejo-runner get pods -o jsonpath='{.items[*].spec.containers[*].image}'
Step 4: Test with Real GitHub Action
Now that we have Node.js, test with actions/checkout@v4.
4.1 Update Test Workflow
Update .forgejo/workflows/test.yml:
name: Test CI
on:
push:
branches: [main]
pull_request:
workflow_dispatch:
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Verify tools
run: |
echo "Node.js: $(node --version)"
echo "npm: $(npm --version)"
echo "Git: $(git --version)"
echo "Make: $(make --version | head -1)"
- name: Show repo info
run: |
echo "Repository: ${{ github.repository }}"
echo "Branch: ${{ github.ref_name }}"
ls -la
4.2 Push and Verify
git add .forgejo/workflows/test.yml
git commit -m "Test checkout action with custom runner"
git push
Check https://forge.tail8d86e.ts.net/eblume/blumeops/actions - should see successful run with actions/checkout@v4.
Step 5: Create Auto-Build Workflow for Runner
Now that Actions work properly, create a workflow to rebuild the runner image automatically.
5.1 Create Build Workflow
Create .forgejo/workflows/build-runner.yml:
name: Build Runner Image
on:
push:
paths:
- 'argocd/manifests/forgejo-runner/Dockerfile'
- '.forgejo/workflows/build-runner.yml'
workflow_dispatch:
env:
REGISTRY: registry.tail8d86e.ts.net
IMAGE_NAME: blumeops/forgejo-runner
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build image
run: |
cd argocd/manifests/forgejo-runner
# Use docker build (available in runner container)
# Note: This builds for the runner's native arch
docker build -t ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} .
docker tag ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} \
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
- name: Push to registry
run: |
# Zot has no auth, just push
docker push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
docker push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
- name: Verify push
run: |
curl -sf "https://${{ env.REGISTRY }}/v2/${{ env.IMAGE_NAME }}/tags/list" | jq .
echo "Image pushed: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}"
5.2 Note on Docker-in-Docker
The runner runs in host mode, so we need Docker CLI available. Options:
- Add Docker CLI to the custom image (see Dockerfile update below)
- Mount Docker socket from minikube (requires deployment change)
- Use Podman instead (rootless, no socket needed)
For now, we'll add Docker CLI to the image and mount the socket.
5.3 Update Dockerfile for Docker Builds
FROM code.forgejo.org/forgejo/runner:3.5.1
RUN apt-get update && apt-get install -y --no-install-recommends \
nodejs \
npm \
git \
curl \
wget \
jq \
make \
gcc \
g++ \
ca-certificates \
# Docker CLI for building container images
docker.io \
&& rm -rf /var/lib/apt/lists/*
RUN node --version && npm --version && docker --version
5.4 Update Deployment for Docker Socket
Add Docker socket mount to deployment.yaml:
volumeMounts:
- name: runner-data
mountPath: /data
- name: runner-config
mountPath: /config
- name: docker-sock
mountPath: /var/run/docker.sock
volumes:
- name: runner-data
emptyDir: {}
- name: runner-config
configMap:
name: forgejo-runner-config
- name: docker-sock
hostPath:
path: /var/run/docker.sock
type: Socket
Step 6: Verification
6.1 Manual Image Build Works
# On gilbert
podman build --platform linux/arm64 -t registry.tail8d86e.ts.net/blumeops/forgejo-runner:test .
podman push registry.tail8d86e.ts.net/blumeops/forgejo-runner:test
6.2 Runner Uses Custom Image
kubectl --context=minikube-indri -n forgejo-runner get pods -o jsonpath='{.items[*].spec.containers[*].image}'
# Should show: registry.tail8d86e.ts.net/blumeops/forgejo-runner:latest
6.3 GitHub Actions Work
actions/checkout@v4succeeds- Test workflow shows Node.js, npm, git versions
6.4 Auto-Build Workflow Works
Push a change to the Dockerfile and verify:
- Workflow triggers
- Image builds successfully
- Image pushed to zot
Verification Checklist
- Dockerfile created for custom runner (Alpine-based with apk)
- Image built manually on gilbert (podman build)
- Image pushed to zot registry
- Runner deployment updated to use custom image
- Runner pod running with new image
actions/checkout@v4works in test workflow- Auto-build workflow created (deferred - needs Docker socket)
- Docker socket mounted (for container builds)
- Auto-build workflow successfully rebuilds runner
Troubleshooting
Image Pull Fails in Minikube
Minikube needs to be able to pull from zot. Check registry mirror config:
ssh indri 'minikube ssh -- cat /etc/containerd/certs.d/registry.tail8d86e.ts.net/hosts.toml'
Docker Build Fails in Workflow
If Docker socket mount doesn't work:
- Check socket exists in minikube:
minikube ssh -- ls -la /var/run/docker.sock - Check permissions: runner may need to be in docker group
- Alternative: Use
podman(rootless) instead of Docker
Node.js Actions Still Fail
Ensure the runner pod restarted after image update:
kubectl --context=minikube-indri -n forgejo-runner rollout restart deployment/forgejo-runner
kubectl --context=minikube-indri -n forgejo-runner logs -f deployment/forgejo-runner
Next Phase
Once the custom runner is working with auto-build, proceed to Phase 3: Mirror Forgejo & Build to set up Forgejo source builds.