Merge pull request 'fix(ci): use compatible DinD runner' (#3) from fix/gitea-runner-dind into main
lint / terraform (push) Has been cancelled
lint / yaml (push) Has been cancelled
lint / ansible (push) Has been cancelled

Reviewed-on: #3
This commit was merged in pull request #3.
This commit is contained in:
2026-09-09 17:49:29 +00:00
4 changed files with 22 additions and 18 deletions
+1 -1
View File
@@ -26,7 +26,7 @@ What changed in this homelab, when, and why. Newest first.
| secrets | Recorded that ESO 2.8.0, five ExternalSecrets and the scoped OpenBao Kubernetes-auth path already exist; the next gate is live recovery testing and migration of any remaining manual Secrets |
| Terraform | Recorded Gitea 1.27 State Registry as the preferred candidate for local roots after version and recovery testing; the OCI recovery root remains in OCI Object Storage to avoid a home-control-plane dependency loop |
| cleanup | Removed the retired NapCat tree, the Contour and Kanidm archive trees, and seven generated Terraform plan files before establishing the clean Git baseline; plans may embed complete state and remain globally ignored |
| CI | Added a review-first Gitea Actions runner bootstrap: official actions chart 0.1.1, pinned runner 2.3.0, one persistent Kubernetes runner with capacity four and rootless DinD, plus an ESO reference to a repository-scoped registration token in OpenBao. It is not deployed until the PR is merged |
| CI | Added a review-first Gitea Actions runner bootstrap: official actions chart 0.1.1, pinned runner 2.3.0, one persistent instance-scoped Kubernetes runner with capacity four, plus an ESO reference to its registration token in OpenBao. The first deployment proved that rootlesskit is blocked by the node's AppArmor unprivileged-userns policy; because the chart requires privileged DinD in either mode, the reviewed fix uses regular DinD instead of weakening the host-wide policy |
| identity | Declared the Samba AD `gitea-admins` group with `panxiao81` as its initial member. Gitea already maps this OIDC group to site administrators; the local `gitea_admin` account remains as break-glass access |
`Carried forward`: re-verify OpenBao/ESO recovery and remaining Secret inventory;
+7 -5
View File
@@ -90,11 +90,13 @@ Gitea Actions is the CI control plane. It integrates directly with repository
permissions and status checks and preserves GitHub Actions workflow syntax.
The bootstrap worker is the official Gitea Runner chart in Kubernetes: one
persistent StatefulSet Pod, rootless Docker-in-Docker and capacity four. Job
persistent StatefulSet Pod, Docker-in-Docker and capacity four. Job
containers are dynamic, while the runner and its Docker daemon remain resident.
Rootless DinD still needs a privileged Pod to establish its user namespace, so
the runner is repository-scoped and restricted to trusted workflows. See
`platform/gitea-runner/`.
The chart's DinD container is privileged in both modes. Rootless mode is blocked
by the node's AppArmor unprivileged-userns policy, so regular DinD avoids weakening
that host-wide policy without pretending the Pod has a stronger isolation boundary.
The runner is instance-scoped and restricted to trusted repositories and workflows.
See `platform/gitea-runner/`.
This is not native pod-per-job execution. If stronger isolation becomes useful,
the runner's ephemeral registration and Gitea `workflow_job` webhook can later
@@ -113,7 +115,7 @@ Proxmox provider exists, so ephemeral Proxmox VMs would mean writing one.
Bootstrap dependencies and current status:
1. **Secret delivery exists.** OpenBao and External Secrets Operator already
synchronize five Secrets. Add the repository-scoped runner registration token
synchronize five Secrets. Add the instance-scoped runner registration token
at `kv/k8s/gitea-runner`; Git contains only its `ExternalSecret` reference.
2. **Git remote exists.** `homelab-infra` is hosted in Gitea. An off-cluster
read-only mirror remains required for disaster recovery.
+10 -4
View File
@@ -2,9 +2,14 @@
This is the bootstrap runner for Gitea Actions. One persistent runner Pod accepts
up to four jobs; each job runs in a dynamically created container inside a
rootless Docker-in-Docker daemon. Rootless DinD still requires a privileged Pod
to create its user namespace, so this runner is restricted to this repository
and trusted workflows.
Docker-in-Docker daemon. The official chart runs DinD privileged. Rootless DinD
would still be privileged and is blocked by the node's AppArmor user-namespace
policy, so this deployment uses regular DinD instead of weakening that host-wide
policy. Only trusted workflows may target this runner.
The runner is registered at instance scope so it is available to every repository
on this Gitea instance. Repository permissions and protected-branch review are
therefore the security boundary; do not enable Actions for untrusted repositories.
The runner registration token is authoritative in OpenBao at
`kv/k8s/gitea-runner`. External Secrets Operator projects its `token` property to
@@ -16,7 +21,8 @@ command line.
This is a one-time manual deployment because Flux is not installed yet:
1. Merge the reviewed PR.
2. Create a repository-scoped runner registration token in Gitea.
2. As a Gitea site administrator, create an instance-scoped runner registration
token under **Site Administration → Actions → Runners**.
3. Store it as the `token` property at `kv/k8s/gitea-runner` without exposing it
in shell history:
+4 -8
View File
@@ -44,14 +44,10 @@ statefulset:
docker_timeout: 300s
dind:
rootless: true
uid: 1000
# The node enforces AppArmor's unprivileged-userns restriction, which blocks
# rootlesskit even though this chart must run DinD privileged either way.
rootless: false
registry: docker.io
repository: docker
tag: 29.7.1-dind-rootless
tag: 29.7.1-dind
pullPolicy: IfNotPresent
extraEnvs:
- name: DOCKERD_ROOTLESS_ROOTLESSKIT_NET
value: slirp4netns
- name: DOCKERD_ROOTLESS_ROOTLESSKIT_MTU
value: "65520"