--- # 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: # Set to 0 until the DinD/privileged-pod blocker is resolved (see comments above). # Change to 1 when a Docker daemon is available (Standard node pool or external TCP). replicas: 0 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: {}