# 容器化部署

<cite>
**本文档引用的文件**
- [docker-compose.yml](file://docker-nginx/docker-compose.yml)
- [bookapi.conf](file://docker-nginx/bookapi.conf)
- [README.md](file://docker-nginx/README.md)
- [DEPLOY.md](file://docs/DEPLOY.md)
- [DEPLOY_PROD.md](file://DEPLOY_PROD.md)
- [server/src/app.ts](file://server/src/app.ts)
- [server/src/config/index.ts](file://server/src/config/index.ts)
- [server/src/services/redis.service.ts](file://server/src/services/redis.service.ts)
- [server/src/services/storage.service.ts](file://server/src/services/storage.service.ts)
- [server/package.json](file://server/package.json)
- [my-uniapp-vue3/package.json](file://my-uniapp-vue3/package.json)
</cite>

## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能考虑](#性能考虑)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录](#附录)

## 简介
本文件面向AI有声书生成平台的容器化部署，聚焦于基于Docker Compose的Nginx反向代理与后端服务编排。内容涵盖：
- Docker Compose配置结构与服务定义
- Nginx反向代理的端口映射、卷挂载与请求转发策略
- 容器间网络通信与数据持久化方案
- 开发与生产环境的配置差异（环境变量、配置文件挂载、日志输出）
- 容器生命周期管理（启动/停止/重启）与健康检查、自动重启机制

## 项目结构
围绕容器化部署的关键文件与目录如下：
- docker-nginx：包含Nginx反向代理的Compose与配置
- server：后端Node.js应用（Koa）
- my-uniapp-vue3：前端UniApp构建产物（H5）
- docs/DEPLOY.md：传统部署与PM2管理说明（参考）
- DEPLOY_PROD.md：生产环境部署与宝塔Nginx配置说明（参考）

```mermaid
graph TB
subgraph "宿主机"
Host["宿主机网络<br/>端口映射: 80->80"]
end
subgraph "容器编排"
Nginx["Nginx容器<br/>nginx-bookapi"]
Backend["后端容器<br/>server"]
end
subgraph "存储"
Uploads["上传目录<br/>/data/ai/audio/server/uploads"]
Videos["视频目录<br/>/data/ai/audio/server/public/videos"]
EnvFile[".env 环境变量<br/>/data/ai/audio/server/.env"]
end
Host --> |"80/tcp"| Nginx
Nginx --> |"http://host.docker.internal:3000"| Backend
Backend --> |"MySQL:3306"| Host
Backend --> |"Redis:6379"| Host
Backend -. 卷挂载 .-> Uploads
Backend -. 卷挂载 .-> Videos
Backend -. 卷挂载 .-> EnvFile
```

图表来源
- [docker-compose.yml:1-12](file://docker-nginx/docker-compose.yml#L1-L12)
- [bookapi.conf:1-15](file://docker-nginx/bookapi.conf#L1-L15)
- [DEPLOY_PROD.md:266-294](file://DEPLOY_PROD.md#L266-L294)

章节来源
- [docker-compose.yml:1-12](file://docker-nginx/docker-compose.yml#L1-L12)
- [bookapi.conf:1-15](file://docker-nginx/bookapi.conf#L1-L15)
- [DEPLOY.md:1-251](file://docs/DEPLOY.md#L1-L251)
- [DEPLOY_PROD.md:1-393](file://DEPLOY_PROD.md#L1-L393)

## 核心组件
- Nginx反向代理服务
  - 使用官方Nginx镜像，容器名为nginx-bookapi
  - 将宿主80端口映射至容器80端口
  - 挂载bookapi.conf作为只读配置文件
  - 通过extra_hosts允许容器访问宿主机host.docker.internal
  - 重启策略unless-stopped，实现异常退出后的自动重启
- 后端服务（server）
  - 基于Node.js/Koa，监听配置中的端口（默认3000）
  - 提供/api/*路由与/health健康检查接口
  - 通过环境变量控制端口、TTS模型、存储类型、Redis等
  - 依赖MySQL与Redis，支持阿里云OSS或本地存储
- 前端（my-uniapp-vue3）
  - 构建产物位于dist/，可由Nginx直接提供静态文件服务
  - 生产环境Nginx配置中指向/data/ai/audio/frontend/build/h5

章节来源
- [docker-compose.yml:1-12](file://docker-nginx/docker-compose.yml#L1-L12)
- [bookapi.conf:1-15](file://docker-nginx/bookapi.conf#L1-L15)
- [server/src/app.ts:92-94](file://server/src/app.ts#L92-L94)
- [server/src/config/index.ts:69-117](file://server/src/config/index.ts#L69-L117)
- [server/package.json:1-60](file://server/package.json#L1-L60)
- [my-uniapp-vue3/package.json:1-65](file://my-uniapp-vue3/package.json#L1-L65)

## 架构总览
容器化部署采用“Nginx反向代理 + 后端服务”的双容器模式。Nginx负责域名解析与HTTP请求转发，后端处理业务逻辑与数据访问。

```mermaid
sequenceDiagram
participant Client as "客户端浏览器"
participant Nginx as "Nginx容器"
participant Backend as "后端容器"
Client->>Nginx : "HTTP 请求 (bookapi.rrbrr.com)"
Nginx->>Nginx : "解析bookapi.conf<br/>设置X-Forwarded-*头"
Nginx->>Backend : "转发到 http : //host.docker.internal : 3000"
Backend->>Backend : "路由匹配 /api/*"
Backend-->>Nginx : "响应 (JSON/静态资源)"
Nginx-->>Client : "返回响应"
```

图表来源
- [bookapi.conf:5-13](file://docker-nginx/bookapi.conf#L5-L13)
- [server/src/app.ts:92-130](file://server/src/app.ts#L92-L130)

## 详细组件分析

### Nginx反向代理服务
- 服务名称与镜像
  - 服务名：nginx
  - 镜像：nginx:latest
  - 容器名：nginx-bookapi
- 端口映射
  - "80:80"：将宿主机80端口映射到容器80端口
- 卷挂载
  - ./bookapi.conf:/etc/nginx/conf.d/bookapi.conf:ro：挂载只读配置文件
- 网络与主机访问
  - extra_hosts配置允许容器解析host.docker.internal
- 重启策略
  - unless-stopped：容器非正常退出时自动重启

```mermaid
flowchart TD
Start(["启动 docker-compose"]) --> Pull["拉取nginx镜像"]
Pull --> Create["创建nginx-bookapi容器"]
Create --> Mount["挂载bookapi.conf<br/>只读"]
Mount --> Expose["映射端口80:80"]
Expose --> ExtraHosts["配置host.docker.internal"]
ExtraHosts --> RestartPolicy["设置重启策略: unless-stopped"]
RestartPolicy --> Ready(["Nginx就绪"])
```

图表来源
- [docker-compose.yml:1-12](file://docker-nginx/docker-compose.yml#L1-L12)

章节来源
- [docker-compose.yml:1-12](file://docker-nginx/docker-compose.yml#L1-L12)
- [bookapi.conf:1-15](file://docker-nginx/bookapi.conf#L1-L15)
- [README.md:1-41](file://docker-nginx/README.md#L1-L41)

### 后端服务（server）
- 应用入口与路由
  - 健康检查：GET /health
  - 路由注册：/api/*各类模块路由
- 环境变量与配置
  - 端口：优先SERVER_PORT，其次PORT，默认3000
  - JWT密钥与过期时间
  - 阿里云百炼TTS相关配置
  - 存储类型：oss或local
  - Redis连接参数
- 依赖服务
  - MySQL：Prisma连接
  - Redis：缓存与队列
  - OSS：对象存储（可选）

```mermaid
classDiagram
class Config {
+number port
+string nodeEnv
+object jwt
+object dashscope
+object models
+object upload
}
class RedisService {
+isAvailable() boolean
+get(key) Promise~string|null~
+set(key,value,ttl) Promise~boolean~
+getJSON(key) Promise~any~
+setJSON(key,value,ttl) Promise~boolean~
+del(key) Promise~boolean~
+delPattern(pattern) Promise~boolean~
+hset(key,field,value) Promise~boolean~
+hget(key,field) Promise~string|null~
+hgetall(key) Promise~object|null~
}
class StorageService {
+setStorageType(type)
+getStorageType() StorageType
+uploadAudio(localPath,audioId) Promise~string~
+uploadVideo(localPath,videoId) Promise~string~
+uploadCover(localPath,bookId) Promise~string~
+uploadFile(localPath,category,id) Promise~string~
+uploadBuffer(buffer,objectKey,content) Promise~string~
+deleteFile(url) Promise~void~
+deleteDirectory(prefix,id) Promise~void~
+downloadFile(url) Promise~Buffer~
+getSignedUrl(url,expires) Promise~string~
}
Config --> RedisService : "读取Redis配置"
Config --> StorageService : "读取存储类型"
```

图表来源
- [server/src/config/index.ts:69-117](file://server/src/config/index.ts#L69-L117)
- [server/src/services/redis.service.ts:1-200](file://server/src/services/redis.service.ts#L1-L200)
- [server/src/services/storage.service.ts:1-200](file://server/src/services/storage.service.ts#L1-L200)

章节来源
- [server/src/app.ts:92-130](file://server/src/app.ts#L92-L130)
- [server/src/config/index.ts:69-117](file://server/src/config/index.ts#L69-L117)
- [server/src/services/redis.service.ts:1-200](file://server/src/services/redis.service.ts#L1-L200)
- [server/src/services/storage.service.ts:1-200](file://server/src/services/storage.service.ts#L1-L200)

### 容器间网络通信机制
- 默认网络
  - Docker Compose默认创建一个桥接网络，容器可通过服务名相互访问
- 宿主机访问
  - Nginx容器通过extra_hosts解析host.docker.internal
  - 在容器内使用http://host.docker.internal:3000访问宿主机上的后端服务
- 端口暴露
  - 宿主机80端口映射至Nginx容器80端口
  - 后端服务监听配置端口（默认3000），需确保未被占用

章节来源
- [docker-compose.yml:9-11](file://docker-nginx/docker-compose.yml#L9-L11)
- [bookapi.conf:7-7](file://docker-nginx/bookapi.conf#L7-L7)

### 数据持久化方案
- 上传与视频文件
  - 建议将后端uploads与public/videos目录以卷挂载方式持久化
  - 生产环境示例路径：/data/ai/audio/server/uploads、/data/ai/audio/server/public/videos
- 环境变量
  - 建议将.env文件以卷挂载方式注入容器，便于动态调整配置
- 数据库
  - MySQL与Redis建议独立容器或外部服务，通过环境变量连接

章节来源
- [DEPLOY_PROD.md:308-317](file://DEPLOY_PROD.md#L308-L317)
- [server/src/config/index.ts:113-117](file://server/src/config/index.ts#L113-L117)

### 开发环境与生产环境差异
- 端口与域名
  - 开发：Nginx监听80，代理到宿主机host.docker.internal:3000
  - 生产：宝塔Nginx监听80/443，反向代理到127.0.0.1:3100
- 环境变量
  - 生产示例包含：NODE_ENV、SERVER_PORT、JWT_SECRET、DASHSCOPE_*、DATABASE_URL、STORAGE_TYPE、REDIS_*、OSS_*、MINIMAX_API_KEY
- 配置文件挂载
  - 开发：Nginx配置文件通过卷挂载
  - 生产：宝塔面板管理Nginx配置，路径位于/www/server/panel/vhost/nginx/
- 日志输出
  - 后端使用Winston记录日志；生产环境建议结合宝塔日志或容器日志收集
  - Nginx访问/错误日志：/var/log/nginx/access.log、/var/log/nginx/error.log

章节来源
- [README.md:1-41](file://docker-nginx/README.md#L1-L41)
- [DEPLOY.md:140-197](file://docs/DEPLOY.md#L140-L197)
- [DEPLOY_PROD.md:105-144](file://DEPLOY_PROD.md#L105-L144)
- [DEPLOY_PROD.md:146-245](file://DEPLOY_PROD.md#L146-L245)

## 依赖关系分析
- 后端服务依赖
  - 数据库：Prisma连接MySQL
  - 缓存：ioredis连接Redis
  - 存储：ossService或本地FS
- Nginx依赖
  - 反向代理到后端容器的host.docker.internal:3000
- 前端依赖
  - 构建产物H5目录由Nginx提供静态文件服务

```mermaid
graph LR
Nginx["Nginx容器"] --> Backend["后端容器"]
Backend --> MySQL["MySQL服务"]
Backend --> Redis["Redis服务"]
Backend --> OSS["阿里云OSS"]
Frontend["前端H5"] --> Nginx
```

图表来源
- [server/src/app.ts:138-151](file://server/src/app.ts#L138-L151)
- [server/src/services/redis.service.ts:7-38](file://server/src/services/redis.service.ts#L7-L38)
- [server/src/services/storage.service.ts:43-63](file://server/src/services/storage.service.ts#L43-L63)
- [DEPLOY_PROD.md:266-294](file://DEPLOY_PROD.md#L266-L294)

章节来源
- [server/src/app.ts:138-151](file://server/src/app.ts#L138-L151)
- [server/src/services/redis.service.ts:1-200](file://server/src/services/redis.service.ts#L1-L200)
- [server/src/services/storage.service.ts:1-200](file://server/src/services/storage.service.ts#L1-L200)
- [DEPLOY_PROD.md:266-294](file://DEPLOY_PROD.md#L266-L294)

## 性能考虑
- Nginx静态资源缓存与压缩
  - 生产Nginx配置中对JS/CSS/图片设置了较长缓存与immutable属性
- 后端性能监控
  - 后端内置性能监控中间件与指标接口（/api/metrics）
- 存储与缓存
  - Redis缓存提升热点数据访问性能
  - OSS适合大规模静态资源分发
- 并发与队列
  - 后端使用队列处理长耗时任务（书籍生成等）

章节来源
- [server/src/app.ts:23-24](file://server/src/app.ts#L23-L24)
- [server/src/app.ts:97-97](file://server/src/app.ts#L97-L97)
- [server/src/services/redis.service.ts:1-200](file://server/src/services/redis.service.ts#L1-L200)
- [DEPLOY_PROD.md:223-237](file://DEPLOY_PROD.md#L223-L237)

## 故障排查指南
- Nginx 502/504
  - 检查后端服务是否启动且监听指定端口
  - 核对Nginx配置与反代地址
- 容器无法访问宿主机
  - 确认extra_hosts配置与host.docker.internal解析
  - 若无法解析，改用宿主机局域网IP直连
- 后端服务无法启动
  - 查看PM2日志或容器日志
  - 检查环境变量与数据库连接
- 数据库连接失败
  - 检查MySQL容器状态与密码
  - 使用Prisma迁移命令进行数据库同步

章节来源
- [README.md:30-41](file://docker-nginx/README.md#L30-L41)
- [DEPLOY.md:200-214](file://docs/DEPLOY.md#L200-L214)
- [DEPLOY_PROD.md:348-375](file://DEPLOY_PROD.md#L348-L375)

## 结论
本容器化方案以Nginx作为统一入口，配合后端服务实现高可用与易维护的部署架构。通过合理的端口映射、卷挂载与环境变量管理，可在开发与生产环境中快速切换。建议在生产中结合宝塔面板或Kubernetes进行更精细的资源调度与监控。

## 附录

### 容器启动/停止/重启标准流程
- 启动
  - 开发：进入docker-nginx目录，执行docker-compose up -d
  - 验证：curl http://bookapi.rrbrr.com/api/health
- 停止
  - docker-compose down
- 重启
  - docker-compose restart
- 重载Nginx配置（开发）
  - docker-compose exec nginx nginx -s reload

章节来源
- [README.md:5-28](file://docker-nginx/README.md#L5-L28)

### 健康检查与自动重启
- 健康检查
  - 后端提供/health接口，可用于外部探针或容器编排健康检查
- 自动重启
  - Nginx容器设置restart: unless-stopped
  - 生产环境可结合PM2实现后端进程自动重启

章节来源
- [server/src/app.ts:92-94](file://server/src/app.ts#L92-L94)
- [docker-compose.yml:11-11](file://docker-nginx/docker-compose.yml#L11-L11)
- [DEPLOY.md:161-185](file://docs/DEPLOY.md#L161-L185)