# Docker 生产环境部署指南

## 架构概览

```
                    ┌──────────────────────────────────────────────┐
                    │              Docker Network (zm-rag-net)     │
   :10038           │                                              │
 ┌────────┐  HTTP   │  ┌──────────┐       ┌──────────────┐         │
 │ Client ├────────►│  │ Frontend │──────►│   Backend    │         │
 └────────┘         │  │ (Nginx)  │ proxy │ (FastAPI)    │         │
                    │  └──────────┘       │   :8900      │         │
                    │                     └──────┬───────┘         │
                    │                            │                 │
                    │         ┌──────────────────┼────────┐        │
                    │         ▼         ▼        ▼        ▼        │
                    │  ┌───────────┐ ┌─────┐ ┌──────┐ ┌───────┐    │
                    │  │OpenSearch │ │Neo4j│ │Redis │ │ MySQL │    │
                    │  │  :9200    │ │:7687│ │:6379 │ │ :3306 │    │
                    │  └───────────┘ └─────┘ └──┬───┘ └───────┘    │
                    │                           │                  │
                    │                    ┌──────┴──────┐           │
                    │                    │Celery Worker│           │
                    │                    └──────┬──────┘           │
                    │                           │                  │
                    │                    ┌──────┴──────┐           │
                    │                    │Doc Converter│           │
                    │                    │   :18800    │           │
                    │                    └─────────────┘           │
                    └──────────────────────────────────────────────┘
```

### 服务清单

| 服务 | 技术栈 | 用途 | 对外端口 |
|------|--------|------|----------|
| frontend | Nginx + Vue 3 | 前端静态文件 + 反向代理 | **10038** |
| backend | FastAPI + Uvicorn | REST API + SSE | 内网 |
| celery-worker | Celery + Redis | 异步文档处理任务 | — |
| opensearch | OpenSearch 2.19 + IK 分词 | 全文搜索 + 向量搜索 | 内网 |
| opensearch-dashboards | OpenSearch Dashboards | 搜索可视化运维 | **5601** |
| neo4j | Neo4j 5 Community | 知识图谱 | 内网 |
| redis | Redis Alpine | 缓存 + Celery Broker | 内网 |
| mysql | MySQL 8.0 | 会话持久化 + 文档元数据 | 内网 |
| doc-converter | Spring Boot + Spire.Office | 文档格式转换 | 内网 |

---

## 前置要求

- Linux 服务器（推荐 Ubuntu 22.04+ / CentOS 8+）
- Docker Engine 24+
- Docker Compose v2.20+
- 最低配置：8 核 CPU / 32GB RAM / 100GB SSD
- 推荐配置：16 核 CPU / 64GB RAM / 500GB SSD

### 系统参数调优

OpenSearch 需要调整系统参数，否则会启动失败：

```bash
# 临时生效
sudo sysctl -w vm.max_map_count=262144

# 永久生效
echo "vm.max_map_count=262144" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
```

---

## 快速部署

### 1. 克隆项目

```bash
git clone <repo-url> /opt/zm-rag
cd /opt/zm-rag/docker
```

### 2. 配置环境变量

```bash
# cp .env.prod.example .env.prod
vim .env.prod
```

**必须修改的变量：**

| 变量 | 说明 | 示例 |
|------|------|------|
| `LLM_API_KEY` | 大模型 API Key（DashScope） | `sk-xxxx` |
| `EMBEDDING_API_KEY` | Embedding API Key | `sk-xxxx` |
| `JWT_SECRET` | JWT 签名密钥（64 字符随机字符串） | `openssl rand -hex 32` |
| `MYSQL_ROOT_PASSWORD` | MySQL root 密码 | 强密码 |
| `NEO4J_PASSWORD` | Neo4j 密码 | 强密码 |
| `CORS_ORIGINS` | 允许的前端域名 | `["http://192.168.1.100:10038"]` |
| `FILE_STORAGE_PATH` | 宿主机文件存储路径 | `/home/app/zm-rag/data/files` |

### 3. 创建数据目录

```bash
sudo mkdir -p /home/app/zm-rag/data/files
sudo chmod 777 /home/app/zm-rag/data/files
```

### 4. 构建 Java 文档转换服务 JAR（首次部署）

```bash
cd /home/app/zm-rag/converter
mvn package -DskipTests
cd /home/app/zm-rag/docker
```

### 5. 启动全部服务

```bash
docker compose -f docker-compose.prod.yml --env-file .env.prod up -d --build
```

首次启动需要构建镜像，大约 5-10 分钟。

### 6. 验证部署

```bash
# 查看所有服务状态（等待所有服务变为 healthy）
docker compose -f docker-compose.prod.yml ps

# 测试前端
curl http://localhost:10038

# 测试后端 API（通过 Nginx 代理）
curl http://localhost:10038/api/v1/health

# 查看日志
docker compose -f docker-compose.prod.yml logs -f backend
```

