Files
qiming/qiming-rcoder/docker/README.md
2026-06-01 13:54:52 +08:00

695 lines
16 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Docker 本地测试配置说明
> 本文档说明如何在本地使用 Docker Compose 启动 RCoder 开发环境包含完整的监控服务Pyroscope、Prometheus、Grafana和 eBPF 诊断工具。
## 📑 目录
- [快速开始](#-快速开始)
- [环境要求](#-环境要求)
- [架构概览](#-架构概览)
- [监控服务](#-监控服务)
- [配置说明](#-配置说明)
- [常用命令](#-常用命令)
- [测试页面](#-测试页面)
- [eBPF 诊断工具](#-ebpf-诊断工具)
- [故障排查](#-故障排查)
- [常见问题](#-常见问题)
- [目录结构](#-目录结构)
---
## ⚡ 快速开始
### 一键启动
```bash
# 1. 构建镜像
make dev-build
# 2. 启动所有服务(包含监控)
make dev-up
# 3. 查看日志
make dev-logs
```
### 访问服务
| 服务 | 地址 | 用途 |
|------|------|------|
| **Pyroscope** | http://localhost:4040 | CPU 性能分析火焰图 |
| **Prometheus** | http://localhost:9091 | 时序指标查询 |
| **Grafana** | http://localhost:3000 | 进程监控 Dashboard (admin/admin) |
### 创建测试容器
```bash
# 发送聊天请求,自动创建 agent_runner 容器
curl -X POST http://127.0.0.1:8088/computer/chat \
-H "Content-Type: application/json" \
-d '{"user_id": "user_123", "prompt": "hello"}'
```
---
## 💻 环境要求
### 必需组件
| 组件 | 版本要求 | 用途 |
|------|----------|------|
| **Docker** | 20.10+ | 容器运行时 |
| **Docker Compose** | 2.0+ | 多容器编排 |
| **Make** | 任意 | 构建自动化 |
| **Rust** | 1.75+ | 编译项目(本地开发) |
### 可选组件
| 组件 | 用途 |
|------|------|
| **Python 3** | 启动测试页面 HTTP 服务器 |
| **cURL** | API 测试 |
### 端口占用检查
启动前请确保以下端口未被占用:
```bash
# 检查端口占用
lsof -i :4040 # Pyroscope
lsof -i :9091 # Prometheus
lsof -i :3000 # Grafana
lsof -i :8088 # RCoder API
```
---
## 🏗️ 架构概览
### 整体架构
```mermaid
flowchart TB
subgraph Docker["🐳 Docker Compose 环境"]
direction TB
RCoder["RCoder 主服务<br/>端口: 8088<br/>镜像: master-rcoder:latest<br/>功能: HTTP API + 容器管理"]
subgraph Agent["Agent Runner 子容器(动态创建)"]
Runner["AI 代理运行时<br/>gRPC 服务端<br/>镜像: master-rcoder:latest"]
end
subgraph Monitoring["📊 监控服务"]
direction LR
Pyro["Pyroscope<br/>:4040"]
Prom["Prometheus<br/>:9091"]
Graf["Grafana<br/>:3000"]
Pyro --> Prom --> Graf
end
RCoder ==>|"gRPC<br/>内部网络"| Runner
end
style RCoder fill:#e1f5fe
style Runner fill:#fff3e0
style Pyro fill:#f3e5f5
style Prom fill:#e8f5e9
style Graf fill:#fce4ec
```
> **提示**: 在支持 Mermaid 的平台GitHub、GitLab、IDE 插件)上,上图会渲染为交互式流程图。
### 数据流向
```mermaid
flowchart LR
subgraph AgentRunner["Agent Runner 容器"]
direction TB
Alloy["Grafana Alloy"]
subgraph Collectors["数据采集器"]
EBPF["eBPF Profiler<br/>97 Hz"]
PE["Process Exporter<br/>15s"]
end
Alloy --> EBPF
Alloy --> PE
end
subgraph Storage["存储与分析"]
Pyro["Pyroscope<br/>火焰图 + Top 函数"]
Prom["Prometheus<br/>时序数据存储"]
end
subgraph Viz["可视化"]
Graf["Grafana<br/>统一 Dashboard"]
end
EBPF -->|"CPU 性能数据"| Pyro
PE -->|"进程指标"| Prom
Pyro --> Graf
Prom --> Graf
style AgentRunner fill:#e3f2fd
style Pyro fill:#f3e5f5
style Prom fill:#e8f5e9
style Graf fill:#fce4ec
```
---
## 📊 监控服务
### 服务概览
| 服务 | 端口 | 登录信息 | 数据源 | 用途 |
|------|------|----------|--------|------|
| **Pyroscope** | 4040 | 无需登录 | Alloy eBPF (97 Hz) | CPU 性能分析火焰图 |
| **Prometheus** | 9091 | 无需登录 | Alloy Process Exporter (15s) | 时序指标存储 |
| **Grafana** | 3000 | admin / admin | Prometheus | 可视化 Dashboard |
### Grafana Dashboard
**Dashboard 名称**: `Agent Runner 进程监控`
**包含面板**:
- **概览**: RSS/VSZ 内存、CPU 使用率、文件描述符
- **内存趋势**: RSS 和 VSZ 的时间序列图
- **I/O 监控**: 读取/写入速率
- **上下文切换**: 自愿/非自愿切换速率
- **线程详情**: 线程数量、FD 使用率
- **缺页错误**: 次要/主要缺页错误速率
**可用变量**:
- `project_id`: 过滤项目 ID
- `instance`: 过滤实例
- `process_name`: 过滤进程名称
- `resolution`: 查询分辨率 (15s, 30s, 1m, 5m, 15m)
---
## ⚙️ 配置说明
### 核心配置文件
#### `docker-compose.yml`
监控服务配置,定义所有服务容器。
**服务列表**:
```yaml
services:
rcoder: # 主 RCoder 服务
pyroscope: # CPU 性能分析服务器
prometheus: # 时序指标数据库
grafana: # 可视化平台
```
#### `config.yml`
本地 Docker 容器测试专用配置,用于在 docker-compose 启动的容器中测试动态启动子容器。
### 镜像配置
所有容器使用相同的镜像,确保环境一致性:
```yaml
# 主容器和子容器使用相同镜像
image: "master-rcoder:latest"
```
### 路径配置
| 类型 | 容器内路径 | 宿主机映射路径 | 说明 |
|------|-----------|---------------|------|
| **项目工作目录** | `/app/project_workspace` | `./docker/project_workspace` | 项目代码存放 |
| **日志目录** | `/app/logs` | `./docker/logs` | 容器日志输出 |
| **规范目录** | `/app/specs` | - | 规范文件存放 |
### 与生产环境对比
| 配置项 | 本地测试 | 生产环境 |
|--------|---------|---------|
| **镜像** | `master-rcoder:latest` | `registry.yichamao.com/rcoder:latest-arm64` |
| **配置文件** | `docker/config.yml` | `config.yml` |
| **项目路径** | `/app/project_workspace` | `./project_workspace` |
| **监控服务** | 完整Pyroscope + Prometheus + Grafana | 按需部署 |
---
## 🔧 常用命令
### Make 命令
```bash
# 构建镜像
make dev-build
# 启动服务
make dev-up
# 查看日志
make dev-logs
# 重启服务(代码修改后)
make dev-restart
# 停止服务
make dev-down
```
### Docker 命令
```bash
# 查看运行中的容器
docker ps | grep rcoder
# 查看容器日志
docker logs -f <container_id>
# 进入容器
docker exec -it <container_id> bash
# 检查容器资源使用
docker stats <container_id>
# 检查挂载点
docker inspect <container_id> | grep Mounts -A 20
```
### API 测试
```bash
# 发送聊天请求(创建容器)
curl -X POST http://127.0.0.1:8088/computer/chat \
-H "Content-Type: application/json" \
-d '{"user_id": "user_123", "prompt": "hello"}'
# 查询 Agent 状态
curl http://127.0.0.1:8088/agent/status/user_123
# 取消会话
curl -X POST http://127.0.0.1:8088/agent/session/cancel \
-H "Content-Type: application/json" \
-d '{"session_id": "<session_id>"}'
```
---
## 💚 健康检查
### 快速验证所有服务
```bash
# 一键检查所有服务状态
curl -s http://localhost:4040/health # Pyroscope
curl -s http://localhost:9091/-/healthy # Prometheus
curl -s http://localhost:3000/api/health # Grafana
curl -s http://localhost:8088/health # RCoder
```
### 检查脚本
```bash
# 保存为 check-health.sh
#!/bin/bash
services=(
"Pyroscope:4040:/health"
"Prometheus:9091:/-/healthy"
"Grafana:3000:/api/health"
"RCoder:8088:/health"
)
for service in "${services[@]}"; do
IFS=':' read -r name port endpoint <<< "$service"
if curl -s "http://localhost:${port}${endpoint}" > /dev/null 2>&1; then
echo "$name (${port})"
else
echo "$name (${port}) - 未响应"
fi
done
```
### 监控数据验证
```bash
# 检查 Prometheus 是否接收指标
curl -s 'http://localhost:9091/api/v1/query?query=up' | jq '.data.result[]'
# 检查 Pyroscope 是否有应用数据
curl -s 'http://localhost:4040/ingest?name=agent_runner' | jq
# 检查 Grafana 数据源连接
curl -s 'http://admin:admin@localhost:3000/api/datasources' | jq '.[] | select(.name=="Prometheus") | .isDefault'
```
---
## 🧪 测试页面
`test-page/` 目录提供 VNC、音频和输入法透传功能的集成测试。
### 文件说明
| 文件 | 说明 |
|------|------|
| `vnc-test.html` | 集成测试页面VNC + 音频 + IME |
| `opus-decoder.min.js` | Opus 音频解码库86KB |
### 支持功能
- **VNC 远程桌面**: WebSocket 连接到容器的 noVNC 服务
- **音频流播放**: 接收并播放容器的音频输出Opus 编码)
- **输入法透传**: 使用本地输入法输入到远程桌面
### 使用步骤
#### 1. 启动 HTTP 服务器
```bash
# 进入测试页面目录(从项目根目录执行)
cd docker/test-page
# 或者直接指定绝对路径
# cd $(git rev-parse --show-toplevel)/docker/test-page
# 使用 Python 启动服务器
python3 -m http.server 8000
```
#### 2. 访问测试页面
在浏览器打开http://127.0.0.1:8000/vnc-test.html
#### 3. 配置连接参数
**推荐使用 RCoder 代理模式**:
- RCoder 服务地址: `http://127.0.0.1:8088`
- User ID: `user_123`
- Project ID: 留空或填写实际项目 ID
#### 4. 创建测试容器
```bash
curl -X POST http://127.0.0.1:8088/computer/chat \
-H "Content-Type: application/json" \
-d '{"user_id": "user_123", "prompt": "hello"}'
```
---
## 🔬 eBPF 诊断工具
### 概述
RCoder 集成 eBPF 诊断工具,用于开发环境中快速定位进程阻塞和性能问题。
> **详细文档**: `/docker/rcoder-agent-runner/ebpf-tools/README.md`
### ⚠️ 安全警告
| 模式 | Feature | 容器特权 | 安全性 | 调试能力 |
|------|---------|----------|--------|----------|
| `make dev-restart` | `ebpf-debug` 启用 | 特权 (SYS_ADMIN) | ⚠️ 降低 | ✅ 完整 |
| 生产模式 | 默认关闭 | 限制 | ✅ 高 | ❌ 无 |
> **仅在受信任的调试环境使用 eBPF 模式!**
### 监控能力
| 工具 | 类型 | 频率 | 输出位置 |
|------|------|------|----------|
| **Alloy eBPF** | 持续 CPU 监控 | 97 Hz | Pyroscope Web UI |
| **Alloy Process Exporter** | 进程指标 | 15 秒 | Grafana Dashboard |
| **offcpu-monitor** | 阻塞火焰图 | 60 秒 | `/app/container-logs/diag/*.svg` |
| **syscall-monitor** | 系统调用追踪 | 60 秒 | `/app/container-logs/diag/*.log` |
### 快捷诊断命令
```bash
# 1. 进入容器
docker exec -it <container> bash
# 2. 获取 agent_runner 进程 PID
PID=$(pgrep agent_runner)
# 3. 执行诊断命令
e-offcpu $PID # CPU 性能分析(显示耗时函数)
e-flame $PID 60 # 生成 60 秒火焰图
e-profile $PID # 性能分析
e-all $PID # 综合诊断(包含所有分析)
```
### 导出诊断数据
```bash
# 导出所有诊断数据
docker cp <container>:/app/container-logs/diag ./diag-results
# 导出单个火焰图
docker cp <container>:/app/container-logs/diag/flame-<pid>.svg ./
```
---
## 🐛 故障排查
### 按症状分类
#### 症状:子容器无法启动
**可能原因**: 镜像不存在
```bash
# 检查镜像
docker images | grep master-rcoder
# 解决方案:重新构建
make dev-build
```
#### 症状:配置文件未生效
**可能原因**: 挂载路径错误
```bash
# 检查配置文件挂载
docker exec -it <container_id> cat /app/config.yml
# 检查日志
make dev-logs
```
#### 症状:监控服务无数据
**诊断步骤**:
```bash
# 1. 检查监控服务状态
docker ps | grep -E "pyroscope|prometheus|grafana"
# 2. 检查 agent_runner 容器
docker ps | grep agent_runner
# 3. 检查 Prometheus 指标
curl -s 'http://localhost:9091/api/v1/query?query=up' | jq
# 4. 检查 Alloy 日志
docker exec <container> tail -f /app/container-logs/diag/alloy.log
```
#### 症状Grafana 显示 "No Data"
**可能原因**: 没有 agent_runner 容器运行
**解决方案**:
1. 创建容器(发送聊天请求)
2. 等待 15-30 秒让数据采集
3. 刷新 Dashboard
#### 症状:端口冲突
**Prometheus 端口冲突**9090 → 9091:
```yaml
# docker-compose.yml 已配置端口映射
prometheus:
ports:
- "9091:9090" # 宿主机 9091 → 容器 9090
```
**检查端口占用**:
```bash
lsof -i :4040 # Pyroscope
lsof -i :9091 # Prometheus
lsof -i :3000 # Grafana
lsof -i :8088 # RCoder
```
### 系统化诊断流程
```mermaid
flowchart TD
Start["🐛 问题发生"]
Step1["1⃣ 检查容器状态<br/>docker ps"]
Step2["2⃣ 查看容器日志<br/>docker logs"]
Step3["3⃣ 检查网络连通性<br/>docker network inspect"]
Step4["4⃣ 检查资源使用<br/>docker stats"]
Step5["5⃣ 进入容器调试<br/>docker exec"]
Solve["✅ 问题解决"]
Start --> Step1
Step1 --> Step2
Step2 --> Step3
Step3 --> Step4
Step4 --> Step5
Step5 --> Solve
style Start fill:#ffcdd2
style Step1 fill:#e1f5fe
style Step2 fill:#e1f5fe
style Step3 fill:#e1f5fe
style Step4 fill:#fff3e0
style Step5 fill:#f3e5f5
style Solve fill:#c8e6c9
```
---
## ❓ 常见问题
### Q1: 如何修改镜像名称?
编辑 `docker-compose.yml`:
```yaml
services:
rcoder:
image: "your-custom-image:tag"
```
然后运行 `make dev-restart`
### Q2: 如何持久化监控数据?
编辑 `docker-compose.yml`,添加数据卷:
```yaml
services:
prometheus:
volumes:
- ./prometheus/data:/prometheus
grafana:
volumes:
- ./grafana/data:/var/lib/grafana
```
### Q3: 如何禁用某个监控服务?
注释掉 `docker-compose.yml` 中对应的服务配置。
### Q4: 如何调整资源限制?
编辑 `docker-compose.yml`:
```yaml
services:
rcoder:
deploy:
resources:
limits:
cpus: '2'
memory: 4G
```
### Q5: 容器间通信超时怎么办?
检查 Docker 网络:
```bash
# 查看网络
docker network ls
# 检查网络详情
docker network inspect rcoder_agent-network
# 测试连通性
docker exec <container1> ping <container2_ip>
```
### Q6: 如何清理所有容器和数据?
```bash
# 停止并删除所有容器
make dev-down
# 删除数据卷(谨慎操作)
docker volume prune
# 完全清理
docker system prune -a
```
---
## 📚 附录
### Prometheus 查询示例
```promql
# 内存使用趋势
process_resident_memory_bytes{project_id="user_123"}
# CPU 使用率
rate(process_cpu_seconds_total{project_id="user_123"}[30s]) * 100
# I/O 读取速率
rate(process_read_bytes_total{project_id="user_123"}[30s])
# 文件描述符使用率
process_open_fds{project_id="user_123"} / process_max_fds{project_id="user_123"}
# 上下文切换速率
rate(process_context_switches_total{project_id="user_123",context_switch_type="voluntary"}[30s])
```
### 目录结构
```
docker/
├── README.md # 本文档
├── config.yml # 容器内配置
├── docker-compose.yml # 服务编排配置
├── computer-cache/ # 计算机缓存
├── computer-project-workspace/ # 计算机项目工作区
├── grafana/ # Grafana 配置
│ └── provisioning/ # 自动配置
│ ├── dashboards/ # Dashboard 定义
│ └── datasources/ # 数据源配置
├── logs/ # 日志目录
├── project_workspace/ # 项目工作区
├── prometheus/ # Prometheus 配置
│ └── prometheus.yml # 规则文件
├── rcoder-agent-runner/ # Agent Runner 配置
│ └── ebpf-tools/ # eBPF 工具
│ └── README.md # 详细文档
├── rcoder-master/ # 主服务配置
├── start-rcoder.sh # 启动脚本
└── test-page/ # 测试页面
├── vnc-test.html # VNC 测试页面
└── opus-decoder.min.js # Opus 解码库
```
> **注意**: `Make` 命令在项目根目录的 `Makefile` 中定义,使用 `make -C docker` 或从项目根目录执行。
### 相关文档
- [项目主文档](../README.md)
- [CLAUDE.md](../CLAUDE.md) - 项目架构和开发指南
- [eBPF 工具详细文档](./rcoder-agent-runner/ebpf-tools/README.md)
- [Makefile](../Makefile) - 构建命令说明
---
**最后更新**: 2026-01-13
**维护者**: RCoder Team