From 83eb87bcec8a82ec119f6dc66550c6e5d87ce615 Mon Sep 17 00:00:00 2001 From: panxiao81 Date: Wed, 16 Sep 2026 14:51:06 +0000 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E5=91=BD=E5=90=8D=E4=B8=BA=E5=8A=A8?= =?UTF-8?q?=E6=80=81=20Runner=20=E5=B9=B6=E8=AE=B0=E5=BD=95=E5=8D=8F?= =?UTF-8?q?=E8=AE=AE=E8=B0=83=E5=BA=A6=E8=B7=AF=E7=BA=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 5 ++ container/controller.Dockerfile | 2 +- docs/runner-protocol-roadmap.md | 59 +++++++++++++++++++ pyproject.toml | 14 ++--- src/gitea_dynamic_runner/__init__.py | 1 + .../controller.py | 0 .../jwt_broker.py | 0 .../kubernetes.py | 0 .../models.py | 0 .../pod_worker.py | 0 .../worker.py | 0 src/gitea_microvm_runner/__init__.py | 1 - systemd/gitea-microvm-worker.service | 2 +- tests/test_controller.py | 4 +- tests/test_jwt_broker.py | 2 +- tests/test_pod_worker.py | 4 +- 16 files changed, 79 insertions(+), 15 deletions(-) create mode 100644 docs/runner-protocol-roadmap.md create mode 100644 src/gitea_dynamic_runner/__init__.py rename src/{gitea_microvm_runner => gitea_dynamic_runner}/controller.py (100%) rename src/{gitea_microvm_runner => gitea_dynamic_runner}/jwt_broker.py (100%) rename src/{gitea_microvm_runner => gitea_dynamic_runner}/kubernetes.py (100%) rename src/{gitea_microvm_runner => gitea_dynamic_runner}/models.py (100%) rename src/{gitea_microvm_runner => gitea_dynamic_runner}/pod_worker.py (100%) rename src/{gitea_microvm_runner => gitea_dynamic_runner}/worker.py (100%) delete mode 100644 src/gitea_microvm_runner/__init__.py diff --git a/README.md b/README.md index 9d91702..fc50461 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,11 @@ runs-on: [self-hosted, vm] 消息流使用一个 `WorkQueuePolicy` stream。相同 runner label 的所有 worker 共享同一 durable consumer;扩容只需要增加 worker 或提高单机 capacity。 +当前 webhook → NATS 流程是用于尽快验证 Pod/VM 生命周期的 bootstrap 实现,不是 +长期调度接口。长期目标是让 controller 作为兼容 Gitea Runner 协议的调度器直接注册、 +声明 labels、领取 task,并把已领取 task 交给 Pod/VM executor;路线与迁移边界见 +[`docs/runner-protocol-roadmap.md`](docs/runner-protocol-roadmap.md)。 + ## 开发 ```bash diff --git a/container/controller.Dockerfile b/container/controller.Dockerfile index b4e2a44..b77325e 100644 --- a/container/controller.Dockerfile +++ b/container/controller.Dockerfile @@ -12,4 +12,4 @@ COPY --from=build /venv /venv COPY --from=spire /opt/spire/bin/spire-agent /opt/spire/bin/spire-agent USER 65532:65532 EXPOSE 8787 -ENTRYPOINT ["/venv/bin/gitea-microvm-controller"] +ENTRYPOINT ["/venv/bin/gitea-dynamic-runner-controller"] diff --git a/docs/runner-protocol-roadmap.md b/docs/runner-protocol-roadmap.md new file mode 100644 index 0000000..17d16f5 --- /dev/null +++ b/docs/runner-protocol-roadmap.md @@ -0,0 +1,59 @@ +# Gitea Runner 协议调度器路线 + +## 目标 + +长期形态不依赖 `workflow_job` webhook 发现工作。controller 本身作为 Gitea Runner +协议客户端注册,并声明 `self-hosted`、`pod` 和 `vm` labels;它只在后端存在可用容量 +时领取 task,然后将该 task 交给一个一次性 Pod 或 microVM 执行。 + +```text +Gitea RunnerService + │ Register / Declare / FetchTask + ▼ +dynamic-runner scheduler + │ 已领取的 task + lease + ├── Pod executor + └── microVM executor + │ logs / state / result + └──────────────────────► Gitea +``` + +这与“收到 webhook 后临时注册另一个 act_runner”不同。`FetchTask` 已经完成任务分配, +不能再期待 Gitea 把同一个 task 分配给随后启动的 runner。协议调度器必须让 executor +执行已经领取的 task,并继续完成日志、状态、心跳、取消和最终结果上报。 + +## 设计约束 + +- 对 workflow 的接口保持 `[self-hosted, pod]` 和 `[self-hosted, vm]` 不变。 +- scheduler 在没有对应 backend 容量时不领取 task,避免本地形成不可控积压。 +- 每个 executor 只执行一个 task,完成后销毁。 +- SPIFFE 身份从实际领取的 task 的 repository 和 job name 派生,不需要 queued 与 + in-progress webhook 的二阶段关联。 +- scheduler 的 runner registration credential 不进入 executor;executor 只得到执行 + 当前 task 所需的短期 lease/capability。 +- task ACK、心跳和结果必须能够跨 scheduler 重启恢复;NATS 可以继续作为内部 handoff, + 但不是 Gitea 任务事实来源。 +- Pod 与 VM 共享 task/executor 协议,只有环境创建和销毁实现不同。 + +## 实现顺序 + +1. 固定当前 Gitea 版本所使用的 RunnerService protobuf 与 act_runner 版本,记录兼容 + 范围并建立协议契约测试。 +2. 实现只注册、Declare labels 和容量感知 FetchTask 的 scheduler spike,暂不执行 + task。 +3. 从 act_runner 提取或复用 task 执行与日志上报能力,定义 scheduler 到 executor 的 + 单任务协议。 +4. 首先接入 Pod executor,验证成功、失败、取消、超时和 scheduler 重启。 +5. 接入 microVM executor,并复用同一 task 协议和身份派生逻辑。 +6. 双轨运行并验证后,移除 webhook receiver、临时 runner 注册和 identity binding + subject。 + +## Bootstrap 实现的退出条件 + +只有同时满足以下条件才能删除 webhook 路径: + +- scheduler 能通过 RunnerService 稳定领取并执行 Pod/VM task; +- Gitea UI 中的实时日志、取消、超时和结论与官方 runner 行为一致; +- scheduler 重启不会丢失已领取 task,也不会重复执行; +- SPIFFE 身份只来自实际领取 task; +- 同一套 workflow 无需修改 `runs-on` 即可从 bootstrap 迁移。 diff --git a/pyproject.toml b/pyproject.toml index 39062c1..780f3cd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,9 +3,9 @@ requires = ["setuptools>=75"] build-backend = "setuptools.build_meta" [project] -name = "gitea-microvm-runner" -version = "0.2.0" -description = "On-demand Cloud Hypervisor runners for Gitea Actions" +name = "gitea-dynamic-runner" +version = "0.3.0" +description = "On-demand Pod and microVM execution environments for Gitea Actions" requires-python = ">=3.11" dependencies = ["aiohttp==3.12.15", "nats-py==2.11.0"] @@ -13,10 +13,10 @@ dependencies = ["aiohttp==3.12.15", "nats-py==2.11.0"] test = ["pytest==8.4.2", "pytest-asyncio==1.2.0"] [project.scripts] -gitea-microvm-controller = "gitea_microvm_runner.controller:main" -gitea-microvm-worker = "gitea_microvm_runner.worker:cli" -gitea-pod-worker = "gitea_microvm_runner.pod_worker:cli" -gitea-spire-jwt-broker = "gitea_microvm_runner.jwt_broker:main" +gitea-dynamic-runner-controller = "gitea_dynamic_runner.controller:main" +gitea-dynamic-runner-pod-worker = "gitea_dynamic_runner.pod_worker:cli" +gitea-dynamic-runner-vm-worker = "gitea_dynamic_runner.worker:cli" +gitea-spire-jwt-broker = "gitea_dynamic_runner.jwt_broker:main" [tool.pytest.ini_options] asyncio_mode = "auto" diff --git a/src/gitea_dynamic_runner/__init__.py b/src/gitea_dynamic_runner/__init__.py new file mode 100644 index 0000000..1bd7652 --- /dev/null +++ b/src/gitea_dynamic_runner/__init__.py @@ -0,0 +1 @@ +"""Dynamic Pod and microVM execution environments for Gitea Actions.""" diff --git a/src/gitea_microvm_runner/controller.py b/src/gitea_dynamic_runner/controller.py similarity index 100% rename from src/gitea_microvm_runner/controller.py rename to src/gitea_dynamic_runner/controller.py diff --git a/src/gitea_microvm_runner/jwt_broker.py b/src/gitea_dynamic_runner/jwt_broker.py similarity index 100% rename from src/gitea_microvm_runner/jwt_broker.py rename to src/gitea_dynamic_runner/jwt_broker.py diff --git a/src/gitea_microvm_runner/kubernetes.py b/src/gitea_dynamic_runner/kubernetes.py similarity index 100% rename from src/gitea_microvm_runner/kubernetes.py rename to src/gitea_dynamic_runner/kubernetes.py diff --git a/src/gitea_microvm_runner/models.py b/src/gitea_dynamic_runner/models.py similarity index 100% rename from src/gitea_microvm_runner/models.py rename to src/gitea_dynamic_runner/models.py diff --git a/src/gitea_microvm_runner/pod_worker.py b/src/gitea_dynamic_runner/pod_worker.py similarity index 100% rename from src/gitea_microvm_runner/pod_worker.py rename to src/gitea_dynamic_runner/pod_worker.py diff --git a/src/gitea_microvm_runner/worker.py b/src/gitea_dynamic_runner/worker.py similarity index 100% rename from src/gitea_microvm_runner/worker.py rename to src/gitea_dynamic_runner/worker.py diff --git a/src/gitea_microvm_runner/__init__.py b/src/gitea_microvm_runner/__init__.py deleted file mode 100644 index 89dab5d..0000000 --- a/src/gitea_microvm_runner/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""Gitea microVM runner controller and worker.""" diff --git a/systemd/gitea-microvm-worker.service b/systemd/gitea-microvm-worker.service index abe0bd7..ee4f108 100644 --- a/systemd/gitea-microvm-worker.service +++ b/systemd/gitea-microvm-worker.service @@ -7,7 +7,7 @@ Requires=microvm-runner-network.service [Service] Type=simple EnvironmentFile=-/etc/microvm-runner/worker.env -ExecStart=/opt/gitea-microvm-runner/venv/bin/gitea-microvm-worker +ExecStart=/opt/gitea-dynamic-runner/venv/bin/gitea-dynamic-runner-vm-worker Restart=on-failure RestartSec=5s SupplementaryGroups=kvm diff --git a/tests/test_controller.py b/tests/test_controller.py index 9419598..4daa2a4 100644 --- a/tests/test_controller.py +++ b/tests/test_controller.py @@ -4,8 +4,8 @@ import json import pytest -from gitea_microvm_runner import controller -from gitea_microvm_runner.models import IdentityBinding, RunnerRequest +from gitea_dynamic_runner import controller +from gitea_dynamic_runner.models import IdentityBinding, RunnerRequest def queued_job(**overrides): diff --git a/tests/test_jwt_broker.py b/tests/test_jwt_broker.py index 2a999b5..effd163 100644 --- a/tests/test_jwt_broker.py +++ b/tests/test_jwt_broker.py @@ -1,6 +1,6 @@ import pytest -from gitea_microvm_runner.jwt_broker import extract_svid +from gitea_dynamic_runner.jwt_broker import extract_svid def test_extract_svid_from_spire_json(): diff --git a/tests/test_pod_worker.py b/tests/test_pod_worker.py index ab67270..00c8dc0 100644 --- a/tests/test_pod_worker.py +++ b/tests/test_pod_worker.py @@ -1,7 +1,7 @@ import pytest -from gitea_microvm_runner.models import RunnerRequest -from gitea_microvm_runner import pod_worker +from gitea_dynamic_runner.models import RunnerRequest +from gitea_dynamic_runner import pod_worker def request() -> RunnerRequest: -- 2.54.0