docs: 合并 troubleshooting 目录到 deploy
This commit is contained in:
@@ -1,438 +0,0 @@
|
||||
# 群晖 NAS + Cloudflare Tunnel + 未认证企微 部署指南
|
||||
|
||||
> **适用范围**:阶段一功能测试
|
||||
> **目标域名**:`itdesk.amanzac.com`
|
||||
> **最后更新**:2026-06-07
|
||||
|
||||
---
|
||||
|
||||
## 架构总览
|
||||
|
||||
```
|
||||
HTTPS HTTP
|
||||
员工手机 ──────────→ Cloudflare Edge ──────────→ cloudflared ──→ nginx:80
|
||||
(企微H5) (自动SSL+CDN) Tunnel 容器 │
|
||||
┌────┴────┐
|
||||
│ 路由分发 │
|
||||
└────┬────┘
|
||||
┌──────┼──────┐
|
||||
│ │ │
|
||||
/itdesk/ /itagent/ /api/
|
||||
H5员工端 坐席工作台 后端
|
||||
```
|
||||
|
||||
**关键特点**:
|
||||
- ✅ 无需公网 IP
|
||||
- ✅ 无需 SSL 证书(Cloudflare 自动处理)
|
||||
- ✅ 无需开放 NAS 端口
|
||||
- ✅ 未认证企微可正常使用 OAuth2 + 消息 API
|
||||
|
||||
---
|
||||
|
||||
## §1 前置条件检查清单
|
||||
|
||||
| # | 条件 | 你的状态 | 说明 |
|
||||
|---|------|---------|------|
|
||||
| 1 | 群晖 NAS(DS220+ 及以上) | ✅ 已确认 | 需支持 Docker(ARM 机型需确认镜像兼容) |
|
||||
| 2 | Container Manager 已安装 | ✅ 已确认 | 套件中心安装 |
|
||||
| 3 | Cloudflare 账号 | ✅ 已确认 | 免费版即可 |
|
||||
| 4 | 域名 `amanzac.com` 已托管 Cloudflare | ✅ 已确认 | DNS 管理 → Cloudflare |
|
||||
| 5 | 企微管理后台权限 | ✅ 已确认 | 需配置自建应用 |
|
||||
| 6 | SSH 访问 NAS | ⬜ 待确认 | 需开启 SSH 以执行 docker compose 命令 |
|
||||
|
||||
---
|
||||
|
||||
## §2 Cloudflare Tunnel 配置
|
||||
|
||||
### 2.1 创建 Tunnel
|
||||
|
||||
1. 登录 [Cloudflare Zero Trust](https://one.dash.cloudflare.com/)
|
||||
2. 左侧菜单 → **Networks** → **Tunnels**
|
||||
3. 点击 **Create a tunnel**
|
||||
4. 选择 **Cloudflared** 类型
|
||||
5. 输入 Tunnel 名称,如 `itdesk-nas`
|
||||
6. 点击 **Save tunnel**
|
||||
|
||||
### 2.2 获取 Tunnel Token
|
||||
|
||||
创建完成后,页面会显示安装命令,其中包含 Token:
|
||||
|
||||
```bash
|
||||
# 示例安装命令
|
||||
cloudflared service install eyJhIjoiNjM1...
|
||||
# ^^^^^^^^^^^^
|
||||
# 这就是 Token
|
||||
```
|
||||
|
||||
**复制这个 Token**,后面要填到 `.env` 文件中。
|
||||
|
||||
### 2.3 配置 Tunnel 路由(Public Hostname)
|
||||
|
||||
在 Tunnel 创建页面,配置 **Public Hostname**:
|
||||
|
||||
| 字段 | 填写 | 说明 |
|
||||
|------|------|------|
|
||||
| Subdomain | `itdesk` | 前缀 |
|
||||
| Domain | `amanzac.com` | 你的域名 |
|
||||
| Type | `HTTP` | 容器内是 HTTP |
|
||||
| URL | `nginx` | Docker 容器名(同一网络内) |
|
||||
|
||||
> ⚠️ 注意:Type 选 **HTTP**(不是 HTTPS),因为 cloudflared 和 nginx 之间走的是容器内网 HTTP。SSL 由 Cloudflare Edge 终止。
|
||||
|
||||
点击 **Save tunnel**。
|
||||
|
||||
### 2.4 验证 DNS 记录
|
||||
|
||||
Cloudflare 会自动创建一条 CNAME 记录:
|
||||
- `itdesk.amanzac.com` → `cfargotunnel.com`
|
||||
|
||||
可在 Cloudflare Dashboard → DNS → Records 中确认。
|
||||
|
||||
---
|
||||
|
||||
## §3 项目文件部署到 NAS
|
||||
|
||||
### 3.1 上传项目文件
|
||||
|
||||
**方式一:Git Clone(推荐)**
|
||||
|
||||
如果 NAS 上有 Git:
|
||||
```bash
|
||||
# SSH 登录 NAS
|
||||
ssh admin@NAS_IP
|
||||
|
||||
# 创建项目目录
|
||||
mkdir -p /volume1/docker/wecom-it-desk
|
||||
cd /volume1/docker/wecom-it-desk
|
||||
|
||||
# 克隆项目
|
||||
git clone <你的仓库地址> .
|
||||
```
|
||||
|
||||
**方式二:SCP 上传**
|
||||
|
||||
从开发机上传构建好的文件:
|
||||
```powershell
|
||||
# 在 Windows PowerShell 中执行
|
||||
# 上传核心文件(不含 node_modules 和 .git)
|
||||
scp -r "D:\资料\03-项目开发\wecom_it_smart_desk\docker-compose.nas.yml" admin@NAS_IP:/volume1/docker/wecom-it-desk/
|
||||
scp -r "D:\资料\03-项目开发\wecom_it_smart_desk\.env.nas" admin@NAS_IP:/volume1/docker/wecom-it-desk/
|
||||
scp -r "D:\资料\03-项目开发\wecom_it_smart_desk\nginx" admin@NAS_IP:/volume1/docker/wecom-it-desk/
|
||||
scp -r "D:\资料\03-项目开发\wecom_it_smart_desk\backend" admin@NAS_IP:/volume1/docker/wecom-it-desk/
|
||||
scp -r "D:\资料\03-项目开发\wecom_it_smart_desk\frontend-h5\dist" admin@NAS_IP:/volume1/docker/wecom-it-desk/frontend-h5/dist/
|
||||
scp -r "D:\资料\03-项目开发\wecom_it_smart_desk\frontend-agent\dist" admin@NAS_IP:/volume1/docker/wecom-it-desk/frontend-agent/dist/
|
||||
```
|
||||
|
||||
**方式三:群晖 File Station**
|
||||
|
||||
把构建产物打包成 zip,通过 File Station 上传到 `/docker/wecom-it-desk/` 然后解压。
|
||||
|
||||
### 3.2 配置环境变量
|
||||
|
||||
```bash
|
||||
cd /volume1/docker/wecom-it-desk
|
||||
|
||||
# 复制模板
|
||||
cp .env.nas .env
|
||||
|
||||
# 编辑 .env 文件
|
||||
vi .env
|
||||
```
|
||||
|
||||
**必须修改的项**:
|
||||
|
||||
```bash
|
||||
# 1. 填入 Cloudflare Tunnel Token(从 §2.2 获取)
|
||||
CF_TUNNEL_TOKEN=eyJhIjoiNjM1... # ← 替换为你的实际 Token
|
||||
|
||||
# 2. 修改数据库密码
|
||||
POSTGRES_PASSWORD=YourStrongPassword123! # ← 替换为强密码
|
||||
|
||||
# 3. 如果 NAS 能访问公司内网 Dify,填入 Dify 配置
|
||||
# 如果不能访问,留空即可(AI 功能暂不可用,不影响阶段一)
|
||||
DIFY_API_URL=
|
||||
DIFY_API_KEY=
|
||||
```
|
||||
|
||||
### 3.3 构建前端(如果还没构建)
|
||||
|
||||
前端需要先在开发机(Windows)上构建,再上传 dist/ 目录:
|
||||
|
||||
```powershell
|
||||
# 在 Windows 开发机上
|
||||
cd "D:\资料\03-项目开发\wecom_it_smart_desk"
|
||||
|
||||
# 构建坐席端
|
||||
cd frontend-agent
|
||||
npm install
|
||||
npx vite build
|
||||
|
||||
# 构建 H5 员工端
|
||||
cd ..\frontend-h5
|
||||
npm install
|
||||
npx vite build
|
||||
```
|
||||
|
||||
构建产物在 `frontend-agent/dist/` 和 `frontend-h5/dist/` 中。
|
||||
|
||||
---
|
||||
|
||||
## §4 启动服务
|
||||
|
||||
### 4.1 SSH 登录 NAS 启动
|
||||
|
||||
```bash
|
||||
# SSH 登录 NAS
|
||||
ssh admin@NAS_IP
|
||||
|
||||
# 进入项目目录
|
||||
cd /volume1/docker/wecom-it-desk
|
||||
|
||||
# 启动所有容器(5 个容器)
|
||||
docker compose -f docker-compose.nas.yml up -d
|
||||
|
||||
# 等待约 30 秒,检查状态
|
||||
docker compose -f docker-compose.nas.yml ps
|
||||
```
|
||||
|
||||
**预期输出**:
|
||||
|
||||
| 容器名 | 状态 | 说明 |
|
||||
|--------|------|------|
|
||||
| wecom_it_cloudflared | Running | Cloudflare Tunnel |
|
||||
| wecom_it_nginx | Up (healthy) | 反向代理 |
|
||||
| wecom_it_backend | Up | FastAPI 后端 |
|
||||
| wecom_it_postgres | Up (healthy) | PostgreSQL |
|
||||
| wecom_it_redis | Up (healthy) | Redis |
|
||||
|
||||
### 4.2 验证服务
|
||||
|
||||
```bash
|
||||
# 1. 内网验证(在 NAS 上执行)
|
||||
curl http://localhost:18080/api/health
|
||||
# 预期输出: {"status":"ok","service":"wecom-it-smart-desk"}
|
||||
|
||||
# 2. 内网验证前端
|
||||
curl http://localhost:18080/itdesk/health
|
||||
# 预期输出: healthy
|
||||
|
||||
# 3. 公网验证(从任意有网络的设备)
|
||||
curl https://itdesk.amanzac.com/api/health
|
||||
# 预期输出: {"status":"ok","service":"wecom-it-smart-desk"}
|
||||
|
||||
# 4. 浏览器访问
|
||||
# H5 员工端: https://itdesk.amanzac.com/itdesk/
|
||||
# 坐席工作台: https://itdesk.amanzac.com/itagent/
|
||||
```
|
||||
|
||||
### 4.3 常用运维命令
|
||||
|
||||
```bash
|
||||
# 查看日志
|
||||
docker compose -f docker-compose.nas.yml logs -f backend # 后端日志
|
||||
docker compose -f docker-compose.nas.yml logs -f cloudflared # Tunnel 日志
|
||||
docker compose -f docker-compose.nas.yml logs -f nginx # Nginx 日志
|
||||
|
||||
# 重启某个服务
|
||||
docker compose -f docker-compose.nas.yml restart backend
|
||||
|
||||
# 停止所有服务
|
||||
docker compose -f docker-compose.nas.yml down
|
||||
|
||||
# 更新并重启(代码更新后)
|
||||
docker compose -f docker-compose.nas.yml up -d --build
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## §5 企微自建应用配置
|
||||
|
||||
### 5.1 创建自建应用
|
||||
|
||||
1. 登录 [企微管理后台](https://work.weixin.qq.com/wework_admin/frame)
|
||||
2. **应用管理** → **自建** → **创建应用**
|
||||
3. 填写:
|
||||
- 应用名称:`智能IT支持服务台`
|
||||
- 应用logo:上传一个图标
|
||||
- 可见范围:选择测试部门/人员
|
||||
|
||||
### 5.2 配置网页授权(OAuth2)
|
||||
|
||||
在应用详情页 → **网页授权及JS-SDK**:
|
||||
|
||||
| 配置项 | 填写 | 说明 |
|
||||
|--------|------|------|
|
||||
| 可信域名 | `itdesk.amanzac.com` | OAuth2 回调域名 |
|
||||
|
||||
> **验证方式**:Cloudflare Tunnel 已提供 HTTPS,下载企微提供的验证文件,放到 `frontend-h5/dist/` 根目录后重新构建。
|
||||
|
||||
### 5.3 配置应用主页
|
||||
|
||||
在应用详情页 → **应用主页**:
|
||||
|
||||
```
|
||||
https://itdesk.amanzac.com/itdesk/
|
||||
```
|
||||
|
||||
员工点击企微中的应用入口,直接打开 H5 页面。
|
||||
|
||||
### 5.4 配置接收消息(回调 URL)
|
||||
|
||||
在应用详情页 → **接收消息** → **设置API接收**:
|
||||
|
||||
| 配置项 | 填写 | 说明 |
|
||||
|--------|------|------|
|
||||
| URL | `https://itdesk.amanzac.com/api/wecom/callback` | 企微消息推送地址 |
|
||||
| Token | `wAqMCP` | 与 .env 中 WECOM_TOKEN 一致 |
|
||||
| EncodingAESKey | `KQY3cEsBc3rdi3xua9rPd5WxH8kYOhyASzWZQf75aJS` | 与 .env 中一致 |
|
||||
|
||||
> 点击保存时,企微会向 URL 发送验证请求,后端必须正常响应才能保存成功。
|
||||
|
||||
### 5.5 修改 AI 机器人转人工链接
|
||||
|
||||
在现有 AI 机器人的 Dify 工作流中,将转人工关键字触发的链接从:
|
||||
|
||||
```
|
||||
旧链接:https://work.weixin.qq.com/XXXX(员工服务入口)
|
||||
```
|
||||
|
||||
改为:
|
||||
|
||||
```
|
||||
新链接:https://itdesk.amanzac.com/itdesk/
|
||||
```
|
||||
|
||||
> 这样员工点击转人工链接后,会跳转到 H5 自建应用页面(而非企微员工服务窗口)。
|
||||
|
||||
---
|
||||
|
||||
## §6 阶段一功能测试清单
|
||||
|
||||
### 6.1 基础连通性测试
|
||||
|
||||
| # | 测试项 | 方法 | 预期结果 | 状态 |
|
||||
|---|--------|------|---------|------|
|
||||
| 1 | Cloudflare Tunnel 连通 | 浏览器访问 `https://itdesk.amanzac.com/` | 页面正常加载 | ⬜ |
|
||||
| 2 | 后端 API 健康 | 浏览器访问 `https://itdesk.amanzac.com/api/health` | 返回 `{"status":"ok"}` | ⬜ |
|
||||
| 3 | H5 员工端页面 | 浏览器访问 `https://itdesk.amanzac.com/itdesk/` | H5 页面渲染 | ⬜ |
|
||||
| 4 | 坐席工作台页面 | 浏览器访问 `https://itdesk.amanzac.com/itagent/` | 工作台页面渲染 | ⬜ |
|
||||
|
||||
### 6.2 OAuth2 登录测试
|
||||
|
||||
| # | 测试项 | 方法 | 预期结果 | 状态 |
|
||||
|---|--------|------|---------|------|
|
||||
| 5 | OAuth2 静默授权 | 在企微内点击应用入口 | H5 页面自动登录,显示员工身份 | ⬜ |
|
||||
| 6 | 身份识别 | 授权后查看 H5 页面 | 显示当前用户姓名/工号 | ⬜ |
|
||||
|
||||
### 6.3 坐席工作台测试
|
||||
|
||||
| # | 测试项 | 方法 | 预期结果 | 状态 |
|
||||
|---|--------|------|---------|------|
|
||||
| 7 | 会话列表 | 坐席登录工作台 | 显示进行中的会话 | ⬜ |
|
||||
| 8 | 聊天窗口 | 点击某个会话 | 显示完整对话记录 | ⬜ |
|
||||
| 9 | 发送消息 | 坐席输入文本发送 | 消息发送成功 | ⬜ |
|
||||
| 10 | 快速回复 | 点击快速回复面板 | 三级导航正常,模板可填入 | ⬜ |
|
||||
|
||||
### 6.4 端到端流程测试
|
||||
|
||||
| # | 测试项 | 方法 | 预期结果 | 状态 |
|
||||
|---|--------|------|---------|------|
|
||||
| 11 | AI 对话 → 转人工 | 员工与 AI 对话,触发转人工关键字 | 推送 H5 链接 | ⬜ |
|
||||
| 12 | 员工点击 H5 链接 | 点击推送的链接 | 跳转到 H5 页面,自动登录 | ⬜ |
|
||||
| 13 | 坐席收到会话 | 员工进入 H5 后 | 坐席工作台出现新会话 | ⬜ |
|
||||
| 14 | 坐席回复 | 坐席使用快速回复 | 员工 H5 页面显示回复 | ⬜ |
|
||||
| 15 | 企微通知 | 坐席回复后 | 员工收到企微应用消息通知 | ⬜ |
|
||||
|
||||
---
|
||||
|
||||
## §7 故障排查
|
||||
|
||||
### 7.1 Cloudflare Tunnel 连不上
|
||||
|
||||
```bash
|
||||
# 检查 cloudflared 容器日志
|
||||
docker compose -f docker-compose.nas.yml logs cloudflared
|
||||
|
||||
# 常见错误:
|
||||
# ERR error="failed to connect to Cloudflare edge"
|
||||
# → 检查 Token 是否正确
|
||||
# → 检查 NAS 是否能访问外网
|
||||
```
|
||||
|
||||
### 7.2 企微回调验证失败
|
||||
|
||||
```bash
|
||||
# 检查后端是否收到回调请求
|
||||
docker compose -f docker-compose.nas.yml logs backend | grep callback
|
||||
|
||||
# 常见原因:
|
||||
# 1. Token / EncodingAESKey 与 .env 不一致
|
||||
# 2. 后端回调路由路径不对(应为 /api/wecom/callback)
|
||||
# 3. Nginx 反代配置未正确转发
|
||||
```
|
||||
|
||||
### 7.3 OAuth2 授权失败
|
||||
|
||||
```
|
||||
常见原因:
|
||||
1. 可信域名未配置或未验证 → 企微管理后台检查
|
||||
2. redirect_uri 与可信域名不匹配 → 检查回调 URL
|
||||
3. CorpID 不正确 → 检查 .env 中的 WECOM_CORP_ID
|
||||
```
|
||||
|
||||
### 7.4 容器状态异常
|
||||
|
||||
```bash
|
||||
# 查看所有容器状态
|
||||
docker compose -f docker-compose.nas.yml ps
|
||||
|
||||
# 查看特定容器详细日志
|
||||
docker compose -f docker-compose.nas.yml logs --tail 100 backend
|
||||
|
||||
# 重启所有容器
|
||||
docker compose -f docker-compose.nas.yml restart
|
||||
|
||||
# 完全重建(代码更新后)
|
||||
docker compose -f docker-compose.nas.yml down
|
||||
docker compose -f docker-compose.nas.yml up -d --build
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## §8 与正式部署的区别
|
||||
|
||||
| 维度 | NAS 部署(测试) | 正式部署 |
|
||||
|------|----------------|---------|
|
||||
| 域名 | `itdesk.amanzac.com` | `it-dataquery.dc.servyou-it.com` |
|
||||
| 内网穿透 | Cloudflare Tunnel | 公司内网直连 |
|
||||
| HTTPS | Cloudflare 自动 | Nginx + 公司 CA 证书 |
|
||||
| 数据库密码 | 测试密码 | 强密码 + 审计 |
|
||||
| AI 引擎 | 可能不可用(Dify 在内网) | 可用 |
|
||||
| 员工数 | 测试人员(<10人) | 全公司 |
|
||||
| 企业微信认证 | 未认证(200人上限) | 已认证 |
|
||||
| 数据持久化 | Docker Volume | K8s PVC / 独立 PG 集群 |
|
||||
|
||||
---
|
||||
|
||||
## 附录 A:Cloudflare Tunnel 原理简述
|
||||
|
||||
```
|
||||
传统方式 Cloudflare Tunnel
|
||||
┌─────────────────┐ ┌─────────────────┐
|
||||
互联网 ────→ │ 开放端口 + 公网IP │ 互联网 ────→ │ Cloudflare Edge │
|
||||
│ + SSL 证书 │ │ (自动HTTPS) │
|
||||
│ + DDNS/域名解析 │ └────────┬────────┘
|
||||
└─────────────────┘ │
|
||||
↑ │ Tunnel(长连接)
|
||||
│ │
|
||||
┌─────────────────┐ ┌─────────────────┐
|
||||
│ NAS/服务器 │ cloudflared │ NAS/服务器 │
|
||||
│ (必须可达) │ ←──主动连接──→│ (无需开放端口) │
|
||||
└─────────────────┘ └─────────────────┘
|
||||
|
||||
优势:
|
||||
1. 无需公网 IP — cloudflared 主动外连,不需要入站端口
|
||||
2. 无需 SSL 证书 — Cloudflare Edge 自动处理 HTTPS
|
||||
3. 无需 DDNS — 域名始终指向 Cloudflare
|
||||
4. 更安全 — 不暴露 NAS 任何端口到公网
|
||||
```
|
||||
@@ -0,0 +1,120 @@
|
||||
# 502 Bad Gateway - 后端启动失败
|
||||
|
||||
> 日期:2026-07-05
|
||||
> 问题:坐席端登录失败,返回 502 Bad Gateway
|
||||
|
||||
---
|
||||
|
||||
## 一、问题现象
|
||||
|
||||
用户访问 `https://itsupport.servyou.com.cn/itagent/` 时提示登录失败:
|
||||
```
|
||||
Failed to load resource: the server responded with a status of 502 (Bad Gateway)
|
||||
AxiosError: Request failed with status code 502
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 二、诊断过程
|
||||
|
||||
### 2.1 检查容器状态
|
||||
|
||||
```bash
|
||||
docker ps -a
|
||||
```
|
||||
|
||||
发现后端容器状态为 `unhealthy`:
|
||||
```
|
||||
CONTAINER ID IMAGE STATUS
|
||||
656f7696d4e5 wecom-it-desk-backend:latest Up 8 minutes (unhealthy)
|
||||
```
|
||||
|
||||
### 2.2 检查后端日志
|
||||
|
||||
```bash
|
||||
docker logs 656f7696d4e5 --tail 30
|
||||
```
|
||||
|
||||
发现错误:
|
||||
```
|
||||
ModuleNotFoundError: No module named 'aioredis'
|
||||
```
|
||||
|
||||
### 2.3 原因分析
|
||||
|
||||
- 旧版镜像中代码使用 `import aioredis`
|
||||
- 但 `aioredis` 包与 Python 3.12 不兼容
|
||||
- 报错:`TypeError: duplicate base class TimeoutError`
|
||||
|
||||
---
|
||||
|
||||
## 三、解决方案
|
||||
|
||||
### 3.1 尝试修复(失败)
|
||||
|
||||
尝试在容器内安装 `aioredis` 包,但发现:
|
||||
- `aioredis` 与 Python 3.12 不兼容
|
||||
- 安装后仍报错:`TypeError: duplicate base class TimeoutError`
|
||||
|
||||
### 3.2 最终方案
|
||||
|
||||
删除旧容器,使用正确的环境变量重新启动:
|
||||
|
||||
```bash
|
||||
# 1. 删除旧容器
|
||||
docker stop 656f7696d4e5
|
||||
docker rm 656f7696d4e5
|
||||
|
||||
# 2. 使用正确的 PYTHONPATH 重新启动
|
||||
cd /opt/wecom-it-desk
|
||||
PYTHONPATH=/app docker compose up -d backend
|
||||
```
|
||||
|
||||
关键点:**必须设置 `PYTHONPATH=/app`**,否则会报错 `ModuleNotFoundError: No module named 'app.core'`
|
||||
|
||||
---
|
||||
|
||||
## 四、验证结果
|
||||
|
||||
```bash
|
||||
# 检查容器状态
|
||||
docker ps
|
||||
# 输出:
|
||||
# 2ec80dee024c wecom-it-desk-backend:latest Up 5 minutes (healthy)
|
||||
# e147524342fa redis:7-alpine Up 11 hours (healthy)
|
||||
# 8a2265864f34 nginx:1.27-alpine Up 11 hours
|
||||
# 433ef922c8d8 postgres:16-alpine Up 11 hours (healthy)
|
||||
|
||||
# 测试 API
|
||||
curl http://localhost:8000/health
|
||||
# 输出:{"status":"ok"}
|
||||
|
||||
# 测试页面
|
||||
curl -sk https://localhost/itdesk/
|
||||
# 输出:HTML 页面正常返回
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 五、根因总结
|
||||
|
||||
| 问题 | 原因 |
|
||||
|------|------|
|
||||
| 后端容器 unhealthy | 旧镜像使用 `import aioredis`,与 Python 3.12 不兼容 |
|
||||
| 启动失败 | 需要设置 `PYTHONPATH=/app` 环境变量 |
|
||||
|
||||
---
|
||||
|
||||
## 六、预防措施
|
||||
|
||||
1. **更新镜像**:在 Dockerfile 中将所有 `import aioredis` 改为 `import redis.asyncio as aioredis`
|
||||
2. **环境变量**:确保 docker-compose.yml 中设置 `PYTHONPATH=/app`
|
||||
3. **健康检查**:定期检查容器健康状态
|
||||
|
||||
---
|
||||
|
||||
## 七、相关文件
|
||||
|
||||
- 部署配置:`/opt/wecom-it-desk/docker-compose.yml`
|
||||
- Nginx 配置:`/opt/wecom-it-desk/nginx/nginx.conf`
|
||||
- 后端代码:`/opt/wecom-it-desk/backend/`
|
||||
@@ -0,0 +1,114 @@
|
||||
# WAF 转发配置申请
|
||||
|
||||
## 问题描述
|
||||
|
||||
`itsupport.servyou.com.cn` 域名无法访问,浏览器超时。需 WAF 配置转发规则。
|
||||
|
||||
---
|
||||
|
||||
## 证据链
|
||||
|
||||
### 1. 服务器本地 — 服务正常 ✅
|
||||
|
||||
```
|
||||
# HTTP 已强制跳转 HTTPS(nginx 配置 301 重定向)
|
||||
[root@hz-oa-ai-g-dataquery-90-5-110 ~]# curl http://localhost/itdesk/health
|
||||
<html><head><title>301 Moved Permanently</title></head>...nginx/1.27.5</html>
|
||||
|
||||
# HTTPS 正常响应
|
||||
[root@hz-oa-ai-g-dataquery-90-5-110 ~]# curl -k https://127.0.0.1/itdesk/health -H "Host: itsupport.servyou.com.cn"
|
||||
healthy
|
||||
```
|
||||
|
||||
### 2. SSL 证书 — 有效 ✅
|
||||
|
||||
```
|
||||
[root@hz-oa-ai-g-dataquery-90-5-110 ~]# echo | openssl s_client -connect 127.0.0.1:443 -servername itsupport.servyou.com.cn
|
||||
CONNECTED(00000003)
|
||||
depth=2 C=US, O=DigiCert Inc, CN=DigiCert Global Root G2
|
||||
depth=1 C=US, O=DigiCert, Inc., CN=GeoTrust G2 TLS CN RSA4096 SHA256 2022 CA1
|
||||
depth=0 C=CN, ST=浙江省, L=杭州市, O=税友软件集团股份有限公司, CN=*.servyou.com.cn
|
||||
Verification: OK
|
||||
Protocol: TLSv1.3, Cipher: TLS_AES_256_GCM_SHA384
|
||||
Verify return code: 0 (ok)
|
||||
```
|
||||
|
||||
证书信息:
|
||||
- 主体:`CN=*.servyou.com.cn`(通配符证书)
|
||||
- 颁发者:`GeoTrust G2 TLS CN RSA4096 SHA256 2022 CA1`
|
||||
- 有效期:2025-12-23 ~ 2027-01-12
|
||||
|
||||
### 3. DNS 解析 — 指向 WAF ✅
|
||||
|
||||
```
|
||||
# 服务器 DNS 解析到 WAF 公网 IP
|
||||
[root@hz-oa-ai-g-dataquery-90-5-110 ~]# ping -c 1 itsupport.servyou.com.cn
|
||||
PING itsupport.servyou.com.cn (115.236.188.3): 56(84) bytes of data.
|
||||
--- itsupport.servyou.com.cn ping statistics ---
|
||||
1 packets transmitted, 0 received, 100% packet loss
|
||||
```
|
||||
|
||||
- 解析结果:`115.236.188.3`(WAF 公网 IP)
|
||||
- ping 100% 丢失(WAF 禁 ICMP,正常)
|
||||
|
||||
### 4. WAF 转发 — 不通 ❌
|
||||
|
||||
```
|
||||
# 从服务器通过域名访问 HTTP(超时)
|
||||
[root@hz-oa-ai-g-dataquery-90-5-110 ~]# curl -v http://itsupport.servyou.com.cn/itdesk/health
|
||||
* Trying 115.236.188.3:80...
|
||||
^C(超时无响应)
|
||||
|
||||
# 从服务器通过域名访问 HTTPS(超时)
|
||||
[root@hz-oa-ai-g-dataquery-90-5-110 ~]# curl -v https://itsupport.servyou.com.cn/itdesk/health
|
||||
* Trying 115.236.188.3:443...
|
||||
^C(超时无响应)
|
||||
```
|
||||
|
||||
### 5. 服务器外网连通性 — 正常 ✅
|
||||
|
||||
```
|
||||
# 企微 API 可达
|
||||
[root@hz-oa-ai-g-dataquery-90-5-110 ~]# curl -s https://qyapi.weixin.qq.com/cgi-bin/gettoken
|
||||
{"errcode":41004,"errmsg":"corpsecret missing", "from ip": "218.75.34.87"}
|
||||
|
||||
# PyPI 镜像可达
|
||||
[root@hz-oa-ai-g-dataquery-90-5-110 ~]# curl -s https://pypi.tuna.tsinghua.edu.cn/
|
||||
<html><head><title>302 Found</title></head>...nginx/1.22.1</html>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 结论
|
||||
|
||||
| 环节 | 状态 |
|
||||
|------|------|
|
||||
| 服务器(10.90.5.110) | ✅ HTTP/HTTPS 服务正常 |
|
||||
| SSL 证书(*.servyou.com.cn) | ✅ 有效,TLSv1.3 |
|
||||
| DNS 解析 | ✅ 指向 WAF(115.236.188.3) |
|
||||
| 服务器外网连通性 | ✅ 企微 API / PyPI 均可达 |
|
||||
| **WAF 转发到后端** | **❌ 未配置 — 流量未到达 10.90.5.110** |
|
||||
|
||||
---
|
||||
|
||||
## 需要配置
|
||||
|
||||
请 WAF/网络团队配置转发规则:
|
||||
|
||||
```
|
||||
域名:itsupport.servyou.com.cn
|
||||
源端口:80(HTTP)/ 443(HTTPS)
|
||||
转发目标:10.90.5.110:80
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 服务器信息
|
||||
|
||||
| 项目 | 值 |
|
||||
|------|-----|
|
||||
| 服务器 IP | 10.90.5.110 |
|
||||
| 服务端口 | 80(HTTP→HTTPS 重定向)+ 443(HTTPS) |
|
||||
| 域名 | itsupport.servyou.com.cn |
|
||||
| SSL 证书 | *.servyou.com.cn(DigiCert,有效期至 2027-01-12) |
|
||||
| 系统 | Linux(Docker 部署,nginx 反向代理) |
|
||||
@@ -0,0 +1,136 @@
|
||||
# 蓝绿部署指南
|
||||
|
||||
## 概述
|
||||
|
||||
蓝绿部署是一种零停机部署策略,通过维护两套完全相同的运行环境(Blue 和 Green),实现快速切换和回滚。
|
||||
|
||||
## 架构
|
||||
|
||||
```
|
||||
┌─────────────────┐
|
||||
│ Nginx │
|
||||
│ (流量入口) │
|
||||
└────────┬────────┘
|
||||
│
|
||||
┌──────────────┴──────────────┐
|
||||
│ │
|
||||
▼ ▼
|
||||
┌────────────────┐ ┌────────────────┐
|
||||
│ Blue 环境 │ │ Green 环境 │
|
||||
│ (当前活动) │ │ (待验证) │
|
||||
│ backend:8000 │ │ backend_green: │
|
||||
│ │ │ 5002 │
|
||||
└────────────────┘ └────────────────┘
|
||||
│ │
|
||||
└──────────────┬──────────────┘
|
||||
│
|
||||
┌──────────────┴──────────────┐
|
||||
│ │
|
||||
▼ ▼
|
||||
┌────────────────┐ ┌────────────────┐
|
||||
│ PostgreSQL │ ←──→ │ Redis │
|
||||
│ (共享) │ │ (共享) │
|
||||
└────────────────┘ └────────────────┘
|
||||
```
|
||||
|
||||
## 文件说明
|
||||
|
||||
| 文件 | 位置 | 说明 |
|
||||
|------|------|------|
|
||||
| docker-compose-green.yml | /opt/wecom-it-desk/ | Green 环境配置 |
|
||||
| switch-blue-green.sh | /opt/wecom-it-desk/ | 切换脚本 |
|
||||
| nginx.conf | /opt/wecom-it-desk/nginx/ | Nginx 配置(包含 upstream) |
|
||||
|
||||
## 部署步骤
|
||||
|
||||
### 1. 部署 Green 环境
|
||||
|
||||
```bash
|
||||
cd /opt/wecom-it-desk
|
||||
|
||||
# 构建并启动 Green 环境
|
||||
docker-compose -f docker-compose-green.yml up -d
|
||||
|
||||
# 验证 Green 环境健康
|
||||
curl http://localhost:5002/health
|
||||
```
|
||||
|
||||
### 2. 测试 Green 环境
|
||||
|
||||
通过端口 5080 访问 Green 环境进行测试:
|
||||
- H5: http://服务器IP:5080/itdesk/
|
||||
- 坐席: http://服务器IP:5080/itagent/
|
||||
- 管理后台: http://服务器IP:5080/itadmin/
|
||||
|
||||
### 3. 切换流量到 Green
|
||||
|
||||
```bash
|
||||
# 方法一:使用切换脚本
|
||||
./switch-blue-green.sh to-green
|
||||
|
||||
# 方法二:手动修改 Nginx 配置
|
||||
sed -i 's/wecom_it_backend:8000/wecom_it_backend_green:8000/' /opt/wecom-it-desk/nginx/nginx.conf
|
||||
docker restart wecom_it_nginx
|
||||
```
|
||||
|
||||
### 4. 验证切换
|
||||
|
||||
```bash
|
||||
# 检查 Nginx upstream 配置
|
||||
grep -A1 'upstream backend_api' /opt/wecom-it-desk/nginx/nginx.conf
|
||||
|
||||
# 测试 API
|
||||
curl https://itsupport.servyou.com.cn/api/v1/system/health
|
||||
```
|
||||
|
||||
### 5. 回滚(如有问题)
|
||||
|
||||
```bash
|
||||
# 方法一:使用切换脚本
|
||||
./switch-blue-green.sh to-blue
|
||||
|
||||
# 方法二:手动修改
|
||||
sed -i 's/wecom_it_backend_green:8000/wecom_it_backend:8000/' /opt/wecom-it-desk/nginx/nginx.conf
|
||||
docker restart wecom_it_nginx
|
||||
```
|
||||
|
||||
## 端口说明
|
||||
|
||||
| 端口 | 服务 | 说明 |
|
||||
|------|------|------|
|
||||
| 80/443 | Nginx (Blue) | 生产入口 |
|
||||
| 5002 | Backend (Green) | Green 后端 API |
|
||||
| 5080 | Nginx (Green) | Green 测试入口 |
|
||||
| 5443 | Nginx (Green) | Green HTTPS |
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **数据库共享**:Blue 和 Green 共用同一个 PostgreSQL 和 Redis
|
||||
2. **文件上传**:上传的文件保存在挂载目录,不受切换影响
|
||||
3. **会话影响**:切换后用户可能需要重新登录
|
||||
4. **WebSocket**:切换后现有 WebSocket 连接会断开
|
||||
|
||||
## 快速命令汇总
|
||||
|
||||
```bash
|
||||
# 查看状态
|
||||
docker ps
|
||||
|
||||
# 查看 Green 日志
|
||||
docker logs wecom_it_backend_green
|
||||
|
||||
# 切换到 Green
|
||||
sed -i 's/wecom_it_backend:8000/wecom_it_backend_green:8000/' /opt/wecom-it-desk/nginx/nginx.conf
|
||||
docker restart wecom_it_nginx
|
||||
|
||||
# 切换回 Blue
|
||||
sed -i 's/wecom_it_backend_green:8000/wecom_it_backend:8000/' /opt/wecom-it-desk/nginx/nginx.conf
|
||||
docker restart wecom_it_nginx
|
||||
|
||||
# 停止 Green 环境
|
||||
docker-compose -f docker-compose-green.yml down
|
||||
```
|
||||
|
||||
## 更新日志
|
||||
|
||||
- 2026-07-05: 初始版本
|
||||
@@ -0,0 +1,138 @@
|
||||
# 通讯链路诊断方案
|
||||
|
||||
> 日期:2026-07-03
|
||||
> 目标:诊断当前系统通讯问题,无论结果启动重构方案
|
||||
|
||||
---
|
||||
|
||||
## 一、通讯链路架构
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────────┐
|
||||
│ 完整通讯链路 │
|
||||
├─────────────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ 【用户 → 坐席】 │
|
||||
│ ┌──────────┐ 企微回调 ┌──────────┐ 路由 ┌─────────┐ │
|
||||
│ │ 用户发送 │ ──────────────→ │ 后端API │ ──────────→ │ Message │ │
|
||||
│ │ 消息 │ /wecom/ │ 回调入口 │ │ Router │ │
|
||||
│ └──────────┘ callback └──────────┘ └────┬────┘ │
|
||||
│ │ │ │
|
||||
│ │ ▼ │
|
||||
│ │ ┌───────────┐ │
|
||||
│ │ │ 消息入库 │ │
|
||||
│ │ │ (DB存储) │ │
|
||||
│ │ └───────────┘ │
|
||||
│ │ │ │
|
||||
│ │ ┌────────────────┘ │
|
||||
│ │ ▼ │
|
||||
│ │ ┌──────────┐ │
|
||||
│ │ │ 坐席收到 │ │
|
||||
│ │ │(WS/轮询) │ │
|
||||
│ │ └──────────┘ │
|
||||
│ │ │
|
||||
│ 【坐席 → 用户】 │
|
||||
│ ┌──────────┐ API调用 ┌──────────┐ 企微API ┌────────┐ │
|
||||
│ │ 坐席发送 │ ──────────────→ │ 后端API │ ──────────→ │企微 │ │
|
||||
│ │ 消息 │ POST │ 发送消息 │ /message │服务器 │ │
|
||||
│ └──────────┘ /conversations└──────────┘ /send └────┬───┘ │
|
||||
│ │ /{id}/messages │ │ │
|
||||
│ │ ▼ ▼ │
|
||||
│ │ ┌──────────┐ ┌────────┐ │
|
||||
│ │ │ 消息入库 │ │用户收到 │ │
|
||||
│ │ │(DB存储) │ │消息 │ │
|
||||
│ │ └──────────┘ └────────┘ │
|
||||
│ │ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 二、诊断检查点
|
||||
|
||||
### 2.1 企微回调链路(用户 → 系统)
|
||||
|
||||
| 检查点 | 文件位置 | 检查内容 | 预期结果 |
|
||||
|--------|---------|---------|---------|
|
||||
| C-01 | `wecom_callback.py` GET `/wecom/callback` | 企微URL验证 | 返回解密后的echostr |
|
||||
| C-02 | `wecom_callback.py` POST `/wecom/callback` | 消息解密 | 正确解析XML并解密 |
|
||||
| C-03 | `message_router.py` | 消息路由 | 正确分配会话/坐席 |
|
||||
| C-04 | 数据库 `messages` 表 | 消息存储 | 消息正确写入 |
|
||||
|
||||
### 2.2 坐席发送链路(系统 → 用户)
|
||||
|
||||
| 检查点 | 文件位置 | 检查内容 | 预期结果 |
|
||||
|--------|---------|---------|---------|
|
||||
| C-05 | `messages.py` POST `/conversations/{id}/messages` | API入口 | 正确接收坐席消息 |
|
||||
| C-06 | `wecom_service.py` `send_text_message()` | 企微API调用 | errcode=0 |
|
||||
| C-07 | 企微客户端 | 用户收到消息 | 正常展示 |
|
||||
|
||||
### 2.3 H5 实时推送
|
||||
|
||||
| 检查点 | 文件位置 | 检查内容 | 预期结果 |
|
||||
|--------|---------|---------|---------|
|
||||
| C-08 | `ws_manager.py` | WS连接管理 | 坐席WS连接 |
|
||||
| C-09 | `frontend-agent` | WS接收 | 消息实时展示 |
|
||||
| C-10 | `frontend-h5` | 轮询/WebSocket | 新消息实时更新 |
|
||||
|
||||
---
|
||||
|
||||
## 三、已发现的问题
|
||||
|
||||
### 问题1:非文本消息不推送(messages.py:210-233)
|
||||
|
||||
```python
|
||||
# 只有 text 类型消息才调用企微 API 推送给员工
|
||||
if body.msg_type == "text":
|
||||
# 调用企微API
|
||||
```
|
||||
|
||||
**影响**:图片、文件等消息无法推送到用户微信端
|
||||
|
||||
### 问题2:dev_mode 短路(messages.py:215-216)
|
||||
|
||||
```python
|
||||
if getattr(settings, 'dev_mode', False):
|
||||
logger.debug(f"[DEV] 跳过企微推送: msg_id={message.id}")
|
||||
```
|
||||
|
||||
**影响**:测试环境下消息不会推送到用户
|
||||
|
||||
### 问题3:企微API错误处理(messages.py:231-233)
|
||||
|
||||
```python
|
||||
except Exception as e:
|
||||
# 企微 API 调用失败不阻塞消息存储
|
||||
logger.warning(f"企微消息发送失败(消息已存储): {e}")
|
||||
```
|
||||
|
||||
**影响**:企微API失败时仅记录日志,用户实际未收到消息
|
||||
|
||||
---
|
||||
|
||||
## 四、诊断执行记录
|
||||
|
||||
| 时间 | 检查项 | 结果 | 说明 |
|
||||
|------|--------|------|------|
|
||||
| 2026-07-03 | 代码审查 | ✅ | 完成链路分析 |
|
||||
| - | C-01 企微回调 | ⏳ | 待部署环境验证 |
|
||||
| - | C-05 坐席发送 | ⏳ | 待部署环境验证 |
|
||||
| - | C-07 用户收到 | ⏳ | 待实际测试 |
|
||||
|
||||
---
|
||||
|
||||
## 五、结论
|
||||
|
||||
**当前系统通讯链路代码完整**,但存在以下已知风险:
|
||||
|
||||
1. 非文本消息(图片/文件)无法推送
|
||||
2. dev_mode 会跳过企微推送
|
||||
3. 企微API失败时静默失败
|
||||
|
||||
这些问题可通过系统重构进一步优化消息通讯能力。
|
||||
|
||||
---
|
||||
|
||||
## 六、下一步
|
||||
|
||||
**下一步**:根据诊断结果优化现有通讯链路
|
||||
Reference in New Issue
Block a user