Agent 平台部署¶
一、这页讲什么¶
一个人在本机终端里跑 Agent,关掉窗口任务就没了,换台机器接不上,别人也看不见。这页把 Agent 从「某人的本机会话」变成「部门里多人多台设备都能稳定用」的一层:组网连通、会话常驻、统一控制台、失败通知。
读完能做成:在一台常开机器上起控制面,把第二台设备接进来,关掉本地终端后从另一台机器接回同一个任务。
二、开始之前¶
| 项 | 内容 |
|---|---|
| 更新日期 | 2026-10-21 |
| 适用版本 | Docker 27+;Tailscale 1.80+;tmux 3.4+ |
| 预计耗时 | 首台 2 小时,之后每加一台 20 分钟 |
| 风险级别 | 中。会新增常驻服务与开放端口,改动前先记下原状态 |
| 前置 | 一台常开机器(控制面)、若干被管理设备、组网已通 |
先定两件事再动手:设备清单(主机名、角色、负责人、是否常开),以及控制面绑哪个地址。后者只能绑组网地址或 127.0.0.1,不要直接对公网开。
三、动手做¶
3.1 先确认组网连通¶
控制面与被管理设备必须在同一个可互访的网段里。用组网工具把设备拉进同一张网,再从控制面 ping 每台设备。
$ tailscale status | head -3
<tailnet 地址> server-a linux - active; direct <公网地址>:41641
<tailnet 地址> laptop-b windows - active; relay "tok"
$ ping -c 1 laptop-b
PING laptop-b (<tailnet 地址>): 56 data bytes
64 bytes from <tailnet 地址>: icmp_seq=0 ttl=64 time=12.4 ms
能从控制面 ping 通每台设备就算成。组网细节见 Tailscale 专题。
3.2 起控制面容器¶
控制面负责发现设备、转发指令、展示会话。用容器跑,数据卷单独挂出来,重建容器不丢配置。
$ docker run -d --name agent-console \
-p 127.0.0.1:8080:8080 \
-v /srv/agent-console/data:/data \
--restart unless-stopped \
<控制面镜像>
$ docker ps --filter name=agent-console
CONTAINER ID IMAGE STATUS PORTS NAMES
a1b2c3d4e5f6 ... Up 12 seconds 127.0.0.1:8080->8080/tcp agent-console
看到状态 Up 且端口只绑在 127.0.0.1 就算成。绑 0.0.0.0 等于把控制台暴露到局域网,需要另做鉴权。
需要从别的机器访问时,用组网代理或反向代理转发,不要改容器端口绑定。代理写法见 反向代理与 HTTPS。
3.3 在被管理设备上装连接器¶
连接器主动外连控制面,设备不必开放入站端口。每台设备一个唯一标识,注册后控制面才能列出它。
$ <连接器> register --server http://<控制面地址>:8080 --name laptop-b
Registered connector: laptop-b (id 8f3c...)
$ <连接器> status
connected server=http://<控制面地址>:8080 id=8f3c...
控制台设备列表里出现这台设备、状态为在线就算成。连接器要做成开机自启,否则重启即掉线。
3.4 把 Agent 放进常驻会话¶
约定一条:所有 Agent 都跑在常驻会话里,不跑在裸终端。用 tmux 起带名字的会话,分离后会话继续跑。
$ tmux new -s agent-laptop-b-build
# 在会话里启动 Agent,然后 Ctrl+B 再按 D 分离
$ tmux ls
agent-laptop-b-build: 1 windows (created Tue Oct 21 10:30:12 2026)
$ tmux attach -t agent-laptop-b-build
关掉本地终端重新 SSH 上去,tmux attach 能看到原现场就算成。
会话命名用「agent-设备-用途」,设备命名用「角色-编号」。名字里带设备与用途,半年后还看得懂是谁的任务。
3.5 接一个通知出口¶
长任务跑完要有人知道。推送服务或 IM 机器人留一个出口就够,多个出口会互相抢占,表现为「有时收到有时收不到」。
手机收到这条测试消息就算成。
四、做完怎么确认¶
| 检查项 | 期望结果 |
|---|---|
docker ps |
控制面容器 Up,端口只绑 127.0.0.1 |
| 控制台设备列表 | 每台被管理设备在线 |
| 关掉本地终端再连 | tmux attach 回到原会话,任务还在跑 |
| 从另一台机器打开控制台 | 能看到该设备的会话 |
| 手动发一条通知 | 手机收到 |
五、卡住了怎么排查¶
| 症状 | 多半是 | 怎么办 |
|---|---|---|
| 注册报「记录正忙」 | 上次注册没干净退出,锁没释放 | 找残留进程停掉再重试;反复点重试只会一直命中同一把锁 |
| 设备一直离线 | 连接器没起 / 组网不通 / 控制面地址写错 | 在设备上看连接器日志,先 curl 控制面确认可达 |
| 注册成功但重启后没了 | 连接器没做开机自启 | 做成 systemd 服务或计划任务 |
访问控制台报 Invalid Host header |
绑了非本机地址但没声明公开地址 | 补访问控制与公开地址配置,仍不要开到公网 |
| 两台设备抢同一个标识 | 复制了同一份注册记录 | 每台设备单独注册,一机一个连接器实例 |
| 通知有时收到有时收不到 | 起了多个机器人 | 只留一个出口 |
连接器注册不上的根因通常是「上一次没退干净」。这类「首次启动自动迁移旧数据」的逻辑必须是幂等且可跳过的,否则迁移失败后重试永远命中同一把锁。
六、为什么这样能成¶
四层各管一件事,可以分开换:组网决定「通不通」,会话常驻决定「断线死不死」,控制台决定「在哪管」,通知决定「谁知道」。换掉一层不用动其它层,组网换错只是不通,控制台换错只是换界面。
Agent 跑在被管理设备的常驻会话里,控制台只是遥控器:控制面重启不杀任务,某台设备掉线只影响那一台。连接器主动外连,被管理设备不需要暴露入站端口,风险面比反向代理小。
七、边界与替代¶
- 只有一台机器、一个人用:不需要控制面,组网 + tmux + 通知就够。
- 有「元数据不能经过第三方」的要求:把组网换成自托管控制面,其余三层不动。
- 不要把控制面直接开到公网:需要外部访问就放在组网内,或放在带鉴权的反向代理后面。
- 不要用插件方式接控制面:Linux 上插件方式容易出现注册记录冲突,用独立连接器程序。
- 一台设备只装一个连接器实例:两个实例会争同一份注册记录。
八、官方资料¶
控制面本身是自托管组件,版本与部署参数以内部部署记录为准(见内部台账)。以下几项由上游项目维护,规则以官方文档为准:
- Docker 容器运行参数:https://docs.docker.com/reference/cli/docker/container/run/
- Docker 数据卷与恢复:https://docs.docker.com/engine/storage/volumes/
- tmux 手册(会话、会话分离):https://man.openbsd.org/tmux
- systemd 服务单元(连接器开机自启):https://www.freedesktop.org/software/systemd/man/latest/systemd.service.html
- Tailscale ACL 与标签:https://tailscale.com/kb/1018/acls