---

## 常用运维命令

### 服务管理

```bash
cd /opt/zm-rag/docker

# 启动
docker compose -f docker-compose.prod.yml --env-file .env.prod up -d

# 停止
docker compose -f docker-compose.prod.yml down

# 重启单个服务
docker compose -f docker-compose.prod.yml restart backend

# 重新构建并启动（代码更新后）
docker compose -f docker-compose.prod.yml --env-file .env.prod up -d --build backend celery-worker frontend

# 仅重建前端
docker compose -f docker-compose.prod.yml --env-file .env.prod up -d --build frontend
```

### 日志查看

```bash
# 查看所有服务日志
docker compose -f docker-compose.prod.yml logs -f

# 查看特定服务日志
docker compose -f docker-compose.prod.yml logs -f backend
docker compose -f docker-compose.prod.yml logs -f celery-worker

# 查看最近 100 行
docker compose -f docker-compose.prod.yml logs --tail 100 backend
```

### 数据备份

```bash
# MySQL 备份
docker exec zm-rag-prod-mysql mysqldump -uroot -p<password> zm_rag > backup_$(date +%Y%m%d).sql

# Neo4j 备份（需要先停止 Neo4j）
docker compose -f docker-compose.prod.yml stop neo4j
docker run --rm -v zm-rag-prod_neo4j_data:/data -v $(pwd)/backup:/backup alpine \
  tar czf /backup/neo4j_$(date +%Y%m%d).tar.gz /data
docker compose -f docker-compose.prod.yml start neo4j

# 文件存储备份
tar czf files_backup_$(date +%Y%m%d).tar.gz /home/app/zm-rag/data/files/
```

### 数据清理

```bash
# 清理未使用的 Docker 资源
docker system prune -f

# 清理构建缓存
docker builder prune -f
```

---

## 配置文件说明

```
docker/
├── docker-compose.yml          # 开发环境（本地使用，不要在服务器上用这个）
├── docker-compose.prod.yml     # 生产环境
├── .env                        # 开发环境变量
├── .env.prod.example           # 生产环境变量模板
├── backend/
│   ├── Dockerfile              # 开发用（仅 celery worker）
│   ├── Dockerfile.prod         # 生产用（backend + celery-worker 共用）
│   └── .env.docker             # Docker 内网地址配置
├── frontend/
│   └── Dockerfile.prod         # 前端生产镜像（多阶段构建）
├── nginx/
│   ├── nginx.conf              # 开发用 Nginx 配置
│   └── nginx.prod.conf         # 生产用 Nginx 配置（Docker 内网代理）
└── opensearch/
    ├── Dockerfile              # OpenSearch + IK 分词插件
    ├── opensearch.yml          # OpenSearch 配置
    └── analysis/               # 同义词等分析器配置
```

---

## 性能调优

### Uvicorn Workers

```env
# .env.prod 中设置，建议 CPU 核数 × 2 + 1
UVICORN_WORKERS=9    # 例如 4 核 CPU → 9
```

### OpenSearch 内存

```env
# 建议设为可用内存的 50%，但不超过 32GB
OPENSEARCH_JAVA_OPTS=-Xms8g -Xmx8g
```

### Neo4j 内存

```env
NEO4J_HEAP_INIT=2g
NEO4J_HEAP_MAX=4g
NEO4J_PAGECACHE=2g
```

### Redis 内存

```env
REDIS_MAXMEMORY=4gb
```

---

## 故障排查

### 服务无法启动

```bash
# 查看具体错误
docker compose -f docker-compose.prod.yml logs <service-name>

# 常见问题
# 1. OpenSearch 报 max_map_count 错误 → 执行 sysctl -w vm.max_map_count=262144
# 2. 端口被占用 → netstat -tlnp | grep <port>
# 3. 内存不足 → free -h，适当调低 JVM 参数
```

### Backend 连不上基础设施

```bash
# 进入容器调试
docker exec -it zm-rag-prod-backend bash

# 测试连通性
curl http://opensearch:9200
curl http://doc-converter:18800/actuator/health
redis-cli -h redis ping
```

### 前端页面空白

```bash
# 检查前端构建产物
docker exec zm-rag-prod-frontend ls /usr/share/nginx/html/

# 检查 Nginx 配置
docker exec zm-rag-prod-frontend nginx -t

# 检查 Nginx 日志
docker logs zm-rag-prod-frontend
```

---

## 更新部署

### 代码更新

```bash
cd /opt/zm-rag
git pull

cd docker
# 重新构建应用服务（不影响基础设施数据）
docker compose -f docker-compose.prod.yml --env-file .env.prod up -d --build backend celery-worker frontend
```

### 仅更新前端

```bash
docker compose -f docker-compose.prod.yml --env-file .env.prod up -d --build frontend
```

### 仅更新后端

```bash
docker compose -f docker-compose.prod.yml --env-file .env.prod up -d --build backend celery-worker
```
