AgentMeshOS CI/CD:102 节点 GitHub Actions Runner 槽位扩容(4 槽位)固化说明
- 归属:P19 并行工程计划(不属于 P19 主阶段编号;与
agentmeshos-ci-cd-runner-integration-plan.md、-followup-plan.md 同族)
- 状态:已在 102 现场运行;本文与配套脚本是把现场手工步骤固化为可复现、可评审、可回退的产物,未修改任何现有生产脚本,未推送
- 事实基准:2026-10-16 只读回读(
gh api org runner 列表、102 的 systemctl show、文件 sha256)
📌 结论摘要
102 节点已承载 2 个 self-hosted runner 槽位,与 101 的 2 个槽位合成 4 槽位并发。4 个 runner 全部属于 org agentmeshos、标签 self-hosted,Linux,X64,agentmeshos-ci,2026-10-16 只读回读全部 online。依据是 gh api orgs/agentmeshos/actions/runners(id 6/7 在 101,id 8/9 在 102)与 102 上 systemctl is-active actions.runner.agentmeshos.pcdell-102-agentmeshos-102{a,b}.service。
采用本方案的原因不是"102 更快",而是 101 侧容量单向受限。 101 上由 capacity gate 管理的槽位 pcdell-101-agentmeshos(runner id 6)不随开机启动,其生命周期由 agentmeshos-runner-capacity-gate.timer 单向控制:资源门禁打开才拉起、资源紧张时只停它(不停常驻的 pcdell-101-agentmeshos-2)。因此 101 长期只能保证 1 个稳定槽位,把额外容量放到资源富余的 102 才能形成稳定 4 槽位。
代价与边界必须同时记住。 102 是生产权威节点(OmniRoute 唯一生产权威、Nomad Client、控制面只读备用),CI 与生产容器共用同一个 Docker daemon。因此 102 上的 runner 被限额(每槽 4 GiB 硬上限、Nice=10、IO idle),并且严禁在 CI 里执行 docker system prune / docker rmi / systemctl restart docker 一类全局 Docker 操作(详见风险与限制)。
🗂️ 目录
🎯 为什么在 102 增加槽位
| 观察 |
事实与依据 |
影响 |
101 的 pcdell-101-agentmeshos(runner id 6)是单向棘轮 |
scripts/ci/install-runner-capacity-gate.sh 对 pcdell-101-agentmeshos.service 执行 systemctl disable(不进 boot transaction),生命周期交给 agentmeshos-runner-capacity-gate.timer;scripts/ci/runner-capacity-gate.sh 只在启动门禁通过时 start 该槽位,资源紧张时只 stop 该槽位 |
101 长期可用容量只能按 1 个槽位估算 |
| 门禁阈值不低 |
同一脚本的启动门禁为 MemAvailable ≥ 6144 MiB、swap_free ≥ 4096 MiB、内存 PSI avg60 ≤ 3.00、load5/核 ≤ 1.50、磁盘可用 ≥ 51200 MiB |
101 上 AI 常驻进程(Codex/Paseo/OpenCode)占用内存后,第二槽位容易被停掉 |
| 101 只能证明 2 槽位瞬时在线 |
2026-10-16 只读回读时 id 7 恰好 online |
不代表长期容量;不得据此宣称 101 有 2 个槽位 |
| 102 资源有余量 |
102 MemTotal=15210 MiB(≈14.9 GiB)、MemAvailable=10089 MiB、8 核、根分区 457G 中已用 54G(13%,/opt 同盘) |
具备承载 2 个受限 runner 的条件 |
| 并发收益已被前序工作确认 |
docs/plans/agentmeshos-ci-cd-runner-integration-followup-plan.md 记录的慢因之一就是"只有 2 个自建 runner 导致多 workflow 同时触发时排队" |
扩到 4 槽位直接缩短排队 |
🗺️ 拓扑与槽位
| 槽位 |
所在节点 |
runner 名 |
runner id |
目录 |
systemd 单元 |
生命周期 |
| 101-1 |
101 100.64.0.2 |
pcdell-101-agentmeshos |
6 |
101 既有目录 |
actions.runner.agentmeshos.pcdell-101-agentmeshos.service |
由 capacity gate 单向控制(enabled=disabled) |
| 101-2 |
101 |
pcdell-101-agentmeshos-2 |
7 |
101 既有目录 |
actions.runner.agentmeshos.pcdell-101-agentmeshos-2.service |
常驻(enabled=enabled) |
| 102-1 |
102 100.64.0.4 |
pcdell-102-agentmeshos-102a |
8 |
/opt/agentmeshos-actions-runner-102a |
actions.runner.agentmeshos.pcdell-102-agentmeshos-102a.service |
常驻(enabled) |
| 102-2 |
102 |
pcdell-102-agentmeshos-102b |
9 |
/opt/agentmeshos-actions-runner-102b |
actions.runner.agentmeshos.pcdell-102-agentmeshos-102b.service |
常驻(enabled) |
- 标签统一为
self-hosted,Linux,X64,agentmeshos-ci;workflow 通过 vars.AGENTMESHOS_RUNNER_LABEL(org 与 repo 级均为 agentmeshos-ci)选取自建 runner。
- 102 槽位不参与 101 的 capacity gate:gate 只管理
pcdell-101-agentmeshos(runner id 6),其脚本默认值与 unit 名均硬编码指向 101。
🧱 现场事实(2026-10-16 只读回读)
| 项目 |
值 |
回读方式 |
| 节点身份 |
pcdell-102,Ubuntu 26.04.1 LTS,kernel 7.0.0-38-generic |
hostname、/etc/os-release、uname -r |
| 入口 |
Tailnet 100.64.0.4,SSH 10222,key /root/.ssh/agentmeshos-101-to-102 |
docs/node-aliases.md |
| runner 包 |
actions-runner-linux-x64-2.337.0.tar.gz,sha256 70920811a4f8ad4328818682bca5c6469c1c942fab52448868071d0063816613,Runner.Listener --version = 2.337.0 |
直接读远端二进制版本 |
| runner 用户 |
github-runner,uid 1001,属组 github-runner,docker(docker gid 973) |
id github-runner |
| CI 硬依赖 |
gawk 1:5.3.2-1ubuntu1.1(bug-task 的 workflow 直接调用 gawk) |
dpkg -l gawk |
| 注册记录 |
两槽位 .runner 中 agentName 分别为 pcdell-102-agentmeshos-102a/102b,gitHubUrl=https://github.com/agentmeshos |
读 /opt/.../102{a,b}/.runner |
| 限额 drop-in |
两槽位 /etc/systemd/system/<unit>.d/10-limit.conf,各 171 字节,sha256 39b8ab6c0c98b6dd73a8cc2859bbfe686bc5aa5e7c2288eca872d294804db80d |
sha256sum |
| 限额生效值 |
MemoryHigh=3221225472、MemoryMax=4294967296、MemorySwapMax=1073741824、TasksMax=4096、Nice=10、IOSchedulingClass=3(idle)、Restart=on-failure、RestartUSec=15s、OOMPolicy=stop、KillMode=control-group |
systemctl show -p <property> |
| 空闲内存占用 |
102a MemoryCurrent=65740800(≈62.7 MiB)、102b MemoryCurrent=66736128(≈63.6 MiB) |
systemctl show -p MemoryCurrent |
| 102 上没有 CI slice |
agentmeshos-ci.slice 在 102 不存在 |
systemctl cat agentmeshos-ci.slice 返回 "No files found" |
| 102 上同时运行的生产/常驻容器 |
agentmeshos-auth-site-standby、agentmeshos-console-site-standby、agentmeshos-api-gateway-standby、agentmeshos-standby-origin-gateway、qdrant、zap(zaproxy)、srctools-worker、codex-searxng、agentmeshos-node-metrics |
docker ps -a |
| gh 侧 runner 列表 |
4 个 runner 全部 online;id 6/7 在 101,id 8/9 在 102;busy=false |
gh api orgs/agentmeshos/actions/runners |
🔧 安装与注册流程(脚本化)
唯一入口:scripts/ci/install-runner-102.sh。三种模式:--check(只读)、--install(幂等安装,默认)、--rollback(回退);--dry-run 可与前两者组合,只打印动作、不写远端、不生成 token。
| 阶段 |
动作 |
幂等行为(重复执行时) |
| 1 前置校验 |
101 侧校验 root、gh 认证、ssh/awk/sha256sum/base64、SSH key 与限额模板可读;102 侧校验主机名 pcdell-102、gawk、docker 组、curl/tar/sha256sum/runuser/shred/systemctl/mktemp/base64、/opt 可用空间 ≥ 2048 MiB |
纯只读 |
| 2 包准备 |
需要时 useradd --uid 1001 建 github-runner 并 usermod -aG docker;/var/tmp/agentmeshos-runner-pkg 缓存 actions-runner-linux-x64-2.337.0.tar.gz,sha256sum -c 校验;解压到两个槽位目录并 chown -R github-runner:github-runner |
目录内 Runner.Listener --version 已等于目标版本则完全跳过下载与解压;缓存包 sha256 命中则跳过下载 |
| 3 注册 |
101 侧 gh api -X POST orgs/agentmeshos/actions/runners/registration-token 生成 token,经 stdin 写入 102 的 /run/agentmeshos-runner-registration-token(umask 077,0600);102 侧 runuser -u github-runner -- ./config.sh --url https://github.com/agentmeshos --token "$(cat <token文件>)" --name <slot> --labels self-hosted,Linux,X64,agentmeshos-ci --work _work --unattended --replace |
远端先检查 .runner 中 agentName 匹配则输出 slot_register=skip,连 token 都不生成 |
| 4 服务化 |
cd <槽位目录> && ./svc.sh install github-runner && ./svc.sh start(svc.sh 要求 root,单元内 User=github-runner) |
单元文件已存在则跳过 install;systemctl is-active 为真则跳过 start |
| 5 限额 drop-in |
把 deploy/systemd/runner-102-limit.conf 经 base64 参数传入 102,规范化比对后写入 <unit>.d/10-limit.conf,旧文件备份到 /root/.codex/backups/runner-102-limit-<UTC>/… |
字节相同 → 不写、不备份、不 reload;仅注释差异 → 只写文件、不重启;有效指令变化 → 备份 + daemon-reload,且仅在该 runner busy=false 时 systemctl restart |
| 6 健康校验 |
gh api 读回两个槽位 status=online(最长等待 RUNNER_102_HEALTH_TIMEOUT,默认 90s),再输出 systemctl show 的 MemoryMax/TasksMax 快照 |
读回失败则 runner_102_install=fail 并打印各 runner 状态 |
🔐 注册与凭据边界
| 边界 |
实现 |
| token 来源 |
只用 gh api 现取现用(registration-token / remove-token),有效期短、用途单一 |
| token 传输 |
只经 stdin 写入 102 的 /run/agentmeshos-runner-registration-token(tmpfs,umask 077 + chmod 0600,属主 github-runner) |
| token 生命周期 |
config.sh 读取后立即 shred -u 删除,并用 trap … EXIT 保证异常路径也删除 |
| token 可见性 |
脚本禁用命令回显(set +x),从 printf 到日志都不打印 token;只在失败时输出 org 名与失败原因 |
| 残余风险(已知、无法完全消除) |
GitHub runner 的 config.sh 只接受 --token 参数,token 会在 102 本机 argv 中短暂可见(毫秒级,102 上仅 root 与 github-runner 可读进程表);这是官方实现限制,不是本脚本引入 |
| 不入库 |
token 不出现在仓库、日志、报告与记忆中;.runner 文件(含 agentId、服务端 URL)也不入库 |
⚙️ 限额理由
模板即 deploy/systemd/runner-102-limit.conf(安装到 <unit>.d/10-limit.conf)。
| 字段 |
值 |
理由 |
MemoryHigh |
3G |
软上限:超过则回收该 cgroup 内存并施压,不直接杀进程 |
MemoryMax |
4G |
硬上限:单个 runner 槽位最多 4 GiB,两槽位合计上限 8 GiB,而 102 总内存 15210 MiB、回读时可用 10089 MiB |
MemorySwapMax |
1G |
允许有限换出吸收构建尖峰,避免无限制换出拖慢生产容器 |
TasksMax |
4096 |
限制构建中 fork 爆炸 |
Nice |
10 |
CI 让出 CPU 优先级,生产容器优先 |
IOSchedulingClass |
idle |
CI 磁盘读写只使用空闲 IO,避免与生产容器(含 Qdrant、zap)争 IO |
KillMode |
control-group |
停单元时连整个 cgroup(含构建子进程、Docker CLI 子进程)一起收掉,不留孤儿 |
Restart / RestartSec |
on-failure / 15s |
只对崩溃自愈,避免抖动循环 |
OOMPolicy |
stop |
内存触顶时由 systemd 停掉该单元(fail-closed),不让内核在 CI 与生产容器之间随机挑选牺牲者 |
不含 Slice= |
— |
102 上没有 agentmeshos-ci.slice(已实测不存在),101 的整片聚合上限写法在这里无法复用;因此 102 退化为"每单元单独限额"。若后续要在 102 引入 slice,属于新的设计变更,需单独评审 |
⚠️ 风险与限制
| 风险 |
事实依据 |
必须遵守的约束 |
| CI 与生产容器共用同一个 Docker daemon |
102 的 docker ps -a 同时列出 CI 侧新起的容器与 9 个生产/常驻容器(含控制面 standby 组、Qdrant、zap、srctools-worker、codex-searxng、node-metrics) |
禁止在 CI job 或运维操作中对 102 执行 docker system prune、docker image prune、docker builder prune、docker rmi、docker container prune、systemctl restart docker、systemctl stop docker;这些命令可能删掉当前未被容器占用的 last-known-good 回退镜像标签(例如 standby-rollback)与构建缓存,或整体重启生产容器 |
runner 以 docker 组成员运行,等同 root 级 Docker 权限 |
github-runner 属组含 docker(gid 973) |
不把 102 当作"低信任执行环境";workflow 的 runs-on: agentmeshos-ci 等于允许该 job 操作 102 的 Docker |
| 内存叠加 |
两槽位合计上限 8 GiB,102 回读时 MemAvailable=10089 MiB |
若 102 上生产容器内存需求上升,先收紧 runner 限额或停用 102b,不要提高 runner 上限 |
| 磁盘消耗 |
/opt 回读可用约 389.6 GiB;runner 工作目录 _work 与 Docker 构建缓存同盘 |
不做全局 Docker 清理的前提下,需要定期人工评估 _work 与镜像占用;不得用 prune 代替评估 |
| job 中断窗口 |
限额变更需要重启单元才生效 |
脚本已实现"仅有效指令变化 + runner 空闲时才重启";仍有极小竞态(判定后到重启前恰好被派发 job) |
| 单节点依赖 |
102 既是 CI 槽位又承载生产权威 |
102 宕机同时损失 2 个 CI 槽位;101 的 2 槽位(其中 1 个受门禁控制)仍可承接,但并发下降 |
| 版本漂移 |
runner 包冻结为 v2.337.0 + sha256 |
升级必须同时更新脚本内 RUNNER_VERSION/RUNNER_SHA256 与本文事实表,并按回退步骤保留回退材料 |
🔁 回退步骤
脚本化回退(推荐):
# 只读预演:打印将执行的动作,不产生任何写入
scripts/ci/install-runner-102.sh --dry-run --rollback
# 真实回退:注销两个 runner、卸载 systemd 单元、删 drop-in 与槽位目录、清理包缓存
scripts/ci/install-runner-102.sh --rollback
# 需要连 runner 用户一起删掉时(仅当两槽位目录已删且该用户无进程)
scripts/ci/install-runner-102.sh --rollback --purge-user
回退顺序(脚本内部,逆槽位 b → a):
| 步骤 |
命令(在 102 上以 root 执行) |
判定 |
| 1 停服务 |
cd <槽位目录> && ./svc.sh stop |
失败不阻断后续步骤 |
| 2 卸单元 |
cd <槽位目录> && ./svc.sh uninstall |
失败不阻断;随后显式 rm -f /etc/systemd/system/<unit> |
| 3 删 drop-in |
rm -rf /etc/systemd/system/<unit>.d + systemctl daemon-reload |
— |
| 4 GitHub 注销 |
gh api -X POST orgs/agentmeshos/actions/runners/remove-token → 经 stdin 落 0600 文件 → runuser -u github-runner -- ./config.sh remove --token "$(cat <token文件>)" → shred |
GitHub 侧已不存在时输出 slot_deregister=skipped reason=github_removal_failed,不阻断本地回退 |
| 5 删目录 |
rm -rf /opt/agentmeshos-actions-runner-102{a,b}(带受控路径白名单校验,白名单外一律拒绝删除) |
路径非 102a/102b 时退出码 4 |
| 6 清理包缓存 |
rm -rf /var/tmp/agentmeshos-runner-pkg |
— |
| 7 可选删用户 |
userdel -r github-runner(要求目录已删且 pgrep -u github-runner 无进程) |
不满足则退出码 5 |
| 8 结果读回 |
gh api orgs/agentmeshos/actions/runners |
期望只剩 id 6/7(101 两个) |
手工等价回退(脚本不可用时):在 102 上按上表 1–4 步执行即可让 4 槽位回到 2 槽位;不要回退 gawk、docker 组或 102 上的其他系统配置——它们不属于本变更。
✅ 验收证据与验证方法
| 验收项 |
命令 |
期望结果 |
| 4 个 runner 在线 |
gh api orgs/agentmeshos/actions/runners --jq '.runners[] \| {id,name,status,busy}' |
id 6/7/8/9 全部 online |
| 102 两个单元常驻 |
systemctl is-active actions.runner.agentmeshos.pcdell-102-agentmeshos-102{a,b}.service |
均为 active |
| 限额已生效 |
systemctl show -p MemoryMax -p MemoryHigh -p TasksMax <unit> |
4294967296 / 3221225472 / 4096 |
| drop-in 与仓库模板有效指令一致 |
脚本 --check + sha256sum <unit>.d/10-limit.conf |
现场 sha256 39b8ab6c…;有效指令与模板一致(模板仅多中文注释) |
| 4 槽位可同时 busy |
gh api 历史回放(见 4 槽位并发实测证据) |
已证实:2026-10-15T22:14:07Z 四个 runner 同时 busy |
| 一键只读体检 |
scripts/ci/install-runner-102.sh --check |
末行 runner_102_check=pass slots_online=2 total_slots=4(2026-10-16 实测通过) |
| 安装路径零副作用预演 |
scripts/ci/install-runner-102.sh --dry-run --install |
只打印动作,全仓 git status 不变(2026-10-16 实测通过) |
📊 4 槽位并发实测证据(0 新增负载)
结论:4 槽位并发已证实,且本次零新增负载。 4 槽位同时 busy 已被 GitHub API 权威记录证实,102 两个槽位可同时承接 job 也已被证实;本次核查未触发任何新 job,101 未承受新增负载。
| 验收目标 |
证据 |
时间戳(UTC) |
| 4 槽位同时 busy |
101-id6 probe / 101-id7 probe / 102a probe / 102b probe 四个 workflow_dispatch job 同时在跑(run 38815660380 / 38815666845 / 38815672659 / 38815678660) |
并发峰值 2026-10-15T22:14:07Z;四个 job 分别在 22:13:57 / 22:14:00 / 22:14:03 / 22:14:07 开始,均 success |
| 102 两槽位同时 busy(受控批次) |
同批次 102a 与 102b 两个 probe job 重叠 |
22:14:07 → 22:14:16(9 s);另有 22:12:45 → 22:13:02(17 s) |
| 102 两槽位同时 busy(真实业务流量) |
guardrails(run 38828101602, 102a) 与 build-and-push(run 38828101647, 102b) 重叠 |
2026-10-16T00:12:03 → 00:12:39(36 s) |
| 102 两槽位同时 busy(真实业务流量) |
build-and-push(run 38829906138, 102a) 与 guardrails(run 38829906040, 102b) 重叠 |
2026-10-16T00:30:59 → 00:31:37(38 s) |
证据来源与复现:数据由 gh api repos/agentmeshos/AgentMeshOS/actions/runs(近 48 h 共 133 个 run、98 个带 runner_name 的 job)采集,采集脚本 temp/runner-concurrency-scan.sh、扫描线分析脚本 temp/runner-concurrency-analyze.py(均在仓库 temp/ 下,属过程产物)。跑一次即可复算:bash temp/runner-concurrency-scan.sh 2026-10-14T00:00:00Z && python3 temp/runner-concurrency-analyze.py。
为什么用历史证据而不是新触发:GitHub 侧 job 到 runner 的分配不可定向(4 个 runner 标签完全相同,均为 self-hosted,Linux,X64,agentmeshos-ci),无法把 job 指定给 102;现场触发必然可能落到 101,与"不制造 101 内存压力"的约束冲突。改用 API 历史记录后,峰值 4 并发与 102 双槽重叠都有权威时间戳,且零副作用。
🎯 「102 优先」最终形态建议
建议:101 保留 id7 + id6(修死区后),102 暂不加第 3 槽位。 即:101 保留 1 个常驻槽位(id7)+ 1 个"机会性"槽位(id6,采纳死区修法)已足够,102 暂不加第 3 槽位,正常启动线不下调。依据与推荐值如下,均需用户拍板。
| 问题 |
事实与依据 |
建议(推荐值) |
理由 |
| 101 是否只需 1 槽位 |
id7 为 PRIMARY_SERVICE(常驻)、id6 受门禁控制;近 7 天门禁 219 次 resource_gate_closed,其中 98 次(45%)资源其实够维持运行 |
101 保留 1 个稳定槽位(id7)作为独立兜底,id6 保留为机会性增量 |
102 同时承载生产权威与 2 个 CI 槽位,102 宕机将同时损失 2 槽与生产;101 的稳定槽位是唯一的单点对冲 |
| id6 是否保留 |
id6 增量成本为零(只在 101 资源富余时启动,MemoryMax=4G、OOMPolicy=stop) |
保留,但必须配套死区修法(见 docs/plans/agentmeshos-ci-runner-capacity-gate-deadzone-plan.md) |
不修死区时 id6 会长期 offline,"保留"只是账面数字 |
| 是否下调正常启动线(6144/4096) |
101 现状快照 MemAvailable=5903 MiB 正处死区;交互式负载 opencode serve 占 4681 MiB |
不下调,改用降级线 4096/2048 + 停机 ≥1800 s 的降级启动 |
下调启动线会在 101 最紧张时塞入 4 GiB 上限的 runner,与"保护交互式负载"目标冲突 |
| 4 槽位是否够用 |
近 48 h 98 个 job 的排队统计:p50=7 s、max=2529 s;慢样本集中在 2026-10-15 17:50–21:11(102 槽位尚未承担流量时段) |
当前够用;先上线死区修法并观察 1 周排队分布再决定扩容 |
排队中位数只有 7 s,说明 4 槽位对常态负载富余;历史长尾更像"101 单槽位期"的遗留 |
| 102 是否加第 3 槽位 |
102 MemAvailable=10150 MiB,现存 2 槽位各 MemoryMax=4 GiB(合计 8 GiB 上限),且与生产容器共用 Docker daemon |
暂不加 |
第 3 槽位会把上限推到 12 GiB,逼近 102 可用内存;如确实需要扩容,优先评估"单槽位限额收紧 + 镜像缓存优化"而非加槽 |
排队统计口径:job.started_at - job.created_at(gh api .../runs/<id>/jobs),近 48 h 共 98 个带 runner_name 的 job。样本中出现少量负值(created_at 晚于 started_at),说明该字段会被 API 刷新,因此只使用分位数与极值趋势,不把单个样本当作精确排队时长。
🔎 与现场手工步骤的差异(脚本化改进)
| 项 |
现场手工 |
脚本化后 |
原因 |
| 包下载目录 |
102 的 /tmp/runner-pkg(现场仍有残留目录) |
/var/tmp/agentmeshos-runner-pkg,安装/回退结束可清理 |
不污染 /tmp;缓存可复用且可判定 sha256 |
| drop-in 内容 |
在 102 上手写 171 字节 10-limit.conf |
以 deploy/systemd/runner-102-limit.conf 为唯一事实源,按有效指令规范化比对后写入 |
仓库可评审、可回退;注释差异不触发重启 |
| 重启策略 |
写 drop-in 后 daemon-reload(重启与否取决于当时是否重载服务) |
有效指令变化才 daemon-reload,且仅当该 runner busy=false 时才 restart |
避免打断正在运行的 CI job |
| 幂等 |
每次都要人工判断 |
目录版本、注册状态、单元状态、drop-in 字节/有效指令四级幂等判定 |
重复执行零变更 |
| 正则回退 |
无 |
--rollback / --purge-user,含受控路径白名单与"有进程拒绝删用户" |
失败可回退且不会误删 |
📎 相关文件
| 文件 |
作用 |
scripts/ci/install-runner-102.sh |
102 槽位安装 / 只读体检 / 回退 的唯一入口(本次新增) |
deploy/systemd/runner-102-limit.conf |
102 两槽位的 systemd 限额模板(本次新增) |
scripts/ci/runner-capacity-gate.sh、scripts/ci/install-runner-capacity-gate.sh、deploy/systemd/agentmeshos-runner-capacity-gate.{service,timer}、deploy/systemd/runner-capacity.conf、deploy/systemd/agentmeshos-ci.slice |
101 侧容量门禁(本次未修改) |
docs/node-aliases.md |
102 的别名、Tailnet 地址与 SSH 入口依据 |
docs/plans/agentmeshos-ci-cd-runner-integration-plan.md、-followup-plan.md |
CI runner 整改总计划与后续计划(本页为其并行补充说明) |
⚠️ 未决项 / 需要用户决策
| 事项 |
当前事实 |
需要决定 |
| 本页的文档治理登记 |
实测(2026-10-16):把本页 git add 进索引后 python3 scripts/ci/agentmeshos-document-inventory-check.py 立即以 [ERROR] 存在未分类文档:plans/agentmeshos-ci-runner-102-slots-plan.md(退出码 1)失败;未改 MkDocs 导航时 agentmeshos-plan-nav-check.py 仍 pass |
提交本页时必须同步四处(属"修改现有文件",本任务按边界未改):① scripts/ci/agentmeshos-document-inventory-check.py 的 ACTIVE_PLAN_DOCUMENTS 增加 plans/agentmeshos-ci-runner-102-slots-plan.md;② 用 python3 scripts/ci/agentmeshos-document-inventory-check.py --write 重新生成 docs/plans/document-inventory.json;③ scripts/ci/agentmeshos-plan-nav-check.py 的 ACTIVE_ALLOWED 增加同名条目;④ tools/docs-site/config/mkdocs.yml 的「实施计划」段增加对应导航行。只做 ④ 不做 ③ 会触发"实施计划混入非当前入口" |
| 安装脚本的真实写入路径未在生产实测 |
本任务边界禁止写操作,因此 install-runner-102.sh 只实测了只读路径与零写入路径:--check(通过)、--dry-run --install(通过)、--dry-run --rollback(通过);package/register/service/dropin 的真实写入与 refresh_slot_after_limit_change 的 busy 分支均未实测 |
首次真实执行应安排在变更窗口内:先 --check,再 --install;预期末行 runner_102_install=pass slots_online=2,随后 gh api 复核 4 个 runner online |
| 是否保留 101 的容量门禁槽位 |
101 的 pcdell-101-agentmeshos(runner id 6)仍受单向门禁控制(2026-10-16 回读 agentmeshos-runner-capacity-gate.timer 为 active,每 1 分钟评估一次;该 unit enabled=disabled) |
推荐保留,并采纳 「102 优先」最终形态建议 第 2 行的死区修法;若坚持在 101 彻底停用该槽位,需单独评审门禁与 watchdog 的连带影响 |
102 是否引入 agentmeshos-ci.slice |
102 当前无该 slice,两槽位各自 4 GiB |
若需整片聚合上限(例如 6 GiB),需要新增 slice 单元并在 drop-in 中加 Slice=,属新的设计变更 |
| 4 槽位并发 busy 的实测证据 |
已闭环:GitHub API 历史记录证实 2026-10-15T22:14:07Z 四个槽位同时 busy;102 双槽重叠见 4 槽位并发实测证据,本次未新增任何 job |
无需决策;若要求"现场重新触发一次",需接受 job 可能落到 101 |
| runner 版本升级策略 |
冻结 v2.337.0 |
是否建立定期升级窗口(升级需同步脚本常量与本文事实表,并按回退步骤保留旧包) |
脚本是否登记到 docs/脚本库.md |
该页目前只索引 scripts/deploy/*、scripts/maintenance/*、scripts/clients/*,既有 scripts/ci/*(例如 runner-capacity-gate.sh)均未登记 |
本次沿用既有约定不登记;若要把 CI 脚本纳入该索引,属新的文档治理变更,需与上面的登记门禁一起评审 |