8.6 KiB
8.6 KiB
在精简 LXC 上部署 agentd(design §9 阶段 3)
调度器跑在一台不装任何 agent CLI 的 Debian 12 LXC(agentd-01)上;所有终端(win10、oregon、mac…)都经 Warpgate SSH 远程启动(transport: warpgate-ssh)。LXC 只做调度、回帖、通知。
实际部署(2026-10-21,PAD-11):agentd-01 = PVE CT 600,Debian 12,tailnet 100.69.78.124,Warpgate target agentd-01,登录 root(Vault skill ssh-agentd-01;没有另建部署用户,agentd 以 root 运行)。下面是实际做过的步骤;从 oregon 发命令都经 agent-access.py … run --target agentd-01 --timeout N -- bash -c '…'。
1. 系统包
LXC 交付时已有 python3(3.11)、python3-yaml、openssh-client、git、cron(active);win10 helper 需要的 iconv gzip base64 sha256sum 也都在。从零装:
apt-get update && apt-get install -y python3 python3-yaml openssh-client git cron ca-certificates
jsonschema 可选,没有就用内置子集校验器。
2. 网络
| 去向 | 用途 |
|---|---|
nas.tail9531b.ts.net:8443(tailnet) |
Agent Vault 身份配置 identity/agent.json(含 vault token 与 Warpgate 主机公钥)→ LXC 已在 tailnet |
| Vault(身份配置里的地址) | 取 Plane token、Warpgate 密码 |
Warpgate SSH 115.28.210.101:2222 |
所有终端的中继(LXC → win10 / oregon) |
https://plane.kappiee.com |
Plane API |
https://git.kappiee.com |
git pull(公开仓库,无需凭据) |
3. Agent Vault 客户端
只复制程序文件(客户端没有落盘的 token 缓存;oregon 目录里的 agent-service-check.py 是运维工具,不需要):
# 在 oregon 上:两个文件 base64 后经中继写到 LXC(一次 run 调用,sha256 与 oregon 一致)
/root/.local/share/server-access-client/agent-access.py # 700 root
/root/.local/share/server-access-client/agent-access-askpass.py # 700 root,必须与 agent-access.py 同目录且可执行
# 在 LXC 上验证:
cd /root/.local/share/server-access-client
python3 -I agent-access.py --config https://nas.tail9531b.ts.net:8443/identity/agent.json status # "authenticated": true
python3 -I agent-access.py --config https://nas.tail9531b.ts.net:8443/identity/agent.json list # 含 win10、oregon、agentd-01
- 身份是 tailnet 上的 URL(
--config https://…/identity/agent.json),不落盘。 - Warpgate known_hosts 不用配:客户端每次用身份配置里的
warpgate.host_key生成临时 known_hosts。LXC → oregon 一次中继约 9 s。
4. 代码与配置
cd /opt/plane-agentd && git pull # 仓库已 clone 在 /opt/plane-agentd(https://git.kappiee.com/kappiee/plane-agentd.git)
mkdir -p /var/lib/plane-agentd /var/log/plane-agentd && chmod 700 /var/lib/plane-agentd
python3 -m unittest && python3 cli/agentd check-config
不需要本地配置文件,全部在仓库里(部署可复现):
config/agentd.yaml= agentd-01 的实时配置:state_dir: /var/lib/plane-agentd(状态、心跳、锁),log_dir: /var/log/plane-agentd(agentd.log),helpers_dir: tools/win10,vault.client: ~/.local/share/server-access-client/agent-access.py(root 下即/root/...)。终端 win10(warpgate-ssh/windows/schtasks)和 oregon(warpgate-ssh/linux/nohup,run_root: /home/ubuntu/.gwent-board/agentd-runs,bins.claude);没有 local 终端。tools/win10/win10-ps.sh、win10-put.sh:win10 helper(vault 客户端目录取AGENT_ACCESS_HOME,默认~/.local/share/server-access-client;身份取AGENT_ACCESS_CONFIG)。相对helpers_dir按仓库根解析。config/protocols/gwent-board-protocol.md:看板协议(拼进每轮 prompt,LXC 本机读取)。来源是 gwent 仓库design/board-protocol.md,协议更新时复制过来提交,然后 LXCgit pull。config/agentd.oregon.yaml:oregon 作调度器时的配置(回滚用,见 runbook)。- 相对路径(
state_dir/log_dir/helpers_dir/protocol_file)都按仓库根解析;远程终端的repo/run_root/bins必须是远程绝对路径。
5. 冒烟与切换(实际顺序)
- LXC 上手工跑一次(oregon cron 仍在跑,LXC 未排程;先确认 Plane 上没有 Todo 项可派,否则两个调度器会同时派单):
cd /root/.local/share/server-access-client && python3 -I agent-access.py --config https://nas.tail9531b.ts.net:8443/identity/agent.json exec \ --secret-env PLANE_OREGON_API_TOKEN=PLANE_OREGON_API_TOKEN --secret-env PLANE_WINDOW10_API_TOKEN=PLANE_WINDOW10_API_TOKEN \ --timeout 250 -- python3 /opt/plane-agentd/cli/agentd tick --once # 空闲:无输出,heartbeat errors=[] - oregon:备份 crontab(
~/.gwent-board/crontab.backup-20261021-pad11),删掉agentd-tick.sh那一行;flock ~/.gwent-board/agentd.lock true等正在跑的 tick 结束。 - 状态:
~/.gwent-board/agentd/agentd-state.json(oregon)→/var/lib/plane-agentd/agentd-state.json(LXC,600;base64 经中继写入,比对 sha256)。在途运行的 handle 是终端上的绝对路径,新调度器照常 poll/collect。 - LXC 上 root 的 crontab(只有这一行):
*/2 * * * * /opt/plane-agentd/cron/agentd-tick-lxc.shcron/agentd-tick-lxc.sh=flock -n /var/lib/plane-agentd/cron.lock timeout 900 python3 -I /root/.local/share/server-access-client/agent-access.py --config <identity> exec --secret-env PLANE_OREGON_API_TOKEN=… --secret-env PLANE_WINDOW10_API_TOKEN=… --timeout 850 -- python3 /opt/plane-agentd/cli/agentd --config /opt/plane-agentd/config/agentd.yaml tick --once >> /var/log/plane-agentd/cron.log 2>&1。 注意:经中继装 crontab 时别在set -e下写(crontab -l | grep -v …; echo …) | crontab -——没有旧 crontab 时 grep 返回 1,子 shell 提前退出,装进去的是空 crontab。直接printf '%s\n' '<行>' | crontab -。 - 验证:
/var/lib/plane-agentd/heartbeat.json的at每 2 分钟更新。 - 冒烟经 LXC 调度器:在 oregon 上
cli/agentd smoke GWENT oregon --watch(--watch= 只建项并等待,不在本机 tick;oregon 上cli/agentd默认读config/agentd.yaml,CLI 只需要 Plane token)。
- token 只经
exec --secret-env进 agentd 进程内存;agentd 起的中继子进程环境里去掉了所有token_key(Config.scrubbed_env())。 --secret-env的完整列表:cli/agentd check-config最后一行。- 任何时候只能有一个调度器排程(oregon 的 crontab 里不能有
agentd-tick.sh)。
6. 日志与心跳(LXC)
| 路径 | 内容 |
|---|---|
/var/log/plane-agentd/agentd.log |
每 tick 的动作、错误 |
/var/log/plane-agentd/cron.log |
cron 输出(空闲时为空;skip: another tick holds … 无害) |
/var/lib/plane-agentd/heartbeat.json |
at 超过 10 分钟不更新 = 调度器没在跑;down = 本 tick 中继不通而跳过的终端;launching = 启动未确认的运行 |
/var/lib/plane-agentd/agentd-state.json |
全部工作项状态 |
/var/lib/plane-agentd/agentd-state.json.lxc-smoke |
切换前手工冒烟 tick 产生的空状态(可删) |
终端上 <run_root>/<run_id>/ |
每轮的 prompt.md run.sh/run.ps1 pid.txt launch.pid exit.txt stderr.txt + 执行器输出;重新启动的运行在 <run_id>-r2/ |
7. 加一个终端(例:mac)
- Warpgate 加 SSH target(如
mac),给agent身份授权;agent-access.py … run --target mac --timeout 30 -- bash -c 'echo ok; uname'能通。 - 在终端上装好 agent CLI 并登录(Claude Code / Codex),clone 工作仓库;记下二进制绝对路径。
- 配置:
远程 shell 是目标账户的登录 shell(bash/zsh 均可,agentd 发的是
mac: transport: warpgate-ssh target: mac os: darwin # linux | darwin;darwin 用 perl POSIX::setsid 脱离会话(无 setsid 命令) launch: nohup repo: /Users/me/src/gwent run_root: /Users/me/.agentd-runs bins: {claude: /Users/me/.local/bin/claude} plane_user: mac token_key: PLANE_MAC_API_TOKEN concurrency: 1 executors: [claude-code]bash -c '<script>');终端需有bash base64 nohup pgrep pkill(Linux 另需setsid,macOS 需perl)。 - Plane:建用户
mac,token 存 Vault 键PLANE_MAC_API_TOKEN;项目routing.by_assignee加mac: mac,default_executor加mac: claude-code;cron/agentd-tick-lxc.sh加--secret-env PLANE_MAC_API_TOKEN=PLANE_MAC_API_TOKEN。 - 提交、推送、LXC
git pull;cli/agentd check-config,然后cli/agentd smoke GWENT mac --watch。