diff --git a/clusters/homelab/apps/gitea-actions.yaml b/clusters/homelab/apps/gitea-actions.yaml deleted file mode 100644 index 26c31a9..0000000 --- a/clusters/homelab/apps/gitea-actions.yaml +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: kustomize.toolkit.fluxcd.io/v1 -kind: Kustomization -metadata: - name: gitea-actions - namespace: flux-system -spec: - interval: 10m - path: ./platform/gitea-runner - prune: true - sourceRef: - kind: GitRepository - name: flux-system - timeout: 3m - wait: false diff --git a/clusters/homelab/kustomization.yaml b/clusters/homelab/kustomization.yaml index 7d55d8d..caaa4ae 100644 --- a/clusters/homelab/kustomization.yaml +++ b/clusters/homelab/kustomization.yaml @@ -7,7 +7,6 @@ resources: - apps/envoy-gateway.yaml - apps/external-secrets.yaml - apps/gitea.yaml - - apps/gitea-actions.yaml - apps/http-echo.yaml - apps/openebs.yaml - apps/nats.yaml diff --git a/platform/gitea-runner/README.md b/platform/gitea-runner/README.md deleted file mode 100644 index 7eb983e..0000000 --- a/platform/gitea-runner/README.md +++ /dev/null @@ -1,114 +0,0 @@ -# Gitea Actions runner - -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 -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. - -DinD 同时使用 `--mtu=1450` 和 -`--default-network-opt=bridge=com.docker.network.driver.mtu=1450`,与 k3s Pod 的 -`eth0` 一致。前者只覆盖 Docker 默认 bridge;act 为每个 job 创建 user-defined -bridge,必须由后者设置默认 MTU。不要在未验证节点 Pod MTU 的情况下删除或修改这 -两个参数:MTU 1500 的 job 容器虽然能够解析 GitHub、甚至建立 TCP 连接,但较大的 -TLS 数据包会在嵌套网络路径中丢失,表现为 `github.com` / `api.github.com` 超时或 -`setup-go` 每次请求卡满 6 分钟后重试。Pod 网络和默认 Docker bridge 正常不代表 -Actions job bridge 正常。 - -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 -the `gitea-runner-token` Secret. Never put the token in this directory or a Helm -command line. - -## SPIRE 与 OCI 发布 - -runner Pod 使用专用 ServiceAccount `gitea-actions`,并由精确匹配 namespace、 -ServiceAccount 隐含的 Pod、以及 chart labels 的 `ClusterSPIFFEID` 获得: - -```text -spiffe://ddupan.top/ci/gitea-actions -``` - -SPIFFE CSI socket 同时只读挂载到 runner 和 DinD。act 的 volume allowlist 只允许 -`/run/spire/agent-sockets`;workflow 仍必须在 job container 中显式请求该 bind -mount。原因是 bind mount 由 DinD 内的 dockerd 解析,只挂 runner 容器无法让 job -访问 Workload API。 - -该身份不是通用 registry 管理员。zot 只对明确列出的 CI 镜像仓库授予 -`read/create/update`,不授予 delete 或其他仓库写入。workflow 应获取 -`aud=zot` 的短期 JWT-SVID,并经 stdin 传给 registry client,不得把 JWT、X.509 -SVID 或 Docker auth 写入 workspace/artifact。 - -## Flux 接管状态 - -该 release 最初通过下述 review-first 流程手动 bootstrap。下一个 GitOps 阶段将 -使用 Flux `HelmRelease` 接管它,并首先固定现有 chart `0.1.1`,不在接管 PR 中升级。 - -迁移前审计发现:Helm 保存的 user-supplied values 和 release manifest 仍描述失败的 -rootless DinD 尝试,但 live StatefulSet 与本目录 `values.yaml` 都已经使用 regular -DinD。首次 reconcile 的验收条件是修正 Helm 存储状态,同时 live Pod spec、PVC -identity、runner capacity 和在线状态保持不变。接管稳定后再用独立 PR 升级 chart。 - -接管分两阶段:第一阶段提交 `suspend: true` 的 HelmRelease、HelmRepository 和由 -`values.yaml` 生成的 ConfigMap。Flux 只登记这些对象,不执行 Helm action。合并后 -检查 HelmRepository Ready,并用固定 chart 重复比较期望清单与 live StatefulSet; -第二阶段解除 suspend。第一阶段已经确认 source Ready、完整 chart render 与 live -资源零差异,且登记过程中现有 runner 没有 rollout。失败重试使用 -`RetryOnFailure`,不会用 stored rootless release 做 rollback。 - -## 历史 review-first bootstrap - -这是 Flux 安装前执行过的一次性手动部署流程,保留用于恢复和审计: - -1. Merge the reviewed PR. -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: - - ```bash - read -rsp 'Runner token: ' runner_token - printf '%s' "$runner_token" | bao kv put kv/k8s/gitea-runner token=- - unset runner_token - ``` - -4. From the updated `main`, create the namespace and ExternalSecret, then wait - for `SecretSynced=True`: - - ```bash - KUBECONFIG="$HOME/.kube/config" k3s kubectl apply \ - -f platform/gitea-runner/namespace.yaml - KUBECONFIG="$HOME/.kube/config" k3s kubectl apply \ - -f platform/gitea-runner/external-secret.yaml - KUBECONFIG="$HOME/.kube/config" k3s kubectl wait \ - --namespace gitea-actions \ - --for=condition=Ready externalsecret/gitea-runner-token \ - --timeout=60s - ``` - -5. Install chart `actions` version `0.1.1` from - `https://dl.gitea.com/charts/` with this `values.yaml`: - - ```bash - helm repo add gitea-charts https://dl.gitea.com/charts/ - helm repo update gitea-charts - helm upgrade --install gitea-actions gitea-charts/actions \ - --namespace gitea-actions \ - --version 0.1.1 \ - --values platform/gitea-runner/values.yaml \ - --wait --timeout 10m - ``` - -6. Confirm the runner is online, then re-run the queued lint workflow. - -Do not deploy from an unmerged feature branch. Do not use `--set` for the token. - -The 1 GiB PVC preserves `.runner` identity. Docker image layers are ephemeral; -the Pod has a 20 GiB ephemeral-storage limit. Terraform apply jobs must use a -workflow concurrency group because runner capacity does not serialize access to -a shared state. diff --git a/platform/gitea-runner/clusterspiffeid.yaml b/platform/gitea-runner/clusterspiffeid.yaml deleted file mode 100644 index 55d8420..0000000 --- a/platform/gitea-runner/clusterspiffeid.yaml +++ /dev/null @@ -1,17 +0,0 @@ -apiVersion: spire.spiffe.io/v1alpha1 -kind: ClusterSPIFFEID -metadata: - name: gitea-actions -spec: - className: spire-mgmt-spire - spiffeIDTemplate: spiffe://{{ .TrustDomain }}/ci/gitea-actions - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: gitea-actions - podSelector: - matchLabels: - app.kubernetes.io/instance: gitea-actions - app.kubernetes.io/name: actions-runner - workloadSelectorTemplates: - - k8s:ns:gitea-actions - - k8s:sa:gitea-actions diff --git a/platform/gitea-runner/external-secret.yaml b/platform/gitea-runner/external-secret.yaml deleted file mode 100644 index 2a914a0..0000000 --- a/platform/gitea-runner/external-secret.yaml +++ /dev/null @@ -1,18 +0,0 @@ -apiVersion: external-secrets.io/v1 -kind: ExternalSecret -metadata: - name: gitea-runner-token - namespace: gitea-actions -spec: - refreshInterval: 1h - secretStoreRef: - kind: ClusterSecretStore - name: openbao - target: - creationPolicy: Owner - name: gitea-runner-token - data: - - secretKey: token - remoteRef: - key: k8s/gitea-runner - property: token diff --git a/platform/gitea-runner/helmrelease.yaml b/platform/gitea-runner/helmrelease.yaml deleted file mode 100644 index 190d955..0000000 --- a/platform/gitea-runner/helmrelease.yaml +++ /dev/null @@ -1,31 +0,0 @@ -apiVersion: helm.toolkit.fluxcd.io/v2 -kind: HelmRelease -metadata: - name: gitea-actions - namespace: gitea-actions -spec: - chart: - spec: - chart: actions - interval: 1h - sourceRef: - kind: HelmRepository - name: gitea-charts - version: 0.1.1 - driftDetection: - mode: enabled - install: - strategy: - name: RetryOnFailure - retryInterval: 5m - interval: 30m - releaseName: gitea-actions - targetNamespace: gitea-actions - timeout: 10m - upgrade: - strategy: - name: RetryOnFailure - retryInterval: 5m - valuesFrom: - - kind: ConfigMap - name: gitea-actions-values diff --git a/platform/gitea-runner/helmrepository.yaml b/platform/gitea-runner/helmrepository.yaml deleted file mode 100644 index c545a84..0000000 --- a/platform/gitea-runner/helmrepository.yaml +++ /dev/null @@ -1,8 +0,0 @@ -apiVersion: source.toolkit.fluxcd.io/v1 -kind: HelmRepository -metadata: - name: gitea-charts - namespace: gitea-actions -spec: - interval: 1h - url: https://dl.gitea.com/charts/ diff --git a/platform/gitea-runner/kustomization.yaml b/platform/gitea-runner/kustomization.yaml deleted file mode 100644 index e34e214..0000000 --- a/platform/gitea-runner/kustomization.yaml +++ /dev/null @@ -1,18 +0,0 @@ -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -generatorOptions: - disableNameSuffixHash: true - labels: - reconcile.fluxcd.io/watch: Enabled -configMapGenerator: - - name: gitea-actions-values - namespace: gitea-actions - files: - - values.yaml=values.yaml -resources: - - namespace.yaml - - serviceaccount.yaml - - clusterspiffeid.yaml - - external-secret.yaml - - helmrepository.yaml - - helmrelease.yaml diff --git a/platform/gitea-runner/namespace.yaml b/platform/gitea-runner/namespace.yaml deleted file mode 100644 index e31ad23..0000000 --- a/platform/gitea-runner/namespace.yaml +++ /dev/null @@ -1,4 +0,0 @@ -apiVersion: v1 -kind: Namespace -metadata: - name: gitea-actions diff --git a/platform/gitea-runner/serviceaccount.yaml b/platform/gitea-runner/serviceaccount.yaml deleted file mode 100644 index 8a1541f..0000000 --- a/platform/gitea-runner/serviceaccount.yaml +++ /dev/null @@ -1,6 +0,0 @@ -apiVersion: v1 -kind: ServiceAccount -metadata: - name: gitea-actions - namespace: gitea-actions -automountServiceAccountToken: false diff --git a/platform/gitea-runner/values.yaml b/platform/gitea-runner/values.yaml deleted file mode 100644 index d97568d..0000000 --- a/platform/gitea-runner/values.yaml +++ /dev/null @@ -1,81 +0,0 @@ -enabled: true - -giteaRootURL: http://gitea-http.gitea.svc.cluster.local:3000 -existingSecret: gitea-runner-token -existingSecretKey: token - -statefulset: - replicas: 0 - timezone: Etc/UTC - serviceAccountName: gitea-actions - extraVolumes: - - name: spiffe-workload-api - csi: - driver: csi.spiffe.io - readOnly: true - securityContext: - fsGroup: 1000 - # Chart 0.1.1 applies this block to both runner and DinD containers. - resources: - requests: - cpu: 250m - memory: 512Mi - ephemeral-storage: 2Gi - limits: - cpu: "4" - memory: 6Gi - ephemeral-storage: 20Gi - persistence: - size: 1Gi - - runner: - registry: docker.io - repository: gitea/runner - tag: 2.3.0 - pullPolicy: IfNotPresent - extraVolumeMounts: - - name: spiffe-workload-api - mountPath: /run/spire/agent-sockets - readOnly: true - config: | - log: - level: info - runner: - file: .runner - capacity: 4 - timeout: 3h - shutdown_timeout: 3h - labels: - - self-hosted:docker://docker.gitea.com/runner-images:ubuntu-latest - cache: - enabled: false - container: - require_docker: true - docker_timeout: 300s - # Workflows must still request this exact bind mount explicitly. The - # allowlist prevents arbitrary host paths from reaching job containers. - valid_volumes: - - /run/spire/agent-sockets - - dind: - # 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 - pullPolicy: IfNotPresent - # Bind mounts are resolved by dockerd, so the CSI socket must exist in the - # DinD container as well as in the runner container. - extraVolumeMounts: - - name: spiffe-workload-api - mountPath: /run/spire/agent-sockets - readOnly: true - # k3s uses a 1450-byte pod MTU. Without matching it here, nested Actions - # networks advertise 1500 and GitHub TLS packets disappear on the outer - # overlay path while direct pod traffic remains healthy. - extraArgs: - - --mtu=1450 - # --mtu only changes Docker's default bridge. act creates a user-defined - # bridge per job, so give every new bridge the same explicit default. - - --default-network-opt=bridge=com.docker.network.driver.mtu=1450