1. 项目概述:从单点运维到舰队管理
如果你和我一样,在团队里负责维护多个基于 OpenClaw 的智能体实例,那么下面这个场景你一定不陌生:今天张三在服务器 A 上手动改了个配置,明天李四在服务器 B 上直接docker restart升级把 OAuth 令牌搞丢了,后天你发现某个实例里的技能版本和代码仓库对不上,但又不知道是谁、在什么时候改的。随着实例数量从 1 个增长到 5 个、10 个甚至更多,这种混乱会像滚雪球一样,让日常运维变成一场噩梦。openclaw-fleet这个工具包,就是我在管理了 18 个跨 5 台主机的 OpenClaw 实例后,为了终结这种混乱而沉淀下来的一套舰队管理方案。
简单来说,openclaw-fleet是一套 Bash 脚本和声明式配置的集合,它把 Docker 容器化的 OpenClaw 实例当作一个“舰队”来管理。它的核心思想是“声明即状态”:你只需要在一个fleet.yml文件里描述清楚你希望整个舰队(所有主机上的所有容器)最终长什么样,剩下的工作——检查现状是否符合预期、自动修复偏差、安全升级、部署技能——都可以交给脚本自动化完成。这彻底改变了我们管理分布式应用的方式,从被动的“救火”变成了主动的、可预测的治理。
2. 核心痛点与解决方案设计
在深入工具细节之前,我们先拆解一下多实例 OpenClaw 部署中那些最让人头疼的问题,以及openclaw-fleet是如何针对性地设计解决方案的。
2.1 五大运维顽疾的深度剖析
配置漂移:这是最隐蔽的杀手。想象一下,你通过fleet.yml定义所有容器都应该使用openclaw:2026.2.22镜像。但某天因为一个紧急 Bug,你临时登录到prod-1主机,手动docker run了一个openclaw:latest的测试容器。问题解决后,你忘了清理它。几周后,这个“编外”容器可能还在运行,消耗资源,甚至因为版本差异引入新的问题。更常见的是容器内文件的修改,比如直接进入容器编辑了某个技能的 Python 脚本,这些更改没有回写到版本库,成了“黑箱”操作。
注意:配置漂移之所以危险,是因为它破坏了“基础设施即代码”的基石——可重复性。一个无法通过代码完全重建的环境,其稳定性和可维护性会随时间急剧下降。
升级灾难:直接docker pull新镜像然后docker run一个新容器,是最粗暴的升级方式。对于 OpenClaw 这类需要持久化身份认证信息(auth-profiles.json)的应用,这样做会直接导致所有已配置的 OAuth 令牌、API 密钥丢失,需要全部重新授权,运维成本极高。
技能蔓延:OpenClaw 的技能是其核心能力。当技能被直接编辑在容器内部(例如,通过docker exec进入容器修改文件),就会产生一系列问题:没有版本记录、无法协同开发、无法回滚到上一个可用的版本。最终,你会发现自己对生产环境里运行的技能代码版本一无所知。
静默故障:一个容器进程还在运行(docker ps显示Up),并不代表应用是健康的。网关接口可能无响应,依赖的 Chromium 浏览器可能因为底层库更新而崩溃,或者磁盘满了导致日志无法写入。这些故障不会自动触发容器重启,往往需要用户报告或定期人工检查才能发现。
繁琐的供给:每新增一个 OpenClaw 实例,你都需要重复一系列步骤:创建目录、设置权限、编写docker-compose.yml或docker run命令、配置反向代理、设置环境变量、初始化技能目录……这些重复劳动不仅低效,还极易出错。
2.2 工具包的架构哲学与组件对应
openclaw-fleet的每个组件都精准地瞄准了上述一个或多个痛点:
fleet.yml(声明清单):这是整个系统的“单一事实来源”。它定义了“什么是正确状态”。所有其他工具都围绕这个文件工作,以此为标准进行比对和修正。它解决了“配置漂移”和“繁琐供给”的问题,因为所有配置都集中于此。fleet-verify.sh(验证脚本):这是系统的“巡检员”。它进行双向检查:首先检查现实是否匹配清单(清单->现实),例如该有的容器是否在运行;其次检查清单是否反映了全部现实(现实->清单),例如有没有未被清单记录的“野容器”。它解决了“配置漂移”和“静默故障”的检测问题。fleet-upgrade.sh(升级脚本):这是“外科医生”。它执行升级手术时,会小心翼翼地分离持久化数据(如认证文件)和临时容器层,确保升级只替换应用代码,而保留关键状态。它内置了回滚机制,解决了“升级灾难”。fleet-deploy-skills.sh(技能部署脚本):这是“物流系统”。它将技能代码从 Git 仓库版本化地部署到舰队中各个容器,并可以检查线上技能与仓库版本是否一致,解决了“技能蔓延”。bootstrap-droplet.sh(主机初始化脚本):这是“基地建设者”。它为新主机提供一套标准化的、幂等的初始化流程,包括 Docker 安装、安全加固等,为“繁琐供给”提供了自动化起点。- CI/CD 工作流:这是“自动驾驶仪”。通过定时任务自动执行
fleet-verify.sh,将静默故障的发现从“被动等待”变为“主动告警”。
这种设计遵循了经典的 DevOps 控制论原理:定义一个期望状态(fleet.yml),通过传感器收集当前状态(fleet-verify.sh),最后通过执行器将当前状态向期望状态调整(fleet-upgrade.sh,fleet-deploy-skills.sh)。
3. 从零开始构建你的 OpenClaw 舰队
理论讲完了,我们动手搭建。假设我们有两台 Ubuntu 22.04 服务器(prod-1,prod-2),需要部署 4 个 OpenClaw 实例。
3.1 环境准备与工具安装
首先,在你的运维工作站(或者一个跳板机)上克隆仓库并安装依赖。这些工具主要运行在控制端,用于远程管理舰队主机。
# 克隆舰队管理工具包 git clone https://github.com/vibewrk/openclaw-fleet.git cd openclaw-fleet # 安装必要的 CLI 工具 # yq: 用于在 Bash 中解析和操作 YAML 格式的 fleet.yml # jq: 用于处理和格式化脚本输出的 JSON # 根据你的系统选择安装命令 # 对于 macOS (使用 Homebrew) brew install yq jq # 对于 Ubuntu/Debian sudo apt update sudo apt install -y jq # yq 可能需要从其 GitHub 发布页安装最新版 sudo wget https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 -O /usr/bin/yq && sudo chmod +x /usr/bin/yq # 确保 Bash 版本 >= 4 (用于关联数组等高级功能) bash --version接下来,确保你对所有目标舰队主机(prod-1,prod-2)拥有 SSH 密钥免密登录权限。这是所有远程自动化操作的基础。
# 生成 SSH 密钥对(如果还没有) ssh-keygen -t ed25519 -C "fleet-management" # 将公钥部署到每一台舰队主机 ssh-copy-id user@prod-1-ip-address ssh-copy-id user@prod-2-ip-address # 测试连接 ssh user@prod-1-ip-address "hostname"3.2 编写你的舰队声明清单
这是最关键的一步。我们将基于fleet.example.yml创建自己的fleet.yml。这个文件的结构清晰,分为几个主要部分:
# fleet.yml fleet: name: "My-OpenClaw-Fleet" version: "1.0" defaults: pa_image: "ghcr.io/openclaw/openclaw:2026.2.22" # 舰队默认镜像版本 agent_data_root: "/opt/openclaw-agents" # 所有主机上 Agent 数据的根目录 profiles: # 定义一个基础智能体配置模板 base-pa: checks: - name: gateway-health verify: "curl -sf http://127.0.0.1:${PORT}/" # 健康检查,${PORT} 会被实际端口替换 - name: chromium verify: "which chromium" remediate: "apt-get update && apt-get install -y chromium" critical: false # 非关键依赖,缺失会自动修复 - name: auth-profiles verify: "test -f ${AGENT_DATA_DIR}/auth-profiles.json" # 检查关键认证文件 critical: true # 关键文件缺失将标记为严重故障 skills: - email-processor # 此配置模板默认搭载的技能 # 定义一个管理员智能体配置,继承基础模板并添加额外技能 admin-pa: inherits: base-pa # 继承所有 base-pa 的 checks 和 skills skills: - team-router - system-monitor droplets: # 此处的 droplets 泛指所有主机,名称源自早期基于 DigitalOcean 的实践 prod-1: address: "192.168.1.101" # 主机 IP,也可用域名 ssh_user: "deploy" # SSH 用户名 containers: agent-finance: port: 3001 # 网关端口 profile: base-pa # 使用 base-pa 配置模板 domain: "finance-bot.mycompany.com" # 对外域名(用于提醒) env: # 容器环境变量 OPENCLAW_AGENT_NAME: "finance-assistant" agent-support: port: 3006 # 注意端口间隔,见下文解释 profile: base-pa domain: "support-bot.mycompany.com" prod-2: address: "192.168.1.102" ssh_user: "deploy" containers: agent-admin: port: 3001 profile: admin-pa # 使用管理员配置模板 domain: "admin-bot.mycompany.com" env: OPENCLAW_AGENT_NAME: "admin-console" agent-hr: port: 3006 profile: base-pa domain: "hr-bot.mycompany.com"关于端口间隔的特别说明:OpenClaw 内部会为浏览器 Relay 服务分配一个端口,其规则通常是网关端口 + 3。因此,为了避免端口冲突,在同一主机上运行多个实例时,网关端口号至少需要间隔 5。例如:
agent-finance使用 3001,其 Relay 可能占用 3004。agent-support使用 3006,其 Relay 可能占用 3009。 这样,3001-3005 和 3006-3010 这两个端口区间就被清晰地隔离开,互不干扰。
3.3 初始化舰队主机
在定义好清单后,我们需要确保所有主机都处于一个已知的、一致的基础状态。bootstrap-droplet.sh脚本用于此目的。它是一个幂等脚本,意味着无论运行多少次,只要最终状态符合要求,就不会产生副作用。
# 在控制端,对每一台主机执行初始化 ./scripts/bootstrap-droplet.sh --host prod-1 --ssh-user deploy ./scripts/bootstrap-droplet.sh --host prod-2 --ssh-user deploy这个脚本通常会做以下几件事(具体内容需查看脚本源码):
- 更新系统包并安装基础工具(如
curl,wget,vim)。 - 安装 Docker 和 Docker Compose,这是运行 OpenClaw 容器的前提。
- 进行基础安全加固:如创建专用运维用户、配置 SSH 密钥登录并禁用密码登录、设置防火墙规则、安装 fail2ban 防暴力破解。
- 创建标准化目录结构,比如我们在
defaults中定义的/opt/openclaw-agents。 - 配置日志轮转和基础监控。
实操心得:建议在首次部署舰队前,手动在一台主机上运行一遍引导脚本,并仔细审查其执行的操作。你可能会根据自己公司的安全策略调整某些步骤,比如特定的防火墙端口、审计规则等。将这个定制化的脚本保存为你自己的版本。
4. 舰队日常运维实操详解
有了清单和初始化好的主机,舰队就可以运转了。但日常运维才是重头戏。下面我们拆解几个核心工作流。
4.1 状态验证与漂移检测
这是你最应该频繁执行的操作。fleet-verify.sh是你的“雷达”。
# 最基本的检查:清单里定义的容器是否都在运行? ./scripts/fleet-verify.sh --check这个命令会依次 SSH 到每台主机,检查fleet.yml中定义的每个容器是否存在且状态为Up。输出是简洁的文本报告,绿色[OK]红色[FAIL]。
但仅仅这样不够。因为可能有“野容器”(清单外容器)在运行。这就需要审计模式:
# 审计模式:发现主机上所有正在运行的 OpenClaw 相关容器,并与清单对比 ./scripts/fleet-verify.sh --audit输出会列出两类不一致:
- 清单有但现实没有:比如你定义了一个
agent-test,但它没运行。 - 现实有但清单没有:比如有人手动运行了一个
openclaw:latest的临时容器。
更强大的完整检查与自动修复:
# 执行完整检查,包括健康检查(如网关HTTP状态),并尝试自动修复非关键问题(如安装缺失的chromium) ./scripts/fleet-verify.sh --full --remediate # 输出 JSON 格式,便于集成到其他系统(如监控面板、CI/CD) ./scripts/fleet-verify.sh --full --json | jq '.' # 用 jq 美化输出JSON 输出包含了每个检查点的详细信息,结构清晰,适合机器解析。例如,你可以将其发送到 Prometheus 或 Datadog 进行指标采集和告警。
4.2 安全升级流程
升级是高风险操作。fleet-upgrade.sh的核心安全特性在于它理解 OpenClaw 容器的数据持久化模型。
一个典型的 OpenClaw 容器运行命令可能如下:
docker run -d \ -p 3001:3000 \ -v /opt/openclaw-agents/agent-alice:/home/node/.openclaw/agents/main/agent \ -v /opt/openclaw-agents/agent-alice/cache:/home/node/.cache \ --name agent-alice \ ghcr.io/openclaw/openclaw:2026.2.22关键点在于-v挂载的卷。/home/node/.openclaw/agents/main/agent目录下存放着auth-profiles.json(认证信息)和skills/(技能代码)等需要持久化的数据。
安全升级的幕后原理:
- 停止旧容器:
docker stop agent-alice - 创建备份标签:
docker tag agent-alice agent-alice-backup-$(date +%s) - 移除旧容器:
docker rm agent-alice(注意,-v参数不会被使用,因此绑定的宿主机卷得以保留) - 用新镜像启动新容器:使用与旧容器完全相同的
docker run命令,包括所有端口映射、卷挂载和环境变量,仅将镜像标签更新为目标版本。 - 健康检查:等待新容器启动,并执行
profiles中定义的gateway-health检查。 - 失败回滚:如果健康检查失败,脚本会自动用备份的旧镜像重新启动容器,恢复服务。
# 实战:升级整个舰队到新版本 ./scripts/fleet-upgrade.sh --image ghcr.io/openclaw/openclaw:2026.2.23 # 更稳妥的方式:按主机灰度升级 ./scripts/fleet-upgrade.sh --image ghcr.io/openclaw/openclaw:2026.2.23 --droplet prod-1 # 观察 prod-1 上的实例运行几分钟,确认无误后再升级下一台 ./scripts/fleet-upgrade.sh --image ghcr.io/openclaw/openclaw:2026.2.23 --droplet prod-2 # 升级前先进行模拟演练(Dry Run) ./scripts/fleet-upgrade.sh --image ghcr.io/openclaw/openclaw:2026.2.23 --dry-run # 这会打印出将要执行的所有命令,但不会实际操作,用于检查配置是否正确。 # 如果升级后发现问题,快速回滚到上一个已知良好的镜像(脚本会记录) ./scripts/fleet-upgrade.sh --rollback --droplet prod-1避坑指南:即使有了自动回滚,也强烈建议在升级前,手动备份关键容器的数据卷目录(如
/opt/openclaw-agents/agent-alice)。自动化工具虽好,但多一份离线备份,就多一份安心。特别是重大版本升级前。
4.3 技能管理与版本化部署
技能代码不应该活在容器里,而应该活在 Git 仓库中。fleet-deploy-skills.sh实现了这个理念。
假设你的技能代码仓库结构如下:
my-openclaw-skills-repo/ ├── email-processor/ │ ├── skill.json │ ├── main.py │ └── requirements.txt ├── team-router/ │ └── ... └── system-monitor/ └── ...在fleet.yml的profiles部分,我们定义了每个配置模板搭载的技能列表(如base-pa搭载email-processor)。部署脚本的工作就是将这些技能同步到对应容器的持久化卷中。
# 将本地技能仓库的 v1.2.3 版本(可以是Git tag或commit hash)部署到整个舰队 ./scripts/fleet-deploy-skills.sh --version v1.2.3 --repo-url /path/to/local/repo # 或者从远程 Git 仓库部署 ./scripts/fleet-deploy-skills.sh --version main --repo-url https://github.com/your-org/skills-repo.git # 检查技能状态:对比舰队中运行的技能与指定版本仓库的差异 ./scripts/fleet-deploy-skills.sh --check --version v1.2.3--check模式非常有用,它能快速告诉你,哪个主机上的哪个容器的哪个技能文件被本地修改过(即“漂移”了),输出类似于 Git 的 diff 摘要。
部署流程细节:
- 脚本会解析
fleet.yml,找出所有需要某个技能的容器(根据profile映射)。 - 对于每个目标容器,通过 SSH 连接到其主机。
- 在主机上,将技能仓库的特定版本克隆或更新到一个临时目录。
- 使用
rsync或cp将技能目录同步到容器的持久化数据卷路径下(例如/opt/openclaw-agents/agent-alice/skills/email-processor)。 - 由于 OpenClaw 通常支持技能热重载,或者脚本会发送一个
SIGHUP信号给容器进程,新的技能代码会立即生效,无需重启整个容器。
4.4 集成到 CI/CD 流水线
自动化检查是运维稳定的最后一道防线。项目自带的.github/workflows/fleet-health.yml给出了一个 GitHub Actions 的范例,每 15 分钟检查一次舰队健康状态。
你需要在自己的仓库 Secrets 中配置:
FLEET_SSH_KEY:用于 SSH 连接到舰队主机的私钥。TELEGRAM_BOT_TOKEN和TELEGRAM_CHAT_ID(或其他通知方式如 Slack Webhook):用于发送告警。
这个工作流的核心步骤是:
- name: Verify Fleet Health run: | ./scripts/fleet-verify.sh --full --json > health-report.json # 解析 health-report.json,如果有严重错误(critical: true的检查失败),则退出码非0 ./scripts/check-health-report.py health-report.json当检查失败时,工作流会失败,并触发通知,将问题信息发送到你的即时通讯工具,让你在用户感知之前就发现问题。
5. 高级主题与故障排查
5.1 处理复杂的配置文件与环境变量
有时,OpenClaw 实例需要复杂的配置文件或大量的环境变量。fleet.yml的env部分可以定义容器环境变量,但对于配置文件,最佳实践是:
- 将配置文件也纳入版本控制,放在一个专门的
configs/目录下。 - 在
bootstrap-droplet.sh或一个单独的配置部署脚本中,将这些文件分发到各主机的特定目录(如/etc/openclaw-fleet/configs/)。 - 在
fleet.yml中,通过volumes字段(如果脚本支持扩展)或直接在容器定义中,添加额外的卷挂载指令,将宿主机配置文件映射到容器内。
由于当前fleet.example.yml的 schema 可能未直接暴露volumes配置,你可能需要扩展fleet-upgrade.sh脚本的容器生成逻辑,使其能读取并应用清单中定义的额外挂载卷。
5.2 网络与安全考量
- SSH 安全:确保所有舰队主机使用 SSH 密钥认证,并考虑使用 SSH 证书颁发机构(CA)进行更集中的管理。定期轮换密钥。
- 容器网络:默认的
bridge网络可能满足需求。如果容器间需要通信,可以考虑创建自定义的 Docker 网络(如openclaw-net),并在fleet.yml中指定network_mode。升级脚本需要能处理网络配置。 - 防火墙:
bootstrap-droplet.sh应配置主机防火墙(如ufw),只开放必要的端口(SSH 22,以及 OpenClaw 的网关端口如 3001、3006 等)。 - 认证文件安全:
auth-profiles.json包含敏感令牌。确保其宿主机目录(如/opt/openclaw-agents/agent-alice)的权限严格限制(如chmod 700),并且该目录不被意外备份到不安全的位置。
5.3 常见问题与排查清单
问题1:fleet-verify.sh --check报告容器不存在。
- 排查:SSH 到对应主机,运行
docker ps -a | grep <容器名>。查看容器是否存在但处于Exited状态。 - 可能原因:容器启动失败。查看日志:
docker logs <容器名>。常见原因包括:端口冲突、挂载卷目录权限错误、镜像拉取失败。 - 解决:根据日志修复问题,然后可以尝试手动启动,或使用
fleet-verify.sh --full --remediate(如果配置了修复命令)。
问题2:健康检查(gateway-health)失败,但容器进程在运行。
- 排查:手动在容器内执行健康检查命令:
docker exec <容器名> curl -sf http://localhost:3000/。或者直接检查容器内应用日志。 - 可能原因:应用启动慢,健康检查超时;应用内部依赖(如数据库)连接失败;内存不足。
- 解决:调整
checks中的verify命令,增加重试逻辑和超时时间,例如:verify: "timeout 30 bash -c 'until curl -sf http://127.0.0.1:${PORT}/; do sleep 2; done'"。
问题3:技能部署后不生效。
- 排查:登录主机,检查技能文件是否已正确同步到数据卷目录。进入容器查看技能列表或日志:
docker exec <容器名> ls -la /home/node/.openclaw/agents/main/agent/skills/。 - 可能原因:技能路径配置错误;OpenClaw 未启用技能热重载;技能代码本身有语法错误。
- 解决:确认
fleet.yml中agent_data_root和容器内挂载路径的对应关系。可能需要重启容器以使技能加载(但这会中断服务,需谨慎)。
问题4:升级脚本执行回滚后,服务仍不正常。
- 排查:检查回滚后容器的日志。确认回滚使用的镜像标签是否正确。
- 可能原因:问题可能不是由新版镜像引起,而是由外部因素(如依赖服务故障、配置文件被破坏)导致。回滚到旧镜像同样无法解决。
- 解决:这是一个关键教训。升级前,务必确保当前稳定状态的所有配置和数据都已备份。回滚后仍失败,需要结合日志和监控,从系统层面排查根本原因。
问题5:CI/CD 工作流一直失败,报 SSH 连接错误。
- 排查:在 GitHub Actions 的运行日志中查看详细的 SSH 错误信息。在服务器上检查
sshd日志(/var/log/auth.log)。 - 可能原因:GitHub Actions 的 Secret 中存储的 SSH 私钥格式不正确(需要完整的 PEM 格式,包括
-----BEGIN OPENSSH PRIVATE KEY-----头尾);服务器 IP 或防火墙规则变更;部署密钥未被添加到目标主机的authorized_keys文件。 - 解决:在本地使用相同的私钥测试 SSH 连接。确保 Actions 使用的私钥没有设置密码。检查服务器是否启用了
PasswordAuthentication no和PubkeyAuthentication yes。
管理一个由数十个智能体实例组成的舰队,其挑战不在于单个容器的复杂性,而在于规模带来的混乱与不可预测性。openclaw-fleet提供了一套朴素的、基于声明式配置和自动化脚本的解法。它没有引入 Kubernetes 那样的重量级编排系统,而是用一组 Bash 脚本和 YAML 文件,在 Docker 这个层级之上,构建了恰到好处的秩序。这套工具的价值,在我经历了几次深夜故障排查后变得无比清晰——当你能在 30 秒内通过一个命令掌握整个舰队所有实例的健康状态,当你能一键安全地完成全舰队升级,当每一个技能变更都有迹可循时,你才能真正地从运维苦力中解脱出来,去关注更有价值的事情。