把多台服务器装进一个面板
中文 | English
Oops 是一个以项目为单位,面向多服务器环境的 AI 驱动运维面板。一个界面看清所有容器的状态、日志与健康检查结果,内置 Agent,可调用系统工具和 MCP 扩展直接操作容器、执行诊断,随项目增长越用越强。
Oops!... I Did It Again
graph TB
Browser["Browser"] -->|":8081"| OpsPlane["Ops Plane<br/>Central Server<br/>Agent Runtime"]
subgraph ServerA["Server A"]
NodeletA["Nodelet"]
DockerA["Docker Engine"]
NodeletA --> DockerA
DockerA --> MySQL["MySQL Container"]
DockerA --> B["Container B"]
end
subgraph ServerB["Server B"]
NodeletB["Nodelet"]
DockerB["Docker Engine"]
NodeletB --> DockerB
DockerB --> A["Container A"]
DockerB --> Kafka["Kafka Container"]
end
OpsPlane --> NodeletA
OpsPlane --> NodeletB
subgraph MCPServers["MCP Servers"]
MCPLocal["stdio 模式<br/>本地子进程,跑在中心服务器"]
MCPRemote["SSE 模式<br/>远程进程,可部署在任意机器"]
end
Redis["Redis等其他后端组件"]
OpsPlane -->|"stdio"| MCPLocal
OpsPlane -->|"SSE"| MCPRemote
MCPRemote -.->|"连接"| Kafka
MCPRemote -.->|"连接"| Redis
MCPLocal -.->|"连接"| MySQL
MCPLocal -.->|"连接"| Redis
-
Ops Plane — 中心服务器。提供前端界面,内置 Agent 负责推理与工具调用。用户的问题在这里被转化为对 Nodelet 的查询请求,MCP 连接的启停与保活也由它统一管理。
-
Nodelet — 部署在每台 Docker 主机上的代理 Agent。对外暴露该主机上所有容器的列表、巡检和日志流,一台主机可以同时跑 MySQL、Redis 等多个容器。容器本身就是沙盒,大模型命令在容器内直接执行。首次运行自动生成配对 Token。
-
MCP Server — 两类部署模式:stdio(本地子进程,跑在中心服务器上)和 SSE(远程进程,可部署在任意机器上)。MCP Server 连接到具体容器(MySQL、Redis、ES 等),将容器的运维能力暴露为 LLM 可调用的工具。
graph TB
React["React Chat UI"] -->|"POST /api/runs"| RunAPI["Run API"]
React -->|"GET /api/runs/{id}/events"| SSE["SSE Stream"]
RunAPI --> AgentSession["AgentSession / Harness"]
AgentSession --> Agent["Agent State Machine"]
Agent --> Loop["runAgentLoop"]
Loop --> Provider["Provider Adapter"]
Provider --> Eino["CloudWeGo Eino Model"]
Loop --> ToolRunner["Tool Runtime"]
ToolRunner --> WorkspaceTools["Workspace Tools<br/>read / ls / grep / find<br/>bash / write / edit"]
ToolRunner --> OpsTools["Ops Tools<br/>nodelets / containers / logs"]
ToolRunner --> MCPTools["MCP Tools"]
AgentSession --> RuntimeSession["Session<br/>JSONL v1 tree"]
RuntimeSession --> Context["Leaf Context<br/>messages + model + tools<br/>compaction + branch summary"]
Context --> AgentSession
Agent -->|"AgentEvent"| SSE
SSE --> React
请求处理流程:
- Run 创建 — React 通过
POST /api/runs创建一次运行,后端恢复或新建AgentSession。 - 上下文构建 —
AgentSession从当前 JSONL leaf 回溯出消息、模型、thinking level、启用工具、compaction summary 和 branch summary。 - Agent Loop —
runAgentLoop追加用户消息,请求 Provider,流式接收 assistant message,执行工具,再把 tool result message 按原始 tool call 顺序写回上下文。 - Provider 与工具 — Provider 通过 Eino 绑定模型工具 schema;本地执行走
toolruntime,覆盖 workspace 工具、运维工具和 MCP 工具。 - 事件投影 —
AgentEvent通过 SSE 推给前端;消息是会话事实来源,事件是运行过程投影。run_done返回完整 session snapshot 覆盖前端增量状态。 - 持久化 —
message_end写入消息,turn_endflush pending session writes,agent_end标记 settled。Session JSONL v1 保留原始 tree、compaction details 和 branch summary details。
核心组件:
| 组件 | 源文件 | 职责 |
|---|---|---|
| AI Protocol | internal/agent/ai |
Agent message、content、tool definition、AgentEvent 协议 |
| Provider | internal/agent/ai/api + internal/agent/ai/provider |
OpenAI Compatible 流式 adapter、Provider 选择与模型创建 |
| Agent Core | internal/agent/core |
Agent 状态机、队列、abort、runAgentLoop、tool registry、schema 校验、顺序/并行执行和 hook |
| Agent Runtime | internal/agent/runtime |
AgentSession、Session JSONL v1 tree、资源加载、消息持久化、branch summary、workspace/ops tools 和 Skill store |
| Run API | internal/api/run_handlers.go |
/api/runs、事件订阅、abort |
| Session API | internal/api/runtime_session_handlers.go |
session list/detail/delete/branch |
| MCP Manager | internal/mcp/manager.go |
MCP 连接生命周期、工具动态注册、保活 |
| Skills | internal/agent/runtime + config/skills/ |
Skill 定义加载、可用列表渲染 |
- 自动识别 MySQL、Redis、PostgreSQL、MongoDB、Nginx、Elasticsearch、Kafka、Etcd 等常见服务。
- 查看容器环境变量、端口映射、健康状态、创建时间和实时日志。
- 从环境变量提取 DSN,并支持手动覆盖和 HTTP 健康检查。
- 用自然语言查询容器状态、日志和外部连接,例如“Redis 为什么慢?”。
- Agent Runtime 基于 CloudWeGo Eino provider 执行多轮工具调用,支持 abort、分支和完整事件时间线。
- Workspace 工具、运维工具、Skills 和 MCP 工具按任务进入模型可见工具列表,过程通过 SSE 实时展示。
- 支持 stdio 本地子进程和 SSE 远程连接。
- 内置 MySQL、Redis、Elasticsearch、Kafka、Etcd、Nacos MCP Server。
- 支持连接预填、按工具启停、单工具测试和 5 分钟保活。
- 按项目隔离服务器、容器视图和会话。
- 会话使用 DAG 结构和 JSONL 持久化,重启后可恢复。
- 会话支持 compaction entry 与 branch summary,运行时按 leaf context 恢复上下文。
- 命令在容器边界内执行,支持超时、输出截断和结构化结果。
- 单用户认证、HttpOnly JWT、Bearer Token、登录限流和 Nodelet API 限流。
- zap + lumberjack 结构化日志,控制台通过 SSE 查看服务端日志和 MCP stderr。
- Docker
- Docker Compose
- OpenAI 兼容的 API Key(AI 助手;支持 DeepSeek、OpenAI 等任何兼容提供商)
git clone git@github.com:agermel/oops.git
cd oops# 复制示例配置
cp config/config.example.yaml config/config.yaml编辑 config/config.yaml,填写 llm.provider、llm.api_key、llm.base_url 和 llm.model。
首次启动时会交互式创建用户(用户名 + 密码),系统会自动生成密码哈希。
Nodelet 通过 Web UI 的“服务器管理”面板添加。
使用 Docker Compose 构建并启动中心服务和本机 Nodelet:
cd deployment
docker compose up -d --buildOps Plane 监听 :8081,Nodelet 监听 :8686。首次运行会自动生成 Nodelet 认证 Token,默认持久化在 deployment/nodelet-data/token。
在浏览器打开 http://localhost:8081,登录即可。
在每台远端 Docker 主机上复制 deployment/docker-compose.nodelet.yml,将 OOPS_NODELET_PUBLIC_ADDRESS 改为该主机可被 Ops Plane 访问的地址,然后启动:
docker compose -f docker-compose.nodelet.yml up -d在 deployment/docker-compose.yml 的 oops.environment 中取消 OOPS_MCP_ALLOWED_COMMANDS 一行的注释,填入允许执行的 MCP 命令白名单(逗号分隔)。同时取消 OOPS_LLM_API_KEY 的注释并填入 API Key。
在 Web UI 的 MCP 管理面板中添加连接即可使用。镜像内置 mcp-servers/<name>/ 的固定依赖和启动脚本;Compose 仅将 mcp-servers/local/ 映射到同名容器子目录,供自定义脚本使用。
Kafka 使用 Confluent 官方 MCP Server(@confluentinc/mcp-confluent)。默认 Docker 镜像会在构建阶段预装并编译 Kafka MCP 依赖,运行时直接使用 /opt/oops/mcp-confluent/node_modules/.bin/mcp-confluent。裸机 Linux 部署时请安装 Node.js 22 LTS 和 npm,或通过 OOPS_MCP_NODE_BIN / OOPS_MCP_NPX_BIN 指向 Node 22 的二进制。
Kafka MCP 表单中的用户名 / 密码会生成 KAFKA_API_KEY / KAFKA_API_SECRET。Security Protocol 和 SASL Mechanism 会写入官方 server 的 --kafka-config-file,常见内网 Kafka 可使用 sasl_plaintext + PLAIN。示例:
bootstrap_servers: kafka.example.com:9094
username: root
password: <secret>
security_protocol: sasl_plaintext
sasl_mechanism: PLAIN架构相关可执行文件不纳入 Git。etcd 使用可复算源码树摘要构建,MySQL 使用固定 Go module revision 和 zip SHA-256 构建。三个 Python wrapper 各自使用隔离环境、uv.lock 和精确的 CPython 3.12.13;Docker 构建基镜像使用固定 OCI index 摘要:
./mcp-servers/etcd/build.sh
./mcp-servers/mysql/build.sh
OOPS_MCP_VENV_ROOT="$PWD/.mcp-venvs" ./scripts/sync-mcp-wrapper.sh redis
OOPS_MCP_VENV_ROOT="$PWD/.mcp-venvs" ./mcp-servers/redis/redis-mcp-server --helpmcp-servers/artifacts-manifest.json 记录来源、版本、平台、SHA-256、许可证、构建和校验命令。scripts/verify-artifacts.sh 校验清单结构、Go 源码或 module 输入、wrapper 与 lockfile 的哈希关联、uv 和 CPython 获取脚本、Docker 基镜像摘要,并拒绝 Git 索引中的架构二进制;CI 在固定解释器上执行锁定同步和无凭据 --help smoke。
oops/
├── cmd/
│ ├── oops/ # Ops Plane 中心服务入口
│ └── oops-nodelet/ # Nodelet Agent 入口
├── internal/
│ ├── api/ # HTTP REST API:路由、处理器、中间件
│ ├── auth/ # JWT 认证、bcrypt 哈希、用户存储、限流
│ ├── common/ # 共享工具(环境变量等)
│ ├── config/ # 配置加载(Viper)、项目存储、DSN 存储
│ ├── connection/ # 外部服务健康检查框架 + 注册表
│ ├── console/ # 集中化日志控制台(SSE 推送至浏览器)
│ ├── docker/ # Docker 客户端、22 种服务检测、DSN 提取
│ ├── exec/ # 沙盒命令执行:超时 + 输出截断 + 结构化结果(Nodelet 侧)
│ ├── llm/ # AI Protocol、Agent Core、Session、Provider、工具、Skills
│ ├── logutil/ # 结构化日志(zap + lumberjack 轮转)
│ ├── mcp/ # MCP 管理器、客户端、工具注册、保活
│ ├── nodelet/ # Nodelet HTTP 服务端、客户端、管理器、探活
│ ├── store/ # 通用 JSON 文件持久化(原子写入)
│ └── web/ # 静态文件服务 + SPA 认证包裹
├── web/ # React SPA(TypeScript, Vite, Lucide 图标)
│ └── src/components/ # UI 组件(30+ 组件)
├── config/ # 配置文件、Skills、LLM Prompts
├── deployment/ # Nodelet Dockerfile 与 docker-compose
├── mcp-servers/ # MCP Server 源码、固定 wrapper 与供应链清单
│ ├── mysql/ # MySQL MCP Server
│ ├── redis/ # Redis MCP Server
│ ├── elasticsearch/ # Elasticsearch MCP Server
│ ├── kafka/ # Kafka MCP Server
│ ├── etcd/ # Etcd MCP Server(含 8 个工具)
│ └── nacos/ # Nacos MCP Server
└── data/ # 运行时数据:SQLite、YAML 用户、JSONL 会话
在 config/skills/ 下创建 .md 文件,Skill 通过 fsnotify 热加载,保存后生效:
---
name: my-skill
description: 简短描述这个 Skill 的功能
icon: Zap
label: 我的技能
color: blue
---
你的 Skill 指令内容。LLM 决定加载此 Skill 时,内容会被注入系统提示词。- 将源码、固定版本的 wrapper 或构建脚本放入
mcp-servers/<name>/;Compose 部署的自定义脚本放入mcp-servers/local/<name>/,不要提交架构相关二进制。 - 在
mcp-servers/artifacts-manifest.json记录来源、版本、平台、SHA-256、许可证、构建和校验命令。 - 在 Web UI 的 MCP 管理面板中添加连接,配置会写入
data/runtime.db;连接支持stdio(本地子进程)和sse(远程)两种传输模式。
常用分层检查:
仓库 CI 读取 GitHub Actions variable OOPS_SENSITIVE_PATTERN;变量为空、匹配到敏感词或扫描命令异常都会使门禁失败。
go test -count=1 ./internal/agent/ai ./internal/agent/ai/api ./internal/agent/ai/provider ./internal/agent/core ./internal/agent/runtime ./internal/api
go test -race -count=1 ./internal/agent/core ./internal/agent/runtime ./internal/api
go test -count=1 ./...
(cd web && npm run build)
(cd web && npm test)
git diff --check -- internal web README.md
rg -n -i "$OOPS_SENSITIVE_PATTERN" --hidden --glob '!.omx/**' --glob '!AGENTS.md' --glob '!.git/**' .边界检查:
| 区域 | 重点 |
|---|---|
| Protocol | JSON snapshot 覆盖 message、content、tool、AgentEvent |
| Agent Core | mock stream 覆盖 tool call、tool error、parallel order、max turns、abort |
| Agent Runtime | schema 校验、hook、顺序/并行、workspace path guard、Session JSONL v1、leaf context、branch summary、文件读取 |
| API | /api/runs SSE 顺序、Session API、abort |
| Frontend | AgentEvent reducer、Session Tree、工具列表、构建产物 |
MIT — 详见 LICENSE 文件。
Oops — 基础设施,不出意外。