外观
节点 Agent 部署
node-agent 在真实节点上跑宿主原生 venv 加 systemd,不走容器。
这样安排有三个理由:apply 模式下渲染产物直接落宿主;宿主 dockerd 给路由容器做 bind 挂载时路径一致;agent 直接访问宿主的 docker.sock。
接入流程(注册、审批、provision)见 节点接入;配置项见 Node Agent 配置。
systemd 单元
deploy/tools/systemd/ 提供模板单元,文件头注释里有完整安装步骤。
| 单元 | 说明 |
|---|---|
dn42-node-agent@.service | agent 模板单元:%i 即 node_id,同机可跑多实例;Restart=always 常驻 |
dn42-control-server.service | 控制面也可走 systemd(uvicorn 加外部 postgres 与 redis),但生产推荐 docker 整栈 |
agent-self-update/dn42-node-agent-update.service | 自更新器单元,由 install-updater.sh 一次性安装 |
生产 fleet 的实际布局与模板单元略有差异:每节点单实例、用非模板单元
dn42-node-agent.service,venv 在/opt/dn42-agent(与agent_pip_rollout.sh与自更新器一致)。模板单元适合实验环境同机多实例。
安装
bash
sudo cp deploy/tools/systemd/*.service /etc/systemd/system/
sudo mkdir -p /opt/dn42-control && sudo rsync -a ./ /opt/dn42-control/
sudo python3 -m venv /opt/dn42-control/.venv
# 安装依赖与一方包(见单元文件的 PYTHONPATH / ExecStart)
sudo systemctl daemon-reload
sudo systemctl enable --now dn42-node-agent@edge1
journalctl -u dn42-node-agent@edge1.service -f节点专属变量放 /etc/dn42-control/<node_id>.env:
dotenv
DN42_AGENT_CONTROLLER_URL=https://api.natlan.io
DN42_AGENT_ENROLLMENT_TOKEN=change-me
# STATE_DIR 与 REQUESTED_NODE_ID 已由 unit 注入DN42_AGENT_CONTROLLER_URL 不带尾斜杠。改动后 systemctl restart 才生效。
安装自更新器
首次装机后每节点装一次:
bash
sudo bash deploy/tools/agent-self-update/install-updater.sh此后 agent 升级由控制面驱动——上传 wheel → 设目标版本 → 心跳推送 → 更新器安装 → 健康门校验,失败自动回滚,不再逐机 pip。见 Agent 滚动升级。
更新器是独立的 systemd oneshot 单元,由 agent 用 systemctl start --no-block 触发。进程隔离是必须的:升级会重启 agent,跟着 agent 一起被杀的更新器没法完成安装与回滚。
加固
模板单元已开:
Restart=on-failure/Restart=alwaysProtectSystem=strictNoNewPrivileges=true- 受限的
ReadWritePaths
agent 需要访问宿主 docker.sock,这是它能操作路由容器的唯一通道。控制面不提供远程 shell 或任意命令执行接口,agent 拿到的只是声明式期望状态——见 安全模型。
验证
bash
# 单次诊断,不动机器
python -m agent.main --plan-only --state-dir /var/lib/dn42-control
# 自检(配置 / 状态目录 / 身份 / 控制面 / Docker / 指标)
python -m agent.main --doctor --state-dir /var/lib/dn42-control常驻后从控制面看:GET /control/v1/admin/nodes/{node_id}/health 应在一轮 reconcile 后返回 ok。排障见 故障排查。