Files
gitea-dynamic-runner/docs/design-principles.md

3.8 KiB

动态 Runner 设计原则

对 workflow 的接口

Runner 只向 workflow 暴露两个执行环境:

runs-on: [self-hosted, pod]
runs-on: [self-hosted, vm]
  • self-hosted 是固定前缀。
  • pod 表示一次性 Kubernetes Pod,承担常规 CI、镜像构建和 kind 等任务。
  • vm 表示一次性 microVM,承担需要独立内核、KVM、systemd 或更强隔离的任务。

执行后端是基础设施选择,不是权限角色。workflow 不需要额外声明由 controller 维护的 role 或权限 label。

一个 job,一个环境

Controller 根据 Gitea workflow_job webhook 创建执行环境。每个 Pod 或 VM 注册一个 ephemeral runner,只执行一个 job;任务结束后注销 runner,并删除计算环境及其全部 本地状态。

job_id 仅用于消息去重、状态追踪、实例关联和失败清理,不进入 workload 身份,也 不参与资源授权。

Gitea 不保证由某次 queued webhook 创建的 runner 一定领取该 webhook 对应的 job。 因此创建环境时只赋予无业务权限的启动身份。runner 实际领取任务后,controller 根据 in_progress webhook 返回的 runner_name 和真实 job 名称绑定业务身份;环境中的 job-start hook 必须等目标 SVID 可用后才放行 workflow 的第一步。不能依据 queued 事件提前赋予任务权限。

环境只提供运行边界

基础镜像只提供启动 runner 和执行 workflow 所需的最小环境。Docker、BuildKit、 kind 等工具由 pipeline 按需安装和启动,而不是由 controller 预制成常驻服务。

例如 Pod job 可以在 Pod 内启动仅供本次任务使用的 Docker daemon。该 daemon 及其 镜像、容器和缓存属于当前 job 的临时状态,随 Pod 一起销毁。Docker 创建的容器不是 独立的身份边界;需要访问凭据的操作由 Pod 中的 workflow 进程完成,并通过环境变量 或标准输入把短期凭据交给具体工具。

Workload 身份

动态 Pod 和 VM 都直接拥有自己的 SPIFFE 身份,不继承常驻 runner 的共享身份:

  • Pod 通过 Kubernetes workload attestation 取得身份。
  • VM 通过 VM 内的 SPIRE Agent 取得身份。

SPIFFE ID 由具有业务意义且稳定的 workflow 上下文派生:

spiffe://ddupan.top/ci/<owner>/<repository>/<job-name>

同一种任务在不同运行中使用相同的逻辑 SPIFFE ID;每次运行取得独立、短期的 SVID。 Pod 与 VM 是可替换的执行实现,因此默认不写入 SPIFFE ID。

job 名称必须经过确定性的路径规范化。规范化结果必须保留仓库边界,并在发生冲突时 拒绝创建环境,不能静默地让两个任务共享身份。同一仓库内需要不同权限的任务应使用 不同的 job 名称;workflow 文件只是编排载体,不进入权限身份。

Self-service 与授权边界

新增 workflow 或 job 时,controller 自动为它派生身份,不维护第二份任务或角色 allowlist。能够修改仓库 CI 的主体本来就能修改该仓库已有任务,因此 controller 的 重复审批不能形成额外的安全边界,只会破坏 self-service。

身份不等于权限。新任务可以立即取得自己的 SPIFFE ID,但默认不会因此获得 Zot、 OpenBao 或其他资源的特殊权限。资源所有者在资源端按照有意义的 job 身份 配置授权策略。

非目标设计

目标架构不依赖以下机制:

  • 多个 job 共享的常驻 Docker daemon。
  • 常驻 runner Pod 的共享 SPIFFE 身份。
  • 为嵌套 CI 容器转发共享身份的 JWT broker。
  • 将 Gitea 数字 job ID 编入 SPIFFE ID。
  • controller 维护的仓库任务权限 allowlist。

仓库中的 jwt-broker 是早期方案的实验实现,在 Pod/VM 动态执行环境完成迁移后不应 部署。