9a368986b2
Switch to host-mode labels and document the DinD limitation: Autopilot's Warden blocks privileged containers at the node level. Use internal Gitea service URL (gitea.gitea.svc.cluster.local) to bypass Cloudflare Access. Document three resolution paths (Standard node pool, Cloud Build, external Docker TCP). GCE VM runner remains active in the interim.
115 lines
4.1 KiB
YAML
115 lines
4.1 KiB
YAML
---
|
|
# Gitea Actions runner on GKE Autopilot.
|
|
#
|
|
# Architecture:
|
|
# - init container registers the runner with Gitea (--no-interactive, idempotent)
|
|
# - main container runs act_runner daemon
|
|
#
|
|
# LIMITATION: GKE Autopilot does not allow privileged containers, so Docker-in-Docker
|
|
# (DinD) is not available. The runner uses "host" label mode, which runs steps
|
|
# directly inside the runner pod container rather than spawning Docker containers.
|
|
# forgejo-runner v11 still requires a Docker daemon to start — this deployment
|
|
# will fail until one of the following is resolved:
|
|
#
|
|
# Option A (recommended): Switch to a GKE Standard node pool for the ci namespace.
|
|
# Add a standard node pool with sandbox.config.sandboxType=gvisor or allow
|
|
# privileged pods on specific node pools.
|
|
#
|
|
# Option B: Use Cloud Build for docker build steps; use this runner for shell steps.
|
|
# Requires forking all workflow files to remove docker steps.
|
|
#
|
|
# Option C: Point docker_host at an external Docker TCP daemon (e.g., on the GCE runner VM).
|
|
#
|
|
# Until resolved, the existing GCE VM runner (gitea-runner-1 in us-central1-a)
|
|
# handles CI jobs. This deployment is a placeholder for when privileged pods are available.
|
|
#
|
|
# The ci namespace has pod-security.kubernetes.io/enforce: privileged set
|
|
# (see namespace.yaml) but Autopilot's Warden enforces this at the node level.
|
|
apiVersion: apps/v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: gitea-runner
|
|
namespace: ci
|
|
labels:
|
|
app: gitea-runner
|
|
spec:
|
|
replicas: 1
|
|
selector:
|
|
matchLabels:
|
|
app: gitea-runner
|
|
template:
|
|
metadata:
|
|
labels:
|
|
app: gitea-runner
|
|
spec:
|
|
serviceAccountName: gitea-runner
|
|
securityContext:
|
|
runAsNonRoot: false
|
|
initContainers:
|
|
- name: register
|
|
image: us-central1-docker.pkg.dev/neuron-785695/neuron-ci/ci-base:latest
|
|
command: ["/bin/sh", "-c"]
|
|
args:
|
|
- |
|
|
# Idempotent registration — skip if already registered (.runner file exists).
|
|
if [ -f /data/.runner ]; then
|
|
echo "Runner already registered, skipping."
|
|
else
|
|
act_runner register \
|
|
--instance "${GITEA_INSTANCE_URL}" \
|
|
--token "${GITEA_RUNNER_REGISTRATION_TOKEN}" \
|
|
--name "gke-runner-$(hostname)" \
|
|
--labels "ubuntu-latest:host,ubuntu-24.04:host,linux,x64" \
|
|
--no-interactive
|
|
fi
|
|
cat > /data/config.yaml << 'CONFIGEOF'
|
|
runner:
|
|
capacity: 2
|
|
timeout: 3h
|
|
envs:
|
|
BASH_ENV: "/usr/local/bin/git-ssh-init.sh"
|
|
container:
|
|
# GKE Autopilot blocks privileged DinD — steps run directly
|
|
# in the runner container (host mode). Labels use :host suffix.
|
|
network: host
|
|
docker_host: "-"
|
|
force_pull: false
|
|
valid_volumes: []
|
|
CONFIGEOF
|
|
env:
|
|
# Use the internal Gitea service to avoid Cloudflare Access auth.
|
|
# Gitea is in the same GKE cluster — use the ClusterIP service.
|
|
- name: GITEA_INSTANCE_URL
|
|
value: "http://gitea.gitea.svc.cluster.local:80"
|
|
envFrom:
|
|
- secretRef:
|
|
name: gitea-runner-token
|
|
volumeMounts:
|
|
- mountPath: /data
|
|
name: data
|
|
workingDir: /data
|
|
containers:
|
|
- name: runner
|
|
image: us-central1-docker.pkg.dev/neuron-785695/neuron-ci/ci-base:latest
|
|
command: ["act_runner", "daemon", "--config", "/data/config.yaml"]
|
|
env:
|
|
- name: GITEA_INSTANCE_URL
|
|
value: "http://gitea.gitea.svc.cluster.local:80"
|
|
envFrom:
|
|
- secretRef:
|
|
name: gitea-runner-token
|
|
resources:
|
|
requests:
|
|
cpu: "500m"
|
|
memory: "512Mi"
|
|
limits:
|
|
cpu: "4"
|
|
memory: "4Gi"
|
|
volumeMounts:
|
|
- mountPath: /data
|
|
name: data
|
|
workingDir: /data
|
|
volumes:
|
|
- name: data
|
|
emptyDir: {}
|