Completed: - Add 6 core database documents (docs/01-平台基础层/07-数据库/) Architecture overview, migration history, environment comparison, tech debt tracking, seed data management, PostgreSQL extensions - Restructure deployment docs: archive 20 legacy files to _archive-2025/ - Create unified daily operations manual (01-日常更新操作手册.md) - Add pending deployment change tracker (03-待部署变更清单.md) - Update database development standard to v3.0 (three iron rules) - Fix Prisma schema type drift: align @db.* annotations with actual DB IIT: UUID/Timestamptz(6), SSA: Timestamp(6)/VarChar(20/50/100) - Add migration: 20260227_align_schema_with_db_types (idempotent ALTER) - Add Cursor Rule for auto-reminding deployment change documentation - Update system status guide v6.4 with deployment and DB doc references - Add architecture consultation docs (Prisma guide, SAE deployment guide) Technical details: - Manual migration due to shadow DB limitation (TD-001 in tech debt) - Deployment docs reduced from 20+ scattered files to 3 core documents - Cursor Rule triggers on schema.prisma, package.json, Dockerfile changes Made-with: Cursor
1845 lines
40 KiB
Markdown
1845 lines
40 KiB
Markdown
# AI临床研究平台 - 完整部署实战手册(2025版)
|
||
|
||
> **文档版本**:v1.0(实战版)
|
||
> **创建日期**:2025-12-25
|
||
> **基于实际部署**:2025-12-24 ~ 2025-12-25 完整部署经历
|
||
> **部署成功时间**:约6小时(包含问题排查)
|
||
> **部署人员**:开发团队
|
||
> **部署结果**:✅ 完全成功,所有功能正常运行
|
||
|
||
---
|
||
|
||
## 📋 文档说明
|
||
|
||
### 本文档的特点
|
||
|
||
- ✅ **基于真实部署经历**:记录了2025年12月实际部署的完整过程
|
||
- ✅ **包含所有坑点**:遇到的4个关键问题及解决方案
|
||
- ✅ **经验总结**:提炼出的最佳实践和注意事项
|
||
- ✅ **可直接复制**:所有配置和命令都经过验证
|
||
- ✅ **适合快速部署**:跟着做就能成功
|
||
|
||
### 与其他文档的关系
|
||
|
||
| 文档名称 | 用途 | 何时使用 |
|
||
|---------|------|---------|
|
||
| **本文档** | 实战部署完整流程 | ⭐ 新部署或重新部署时 |
|
||
| `01-快速部署SOP-零基础版.md` | 零基础完整指南 | 从零开始学习时 |
|
||
| `00-部署进度总览.md` | 资源速查索引 | 查询资源信息时 |
|
||
| `12-Node.js后端-SAE部署操作手册.md` | 单服务部署 | 只部署某个服务时 |
|
||
|
||
---
|
||
|
||
## 🎯 部署架构总览
|
||
|
||
```
|
||
用户浏览器
|
||
↓ HTTPS (公网)
|
||
CLB负载均衡器 (公网IP: 8.140.53.236)
|
||
↓ HTTP (内网)
|
||
前端Nginx (SAE: 172.17.173.72:80)
|
||
↓ HTTP (内网, /api/v1/)
|
||
Node.js后端 (SAE: 172.17.173.73:3001)
|
||
↓ HTTP (内网, /api/dc/)
|
||
Python服务 (SAE: 172.17.173.66:8000)
|
||
↓ SQL (内网)
|
||
RDS PostgreSQL (内网: pgm-2zex1m2y3r23hdn5.pg.rds.aliyuncs.com:5432)
|
||
```
|
||
|
||
**关键依赖**:
|
||
- 所有服务在同一个VPC内网(`172.17.0.0/16`)
|
||
- 使用NAT网关访问外网(拉取镜像、调用LLM API)
|
||
- CLB绑定前端,提供公网访问
|
||
|
||
---
|
||
|
||
## 📊 部署顺序(严格按顺序执行)
|
||
|
||
| 步骤 | 服务 | 预计时间 | 依赖项 |
|
||
|------|------|---------|--------|
|
||
| 1️⃣ | VPC网络 + NAT网关 | 15分钟 | 无 |
|
||
| 2️⃣ | RDS PostgreSQL | 30分钟 | VPC |
|
||
| 3️⃣ | OSS对象存储 | 10分钟 | 无 |
|
||
| 4️⃣ | ACR容器镜像仓库 | 10分钟 | 无 |
|
||
| 5️⃣ | Python微服务镜像构建 | 20分钟 | ACR |
|
||
| 6️⃣ | Python微服务部署到SAE | 15分钟 | VPC, ACR |
|
||
| 7️⃣ | Node.js后端镜像构建 | 30分钟 | ACR, RDS |
|
||
| 8️⃣ | Node.js后端部署到SAE | 20分钟 | VPC, ACR, RDS, Python |
|
||
| 9️⃣ | 前端Nginx镜像构建 | 15分钟 | ACR |
|
||
| 🔟 | 前端Nginx部署到SAE | 15分钟 | VPC, ACR, Node.js |
|
||
| 1️⃣1️⃣ | CLB负载均衡器 | 10分钟 | 前端Nginx |
|
||
| 1️⃣2️⃣ | 全链路测试验证 | 30分钟 | 所有服务 |
|
||
|
||
**总计**:约3.5小时(不含问题排查)
|
||
|
||
---
|
||
|
||
## 🔑 一、前置准备(30分钟)
|
||
|
||
### 1.1 阿里云账号与资源
|
||
|
||
**检查清单**:
|
||
- [ ] 阿里云账号已实名认证
|
||
- [ ] 账户余额 ≥ 500元(建议1000元)
|
||
- [ ] 地域选择:华北2(北京)
|
||
- [ ] 已创建RAM访问密钥(用于Docker登录)
|
||
|
||
### 1.2 本地开发环境
|
||
|
||
**必需工具**:
|
||
- [ ] Docker Desktop(Windows/Mac)或 Docker Engine(Linux)
|
||
- [ ] Git(用于代码管理)
|
||
- [ ] Node.js 22+(用于本地构建)
|
||
- [ ] PowerShell 或 Bash(执行脚本)
|
||
|
||
**验证命令**:
|
||
```bash
|
||
docker --version # 应显示 Docker version 24.0+
|
||
git --version # 应显示 git version 2.x+
|
||
node --version # 应显示 v22.x.x
|
||
```
|
||
|
||
### 1.3 项目代码准备
|
||
|
||
```bash
|
||
# 克隆项目(如果还没有)
|
||
git clone <your-repo-url> AIclinicalresearch
|
||
cd AIclinicalresearch
|
||
|
||
# 确认项目结构
|
||
ls -la
|
||
# 应该看到:backend/, frontend-v2/, extraction_service/, docs/
|
||
```
|
||
|
||
---
|
||
|
||
## 🌐 二、基础设施部署(1小时)
|
||
|
||
### 2.1 VPC网络(15分钟)
|
||
|
||
**登录VPC控制台**:https://vpc.console.aliyun.com/
|
||
|
||
#### 创建VPC
|
||
|
||
1. 点击【创建专有网络】
|
||
2. 配置参数:
|
||
```yaml
|
||
VPC名称: ai-clinical-vpc
|
||
地域: 华北2(北京)
|
||
IPv4网段: 172.17.0.0/16
|
||
```
|
||
3. 点击【确定】
|
||
|
||
#### 创建交换机(2个,提高可用性)
|
||
|
||
**交换机1**:
|
||
```yaml
|
||
名称: ai-clinical-vsw-f
|
||
可用区: 华北2 可用区F
|
||
IPv4网段: 172.17.160.0/20
|
||
```
|
||
|
||
**交换机2**:
|
||
```yaml
|
||
名称: ai-clinical-vsw-a
|
||
可用区: 华北2 可用区A
|
||
IPv4网段: 172.17.192.0/20
|
||
```
|
||
|
||
#### 创建安全组
|
||
|
||
1. 进入【安全组】页面
|
||
2. 创建安全组:
|
||
```yaml
|
||
名称: ai-clinical-sg
|
||
网络: ai-clinical-vpc
|
||
```
|
||
3. 配置入方向规则:
|
||
```yaml
|
||
# 允许VPC内网互通
|
||
协议: 全部
|
||
端口: -1/-1
|
||
授权对象: 172.17.0.0/16
|
||
|
||
# 允许HTTPS (443)
|
||
协议: TCP
|
||
端口: 443/443
|
||
授权对象: 0.0.0.0/0
|
||
|
||
# 允许HTTP (80)
|
||
协议: TCP
|
||
端口: 80/80
|
||
授权对象: 0.0.0.0/0
|
||
```
|
||
|
||
---
|
||
|
||
### 2.2 NAT网关(15分钟)
|
||
|
||
**用途**:让VPC内的SAE应用能访问外网(拉取镜像、调用LLM API)
|
||
|
||
#### 创建NAT网关
|
||
|
||
**登录NAT网关控制台**:https://vpc.console.aliyun.com/nat/
|
||
|
||
1. 点击【创建NAT网关】
|
||
2. 配置参数:
|
||
```yaml
|
||
名称: NAT_airesearch
|
||
地域: 华北2(北京)
|
||
VPC: ai-clinical-vpc
|
||
交换机: ai-clinical-vsw-f
|
||
网关类型: 增强型
|
||
付费模式: 按量付费
|
||
```
|
||
3. 点击【立即购买】
|
||
|
||
#### 创建并绑定EIP
|
||
|
||
1. 在NAT网关详情页,点击【绑定弹性公网IP】
|
||
2. 选择【购买新的EIP】:
|
||
```yaml
|
||
计费方式: 按使用流量
|
||
带宽峰值: 5Mbps(测试环境够用)
|
||
```
|
||
3. 购买并绑定
|
||
|
||
#### 配置SNAT条目(关键!)
|
||
|
||
1. 进入NAT网关详情 → 【SNAT管理】
|
||
2. 添加SNAT条目1:
|
||
```yaml
|
||
交换机: ai-clinical-vsw-f
|
||
公网IP: 选择刚才的EIP
|
||
```
|
||
3. 添加SNAT条目2:
|
||
```yaml
|
||
交换机: ai-clinical-vsw-a
|
||
公网IP: 选择刚才的EIP
|
||
```
|
||
|
||
**验证**:
|
||
- SNAT条目状态显示【可用】✅
|
||
|
||
---
|
||
|
||
### 2.3 RDS PostgreSQL(30分钟)
|
||
|
||
**登录RDS控制台**:https://rdsnext.console.aliyun.com/
|
||
|
||
#### 创建实例
|
||
|
||
1. 点击【创建实例】
|
||
2. 配置参数:
|
||
```yaml
|
||
# 基础配置
|
||
地域: 华北2(北京)
|
||
可用区: 可用区F(与交换机对应)
|
||
数据库引擎: PostgreSQL
|
||
版本: 15
|
||
系列: 高可用版
|
||
存储类型: ESSD云盘
|
||
|
||
# 规格
|
||
规格类型: 通用型
|
||
规格: 2核4GB (pg.n2.2c.1m)
|
||
存储空间: 100GB
|
||
|
||
# 网络
|
||
网络类型: 专有网络
|
||
VPC: ai-clinical-vpc
|
||
交换机: ai-clinical-vsw-f
|
||
|
||
# 付费
|
||
付费类型: 按量付费(测试)或 包年包月(生产)
|
||
```
|
||
3. 点击【立即购买】
|
||
|
||
#### 创建数据库和账号
|
||
|
||
**等待实例创建完成(约10分钟)**,然后:
|
||
|
||
1. 进入实例详情 → 【账号管理】
|
||
2. 创建高权限账号:
|
||
```yaml
|
||
账号名称: airesearch
|
||
账号密码: Xibahe@fengzhibo117 # 改为您的强密码
|
||
账号类型: 高权限账号
|
||
```
|
||
|
||
3. 进入【数据库管理】
|
||
4. 创建数据库:
|
||
```yaml
|
||
数据库名称: ai_clinical_research
|
||
字符集: UTF8
|
||
排序规则: en_US.utf8
|
||
授权账号: airesearch (读写)
|
||
```
|
||
|
||
#### 配置白名单
|
||
|
||
1. 进入【数据安全性】→ 【白名单设置】
|
||
2. 修改默认分组:
|
||
```yaml
|
||
白名单: 172.17.0.0/16 # VPC网段
|
||
```
|
||
|
||
#### 配置时区(重要!)
|
||
|
||
1. 进入【参数设置】
|
||
2. 搜索 `timezone`
|
||
3. 修改为:`Asia/Shanghai`
|
||
4. 点击【提交参数】
|
||
|
||
#### 导入数据
|
||
|
||
**方法1:使用本地数据库导出**(推荐)
|
||
|
||
```bash
|
||
# 从本地Docker导出
|
||
docker exec ai-clinical-postgres pg_dump \
|
||
-U postgres \
|
||
-d ai_clinical_research \
|
||
--format=plain \
|
||
--no-owner \
|
||
--no-acl \
|
||
--encoding=UTF8 \
|
||
> rds_init.sql
|
||
|
||
# 临时开启RDS外网地址(仅用于导入)
|
||
# 在RDS控制台 → 数据库连接 → 申请外网地址
|
||
|
||
# 导入到RDS(需要容器内有psql客户端)
|
||
cat rds_init.sql | docker exec -i -e PGPASSWORD="Xibahe@fengzhibo117" \
|
||
ai-clinical-postgres psql \
|
||
-h pgm-2zex1m2y3r23hdn5.pg.rds.aliyuncs.com \
|
||
-p 5432 -U airesearch -d ai_clinical_research
|
||
|
||
# 导入完成后,立即关闭外网地址(安全)
|
||
```
|
||
|
||
**验证**:
|
||
```bash
|
||
# 连接到RDS检查
|
||
docker exec -e PGPASSWORD="Xibahe@fengzhibo117" \
|
||
ai-clinical-postgres psql \
|
||
-h pgm-2zex1m2y3r23hdn5.pg.rds.aliyuncs.com \
|
||
-p 5432 -U airesearch -d ai_clinical_research \
|
||
-c "SELECT nspname FROM pg_namespace WHERE nspname LIKE '%_schema' ORDER BY nspname;"
|
||
|
||
# 应该看到:asl_schema, dc_schema, platform_schema 等
|
||
```
|
||
|
||
---
|
||
|
||
### 2.4 OSS对象存储(10分钟)
|
||
|
||
**登录OSS控制台**:https://oss.console.aliyun.com/
|
||
|
||
#### 创建Bucket
|
||
|
||
1. 点击【创建Bucket】
|
||
2. 配置参数:
|
||
```yaml
|
||
Bucket名称: ai-clinical-research
|
||
地域: 华北2(北京)
|
||
存储类型: 标准存储
|
||
读写权限: 私有
|
||
存储冗余类型: 同城冗余存储
|
||
版本控制: 关闭
|
||
```
|
||
3. 点击【确定】
|
||
|
||
#### 创建RAM访问密钥
|
||
|
||
1. 进入【访问控制RAM】:https://ram.console.aliyun.com/
|
||
2. 创建用户:
|
||
```yaml
|
||
登录名称: oss-bucket-writer
|
||
显示名称: OSS Bucket写入用户
|
||
访问方式: ✅ OpenAPI调用访问
|
||
```
|
||
3. 保存AccessKey:
|
||
```yaml
|
||
AccessKeyId: LTAI5tB2Dt3NdvBL3G7nYGv7
|
||
AccessKeySecret: 1iSN9k39RkApP93QjUhC1DcPIeMG4V
|
||
```
|
||
**⚠️ 立即复制保存,后续无法查看!**
|
||
|
||
4. 为用户授权:
|
||
- 选择用户 → 【添加权限】
|
||
- 选择权限:`AliyunOSSFullAccess`(或自定义权限)
|
||
|
||
---
|
||
|
||
### 2.5 ACR容器镜像仓库(10分钟)
|
||
|
||
**登录容器镜像服务**:https://cr.console.aliyun.com/
|
||
|
||
#### 创建命名空间
|
||
|
||
1. 进入【个人实例】→ 【命名空间】
|
||
2. 点击【创建命名空间】:
|
||
```yaml
|
||
命名空间名称: ai-clinical
|
||
```
|
||
|
||
#### 创建镜像仓库(3个)
|
||
|
||
**仓库1:Python微服务**
|
||
```yaml
|
||
命名空间: ai-clinical
|
||
仓库名称: python-extraction
|
||
仓库类型: 私有
|
||
摘要: Python文档提取服务
|
||
```
|
||
|
||
**仓库2:Node.js后端**
|
||
```yaml
|
||
命名空间: ai-clinical
|
||
仓库名称: backend-service
|
||
仓库类型: 私有
|
||
摘要: Node.js后端API服务
|
||
```
|
||
|
||
**仓库3:前端Nginx**
|
||
```yaml
|
||
命名空间: ai-clinical
|
||
仓库名称: ai-clinical_frontend-nginx
|
||
仓库类型: 私有
|
||
摘要: React前端Nginx服务
|
||
```
|
||
|
||
#### 设置访问凭证
|
||
|
||
**在本地Docker登录ACR**:
|
||
```bash
|
||
# 个人版ACR登录(公网地址)
|
||
docker login \
|
||
--username=gofeng117@163.com \
|
||
--password=fengzhibo117 \
|
||
crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com
|
||
|
||
# 登录成功提示
|
||
# Login Succeeded
|
||
```
|
||
|
||
**记录镜像地址格式**:
|
||
```bash
|
||
# 公网地址(本地推送用)
|
||
crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/<仓库名>:<标签>
|
||
|
||
# VPC地址(SAE拉取用)
|
||
crpi-cd5ij4pjt65mweeo-vpc.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/<仓库名>:<标签>
|
||
```
|
||
|
||
---
|
||
|
||
## 🐍 三、Python微服务部署(35分钟)
|
||
|
||
### 3.1 构建Docker镜像(20分钟)
|
||
|
||
#### 进入目录
|
||
|
||
```bash
|
||
cd AIclinicalresearch/extraction_service
|
||
```
|
||
|
||
#### 检查Dockerfile
|
||
|
||
确认Dockerfile存在且内容正确:
|
||
|
||
```dockerfile
|
||
# 应该包含:
|
||
FROM python:3-slim
|
||
# ... 安装依赖
|
||
COPY requirements-prod.txt .
|
||
RUN pip install --no-cache-dir -r requirements-prod.txt
|
||
# ... 复制代码
|
||
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
|
||
```
|
||
|
||
#### 构建镜像
|
||
|
||
```bash
|
||
# 构建镜像
|
||
docker build -t python-extraction:v1.0 .
|
||
|
||
# 等待构建完成(约10-15分钟)
|
||
# Successfully built...
|
||
# Successfully tagged python-extraction:v1.0
|
||
```
|
||
|
||
#### 本地测试(可选但推荐)
|
||
|
||
```bash
|
||
# 运行容器
|
||
docker run -d -p 8000:8000 --name python-test python-extraction:v1.0
|
||
|
||
# 测试健康检查
|
||
curl http://localhost:8000/api/health
|
||
|
||
# 应该返回:
|
||
# {
|
||
# "status": "healthy",
|
||
# "checks": {...}
|
||
# }
|
||
|
||
# 停止容器
|
||
docker stop python-test
|
||
docker rm python-test
|
||
```
|
||
|
||
#### 推送到ACR
|
||
|
||
```bash
|
||
# 打标签
|
||
docker tag python-extraction:v1.0 \
|
||
crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/python-extraction:v1.0
|
||
|
||
# 推送镜像
|
||
docker push \
|
||
crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/python-extraction:v1.0
|
||
|
||
# 等待推送完成(约5-10分钟,镜像约1.1GB)
|
||
# The push refers to repository [...]
|
||
# v1.0: digest: sha256:... size: ...
|
||
```
|
||
|
||
---
|
||
|
||
### 3.2 部署到SAE(15分钟)
|
||
|
||
**登录SAE控制台**:https://sae.console.aliyun.com/
|
||
|
||
#### 创建命名空间(首次)
|
||
|
||
1. 进入【命名空间】
|
||
2. 点击【创建命名空间】:
|
||
```yaml
|
||
命名空间ID: cn-beijing:test-airesearch
|
||
命名空间名称: 测试环境
|
||
```
|
||
|
||
#### 创建应用
|
||
|
||
1. 点击【创建应用】
|
||
2. 应用基本信息:
|
||
```yaml
|
||
应用名称: python-extraction-test
|
||
命名空间: cn-beijing:test-airesearch
|
||
|
||
# 实例规格
|
||
CPU: 1核
|
||
内存: 2GB
|
||
实例数: 1
|
||
|
||
# 应用部署方式
|
||
部署方式: 镜像
|
||
镜像类型: 容器镜像服务企业版/个人版
|
||
```
|
||
|
||
3. 选择镜像:
|
||
```yaml
|
||
地域: 华北2(北京)
|
||
命名空间: ai-clinical
|
||
仓库: python-extraction
|
||
镜像版本: v1.0
|
||
|
||
# ⚠️ 使用VPC地址(SAE内网拉取,免流量费)
|
||
镜像地址会自动转为VPC地址:
|
||
crpi-cd5ij4pjt65mweeo-vpc.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/python-extraction:v1.0
|
||
```
|
||
|
||
4. 配置镜像访问凭证:
|
||
```yaml
|
||
用户名: gofeng117@163.com
|
||
密码: fengzhibo117
|
||
```
|
||
|
||
5. 应用配置:
|
||
```yaml
|
||
# 启动命令配置
|
||
启动命令: 留空(使用Dockerfile的CMD)
|
||
|
||
# 端口配置
|
||
容器端口: 8000
|
||
协议: TCP
|
||
```
|
||
|
||
6. 环境变量(可选):
|
||
```bash
|
||
LOG_LEVEL=INFO
|
||
TEMP_DIR=/tmp/extraction_service
|
||
```
|
||
|
||
7. 网络配置:
|
||
```yaml
|
||
VPC: ai-clinical-vpc
|
||
交换机: ai-clinical-vsw-f
|
||
安全组: ai-clinical-sg
|
||
```
|
||
|
||
8. 健康检查:
|
||
```yaml
|
||
# 存活检查(Liveness)
|
||
检查方式: HTTP
|
||
检查路径: /api/health
|
||
端口: 8000
|
||
初始延迟: 30秒
|
||
检查间隔: 10秒
|
||
检查超时: 5秒
|
||
不健康阈值: 3次
|
||
|
||
# 就绪检查(Readiness)
|
||
检查方式: HTTP
|
||
检查路径: /api/health
|
||
端口: 8000
|
||
初始延迟: 10秒
|
||
```
|
||
|
||
9. 点击【确认创建】
|
||
|
||
#### 等待部署完成
|
||
|
||
- 查看【实例部署】页面
|
||
- 状态变为【Running】(约5-10分钟)
|
||
- 记录内网地址:`http://172.17.173.66:8000`
|
||
|
||
#### 验证部署
|
||
|
||
```bash
|
||
# 方法1:在SAE应用内查看日志
|
||
# 应该看到:
|
||
# INFO: Uvicorn running on http://0.0.0.0:8000
|
||
# INFO: Application startup complete
|
||
|
||
# 方法2:从Node.js应用测试(部署后)
|
||
curl http://172.17.173.66:8000/api/health
|
||
```
|
||
|
||
---
|
||
|
||
## 🟢 四、Node.js后端部署(50分钟)
|
||
|
||
### 4.1 准备工作(10分钟)
|
||
|
||
#### 生成强JWT密钥
|
||
|
||
```bash
|
||
# 在PowerShell或Bash中生成
|
||
openssl rand -hex 32
|
||
# 或
|
||
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
|
||
|
||
# 示例输出(使用您自己生成的):
|
||
# 8a3f9e7c2d1b5a4e6f8c9d0a3b5e7f1c2a4b6c8d0e2f4a6b8c0d2e4f6a8b0c2d4
|
||
```
|
||
|
||
#### 准备环境变量清单
|
||
|
||
创建文件 `backend/.env.production`(不提交到Git):
|
||
|
||
```bash
|
||
# ==================== 基础配置 ====================
|
||
NODE_ENV=production
|
||
PORT=3001
|
||
LOG_LEVEL=info
|
||
|
||
# ==================== 数据库连接 ====================
|
||
DATABASE_URL=postgresql://airesearch:Xibahe%40fengzhibo117@pgm-2zex1m2y3r23hdn5.pg.rds.aliyuncs.com:5432/ai_clinical_research?connection_limit=18&pool_timeout=10
|
||
|
||
# ==================== Python微服务 ⚠️ 关键!====================
|
||
EXTRACTION_SERVICE_URL=http://172.17.173.66:8000
|
||
|
||
# ==================== OSS对象存储 ====================
|
||
OSS_ACCESS_KEY_ID=LTAI5tB2Dt3NdvBL3G7nYGv7
|
||
OSS_ACCESS_KEY_SECRET=1iSN9k39RkApP93QjUhC1DcPIeMG4V
|
||
OSS_BUCKET=ai-clinical-research
|
||
OSS_ENDPOINT=oss-cn-beijing-internal.aliyuncs.com
|
||
OSS_REGION=cn-beijing
|
||
|
||
# ==================== JWT认证 ====================
|
||
JWT_SECRET=8a3f9e7c2d1b5a4e6f8c9d0a3b5e7f1c2a4b6c8d0e2f4a6b8c0d2e4f6a8b0c2d4
|
||
JWT_EXPIRES_IN=7d
|
||
|
||
# ==================== LLM API密钥 ====================
|
||
DEEPSEEK_API_KEY=sk-7f8cc37a79fa4799860b38fc7ba2e150
|
||
DASHSCOPE_API_KEY=sk-75b4ff29a14a49e79667a331034f3298
|
||
|
||
# ==================== CloseAI配置 ====================
|
||
CLOSEAI_API_KEY=sk-cu0iepbXYGGx2jc7BqP6ogtSWmP6fk918qV3RUdtGC3Ed1po
|
||
CLOSEAI_OPENAI_BASE_URL=https://api.openai-proxy.org/v1
|
||
CLOSEAI_CLAUDE_BASE_URL=https://api.openai-proxy.org/anthropic
|
||
|
||
# ==================== Dify配置 ====================
|
||
DIFY_API_URL=http://localhost/v1
|
||
DIFY_API_KEY=dataset-mfvdiKvQ213NvxWm7RoYMN3c
|
||
|
||
# ==================== Postgres-Only架构 ====================
|
||
QUEUE_TYPE=pgboss
|
||
CACHE_TYPE=postgres
|
||
```
|
||
|
||
---
|
||
|
||
### 4.2 构建Docker镜像(30分钟)
|
||
|
||
#### 方案选择
|
||
|
||
我们使用**方案B:本地编译 + Docker打包**(最稳定)
|
||
|
||
#### 步骤1:本地编译TypeScript
|
||
|
||
```bash
|
||
cd AIclinicalresearch/backend
|
||
|
||
# 安装依赖
|
||
npm install
|
||
|
||
# 编译TypeScript
|
||
npm run build
|
||
|
||
# 验证编译结果
|
||
ls dist/
|
||
# 应该看到:index.js, common/, modules/ 等
|
||
```
|
||
|
||
#### 步骤2:检查Dockerfile
|
||
|
||
确认Dockerfile内容正确:
|
||
|
||
```dockerfile
|
||
FROM node:22-alpine
|
||
|
||
WORKDIR /app
|
||
|
||
# 复制package.json和package-lock.json
|
||
COPY package*.json ./
|
||
|
||
# 只安装生产依赖
|
||
RUN npm ci --only=production --ignore-scripts
|
||
|
||
# 复制编译后的代码
|
||
COPY dist ./dist
|
||
|
||
# 复制Prisma客户端
|
||
COPY node_modules/.prisma ./node_modules/.prisma
|
||
|
||
# 复制Prisma schema(用于runtime)
|
||
COPY prisma ./prisma
|
||
|
||
# ⚠️ 复制config目录(重要!)
|
||
COPY config ./config
|
||
|
||
# 暴露端口
|
||
EXPOSE 3001
|
||
|
||
# 启动命令
|
||
CMD ["node", "dist/index.js"]
|
||
```
|
||
|
||
**⚠️ 关键修复1**:必须包含 `COPY config ./config`,否则会报错 `ENOENT: no such file or directory, open '/app/config/agents.yaml'`
|
||
|
||
#### 步骤3:构建镜像
|
||
|
||
```bash
|
||
# 构建镜像
|
||
docker build -t backend-service:v1.3 .
|
||
|
||
# 等待构建完成(约5分钟)
|
||
```
|
||
|
||
#### 步骤4:本地测试(推荐)
|
||
|
||
```bash
|
||
# 运行容器(连接本地数据库测试)
|
||
docker run -d -p 3001:3001 \
|
||
-e NODE_ENV=production \
|
||
-e DATABASE_URL="postgresql://postgres:postgres@host.docker.internal:5432/ai_clinical_research" \
|
||
-e EXTRACTION_SERVICE_URL=http://host.docker.internal:8000 \
|
||
--name backend-test \
|
||
backend-service:v1.3
|
||
|
||
# 查看日志
|
||
docker logs -f backend-test
|
||
|
||
# 应该看到:
|
||
# ✅ Loaded 12 agent configurations
|
||
# ✅ 数据库连接成功
|
||
# 🚀 AI临床研究平台 - 后端服务器启动成功!
|
||
# 📍 服务地址: http://localhost:3001
|
||
|
||
# 测试健康检查
|
||
curl http://localhost:3001/health
|
||
|
||
# 停止测试容器
|
||
docker stop backend-test
|
||
docker rm backend-test
|
||
```
|
||
|
||
#### 步骤5:推送到ACR
|
||
|
||
```bash
|
||
# 打标签
|
||
docker tag backend-service:v1.3 \
|
||
crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/backend-service:v1.3
|
||
|
||
# 推送镜像
|
||
docker push \
|
||
crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/backend-service:v1.3
|
||
|
||
# 等待推送完成(约10分钟,镜像约838MB)
|
||
```
|
||
|
||
---
|
||
|
||
### 4.3 部署到SAE(10分钟)
|
||
|
||
**登录SAE控制台**:https://sae.console.aliyun.com/
|
||
|
||
#### 创建应用
|
||
|
||
1. 点击【创建应用】
|
||
2. 应用基本信息:
|
||
```yaml
|
||
应用名称: nodejs-backend-test
|
||
命名空间: cn-beijing:test-airesearch
|
||
|
||
# 实例规格
|
||
CPU: 1核
|
||
内存: 2GB
|
||
实例数: 1
|
||
```
|
||
|
||
3. 选择镜像:
|
||
```yaml
|
||
镜像类型: 容器镜像服务企业版/个人版
|
||
地域: 华北2(北京)
|
||
命名空间: ai-clinical
|
||
仓库: backend-service
|
||
镜像版本: v1.3
|
||
|
||
# 镜像访问凭证
|
||
用户名: gofeng117@163.com
|
||
密码: fengzhibo117
|
||
```
|
||
|
||
4. 应用配置:
|
||
```yaml
|
||
# 启动命令
|
||
启动命令: 留空(使用Dockerfile的CMD)
|
||
|
||
# ⚠️ 关键:不要配置 /bin/bash,Alpine Linux没有bash!
|
||
|
||
# 端口配置
|
||
容器端口: 3001
|
||
协议: TCP
|
||
```
|
||
|
||
5. 环境变量(⚠️ 非常重要!):
|
||
|
||
**复制上面准备的完整环境变量清单**,特别注意:
|
||
|
||
```bash
|
||
# ⚠️ 最容易出错的环境变量
|
||
EXTRACTION_SERVICE_URL=http://172.17.173.66:8000
|
||
# 不是 PYTHON_SERVICE_URL!名字必须正确!
|
||
|
||
DATABASE_URL=postgresql://airesearch:Xibahe%40fengzhibo117@pgm-2zex1m2y3r23hdn5.pg.rds.aliyuncs.com:5432/ai_clinical_research?connection_limit=18&pool_timeout=10
|
||
# 注意:@ 要写成 %40
|
||
```
|
||
|
||
6. 网络配置:
|
||
```yaml
|
||
VPC: ai-clinical-vpc
|
||
交换机: ai-clinical-vsw-f
|
||
安全组: ai-clinical-sg
|
||
```
|
||
|
||
7. 健康检查:
|
||
```yaml
|
||
# 存活检查(Liveness)
|
||
检查方式: HTTP
|
||
检查路径: /health
|
||
端口: 3001
|
||
初始延迟: 60秒 # Node.js启动较慢
|
||
检查间隔: 10秒
|
||
|
||
# 就绪检查(Readiness)
|
||
检查方式: HTTP
|
||
检查路径: /health
|
||
端口: 3001
|
||
初始延迟: 30秒
|
||
```
|
||
|
||
8. 点击【确认创建】
|
||
|
||
#### 等待部署完成
|
||
|
||
- 查看【实例部署】页面
|
||
- 状态变为【Running】(约10分钟)
|
||
- 记录内网地址:`http://172.17.173.73:3001`
|
||
|
||
#### 验证部署
|
||
|
||
查看日志,确认以下信息:
|
||
|
||
```bash
|
||
# ✅ 应该看到的日志:
|
||
✅ Loaded 12 agent configurations
|
||
[PgBossQueue] Using PgBossQueue (Postgres-Only架构)
|
||
[PostgresCacheAdapter] Cleanup task started
|
||
✅ 数据库连接成功!
|
||
📊 数据库版本: PostgreSQL 15.14
|
||
PythonExecutorService initialized: http://172.17.173.66:8000 # ⚠️ 确认这个!
|
||
🚀 AI临床研究平台 - 后端服务器启动成功!
|
||
📍 服务地址: http://localhost:3001
|
||
Server listening at http://172.17.173.73:3001
|
||
|
||
# ❌ 如果看到错误:
|
||
ENOENT: no such file or directory, open '/app/config/agents.yaml'
|
||
→ Dockerfile缺少 COPY config ./config
|
||
|
||
Error: unable to determine transport target for "pino-pretty"
|
||
→ src/index.ts 日志配置问题,需要条件判断环境
|
||
|
||
ReferenceError: require is not defined
|
||
→ healthCheck.ts 使用了require,需改为import
|
||
```
|
||
|
||
---
|
||
|
||
### 4.4 常见问题修复
|
||
|
||
#### 问题1:config目录缺失
|
||
|
||
**错误**:
|
||
```
|
||
ENOENT: no such file or directory, open '/app/config/agents.yaml'
|
||
```
|
||
|
||
**解决**:
|
||
```dockerfile
|
||
# 在Dockerfile中添加
|
||
COPY config ./config
|
||
```
|
||
|
||
#### 问题2:pino-pretty生产环境报错
|
||
|
||
**错误**:
|
||
```
|
||
Error: unable to determine transport target for "pino-pretty"
|
||
```
|
||
|
||
**解决**:修改 `src/index.ts`
|
||
```typescript
|
||
const fastify = Fastify({
|
||
logger: config.nodeEnv === 'production'
|
||
? { level: config.logLevel } // 生产环境:简单JSON日志
|
||
: { // 开发环境:pino-pretty
|
||
level: config.logLevel,
|
||
transport: {
|
||
target: 'pino-pretty',
|
||
options: {
|
||
colorize: true,
|
||
translateTime: 'HH:MM:ss Z',
|
||
ignore: 'pid,hostname',
|
||
},
|
||
},
|
||
},
|
||
});
|
||
```
|
||
|
||
#### 问题3:healthCheck require报错
|
||
|
||
**错误**:
|
||
```
|
||
ReferenceError: require is not defined in ES module
|
||
```
|
||
|
||
**解决**:修改 `src/common/health/healthCheck.ts`
|
||
```typescript
|
||
import os from 'os'; // 添加导入
|
||
|
||
// 修改使用方式
|
||
checks.cpu = {
|
||
usage: process.cpuUsage(),
|
||
loadAverage: process.platform !== 'win32' ? os.loadavg() : 'N/A' // 使用import的os
|
||
}
|
||
```
|
||
|
||
#### 问题4:bash路径错误
|
||
|
||
**错误**:
|
||
```
|
||
executable '/bin/bash' not found in $PATH
|
||
```
|
||
|
||
**解决**:
|
||
- SAE启动命令留空,使用Dockerfile的CMD
|
||
- 或使用 `/bin/sh` 代替 `/bin/bash`
|
||
|
||
---
|
||
|
||
## 🎨 五、前端Nginx部署(30分钟)
|
||
|
||
### 5.1 构建Docker镜像(15分钟)
|
||
|
||
#### 进入目录
|
||
|
||
```bash
|
||
cd AIclinicalresearch/frontend-v2
|
||
```
|
||
|
||
#### 检查关键文件
|
||
|
||
**1. Dockerfile**(多阶段构建):
|
||
```dockerfile
|
||
# 第一阶段:构建React应用
|
||
FROM node:22-alpine AS builder
|
||
WORKDIR /app
|
||
COPY package*.json ./
|
||
RUN npm ci
|
||
COPY . .
|
||
RUN npm run build
|
||
|
||
# 第二阶段:Nginx托管
|
||
FROM nginx:alpine
|
||
COPY --from=builder /app/dist /usr/share/nginx/html
|
||
COPY nginx.conf /etc/nginx/templates/nginx.conf.template
|
||
COPY docker-entrypoint.sh /docker-entrypoint.sh
|
||
RUN chmod +x /docker-entrypoint.sh
|
||
EXPOSE 80
|
||
ENTRYPOINT ["/docker-entrypoint.sh"]
|
||
```
|
||
|
||
**2. docker-entrypoint.sh**(动态配置):
|
||
```bash
|
||
#!/bin/bash
|
||
set -e
|
||
|
||
# ⚠️ 检查必需的环境变量
|
||
if [ -z "$BACKEND_SERVICE_HOST" ]; then
|
||
echo "❌ ERROR: BACKEND_SERVICE_HOST environment variable is required!"
|
||
exit 1
|
||
fi
|
||
|
||
if [ -z "$BACKEND_SERVICE_PORT" ]; then
|
||
export BACKEND_SERVICE_PORT=3001 # 默认值
|
||
fi
|
||
|
||
# 使用envsubst动态替换配置
|
||
envsubst '${BACKEND_SERVICE_HOST} ${BACKEND_SERVICE_PORT}' \
|
||
< /etc/nginx/templates/nginx.conf.template \
|
||
> /etc/nginx/nginx.conf
|
||
|
||
# 启动Nginx
|
||
exec nginx -g 'daemon off;'
|
||
```
|
||
|
||
**3. nginx.conf**(使用变量占位符):
|
||
```nginx
|
||
upstream backend {
|
||
server ${BACKEND_SERVICE_HOST}:${BACKEND_SERVICE_PORT} fail_timeout=30s max_fails=3;
|
||
keepalive 32;
|
||
}
|
||
|
||
server {
|
||
listen 80;
|
||
root /usr/share/nginx/html;
|
||
|
||
# API反向代理
|
||
location /api/ {
|
||
proxy_pass http://backend;
|
||
proxy_set_header Host $host;
|
||
proxy_set_header X-Real-IP $remote_addr;
|
||
# ...
|
||
}
|
||
|
||
# SPA路由支持
|
||
location / {
|
||
try_files $uri $uri/ /index.html;
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 构建镜像
|
||
|
||
```bash
|
||
# 构建镜像
|
||
docker build -t ai-clinical_frontend-nginx:v1.0 .
|
||
|
||
# 等待构建完成(约10分钟)
|
||
# 第一阶段会构建React应用,第二阶段打包到Nginx
|
||
```
|
||
|
||
#### 本地测试
|
||
|
||
```bash
|
||
# 运行容器
|
||
docker run -d -p 3000:80 \
|
||
-e BACKEND_SERVICE_HOST=host.docker.internal \
|
||
-e BACKEND_SERVICE_PORT=3001 \
|
||
--name frontend-test \
|
||
ai-clinical_frontend-nginx:v1.0
|
||
|
||
# 访问前端
|
||
open http://localhost:3000
|
||
# 或
|
||
curl http://localhost:3000
|
||
|
||
# 停止容器
|
||
docker stop frontend-test
|
||
docker rm frontend-test
|
||
```
|
||
|
||
#### 推送到ACR
|
||
|
||
```bash
|
||
# 打标签
|
||
docker tag ai-clinical_frontend-nginx:v1.0 \
|
||
crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/ai-clinical_frontend-nginx:v1.0
|
||
|
||
# 推送镜像
|
||
docker push \
|
||
crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/ai-clinical_frontend-nginx:v1.0
|
||
|
||
# 等待推送完成(约3分钟,镜像约50MB)
|
||
```
|
||
|
||
---
|
||
|
||
### 5.2 部署到SAE(15分钟)
|
||
|
||
**登录SAE控制台**:https://sae.console.aliyun.com/
|
||
|
||
#### 创建应用
|
||
|
||
1. 点击【创建应用】
|
||
2. 应用基本信息:
|
||
```yaml
|
||
应用名称: frontend-nginx-service
|
||
命名空间: cn-beijing:test-airesearch
|
||
|
||
# 实例规格
|
||
CPU: 0.5核
|
||
内存: 1GB
|
||
实例数: 1
|
||
```
|
||
|
||
3. 选择镜像:
|
||
```yaml
|
||
镜像类型: 容器镜像服务企业版/个人版
|
||
地域: 华北2(北京)
|
||
命名空间: ai-clinical
|
||
仓库: ai-clinical_frontend-nginx
|
||
镜像版本: v1.0
|
||
|
||
# 镜像访问凭证
|
||
用户名: gofeng117@163.com
|
||
密码: fengzhibo117
|
||
```
|
||
|
||
4. 应用配置:
|
||
```yaml
|
||
# 启动命令
|
||
启动命令: 留空(使用ENTRYPOINT)
|
||
|
||
# 端口配置
|
||
容器端口: 80
|
||
协议: TCP
|
||
```
|
||
|
||
5. 环境变量(⚠️ 关键配置):
|
||
```bash
|
||
BACKEND_SERVICE_HOST=172.17.173.73 # Node.js后端内网IP
|
||
BACKEND_SERVICE_PORT=3001
|
||
```
|
||
|
||
6. 网络配置:
|
||
```yaml
|
||
VPC: ai-clinical-vpc
|
||
交换机: ai-clinical-vsw-f
|
||
安全组: ai-clinical-sg
|
||
```
|
||
|
||
7. 健康检查:
|
||
```yaml
|
||
# 存活检查
|
||
检查方式: HTTP
|
||
检查路径: /health
|
||
端口: 80
|
||
初始延迟: 10秒
|
||
检查间隔: 10秒
|
||
|
||
# 就绪检查
|
||
检查方式: HTTP
|
||
检查路径: /health
|
||
端口: 80
|
||
初始延迟: 5秒
|
||
```
|
||
|
||
8. 点击【确认创建】
|
||
|
||
#### 等待部署完成
|
||
|
||
- 查看【实例部署】页面
|
||
- 状态变为【Running】(约5分钟)
|
||
- 记录内网地址:`http://172.17.173.72:80`
|
||
|
||
#### 验证部署
|
||
|
||
查看日志:
|
||
|
||
```bash
|
||
# ✅ 应该看到:
|
||
============================================
|
||
Starting Frontend Nginx Service
|
||
Backend Service: 172.17.173.73:3001
|
||
============================================
|
||
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
|
||
nginx: configuration file /etc/nginx/nginx.conf test is successful
|
||
```
|
||
|
||
---
|
||
|
||
## 🌐 六、CLB负载均衡配置(10分钟)
|
||
|
||
### 6.1 配置公网访问
|
||
|
||
**方式1:SAE自动创建CLB(推荐)**
|
||
|
||
1. 进入SAE应用:`frontend-nginx-service`
|
||
2. 点击【公网访问】或【访问配置】Tab
|
||
3. 点击【添加公网访问】
|
||
4. 配置参数:
|
||
```yaml
|
||
负载均衡类型: 公网
|
||
负载均衡产品: CLB (传统型负载均衡)
|
||
付费模式: 按量付费
|
||
|
||
# 监听配置
|
||
协议: HTTP
|
||
端口: 80
|
||
后端端口: 80
|
||
|
||
# 健康检查
|
||
健康检查: 启用
|
||
检查路径: /health
|
||
```
|
||
5. 点击【确定】
|
||
6. 等待2-3分钟,自动分配公网IP
|
||
|
||
**方式2:手动创建CLB**
|
||
|
||
1. 登录CLB控制台:https://slb.console.aliyun.com/
|
||
2. 创建负载均衡实例
|
||
3. 配置监听器(HTTP:80)
|
||
4. 添加后端服务器(前端Nginx的内网IP)
|
||
5. 配置健康检查
|
||
|
||
### 6.2 获取公网地址
|
||
|
||
- 在SAE应用详情页查看【公网访问地址】
|
||
- 示例:`http://8.140.53.236/`
|
||
- 复制此地址用于测试
|
||
|
||
---
|
||
|
||
## ✅ 七、完整链路测试(30分钟)
|
||
|
||
### 7.1 基础功能测试
|
||
|
||
#### 测试1:前端页面访问
|
||
|
||
```bash
|
||
# 浏览器访问
|
||
http://8.140.53.236/
|
||
|
||
# 应该看到:
|
||
✅ React应用正常加载
|
||
✅ 页面样式正常
|
||
✅ 没有CORS错误
|
||
```
|
||
|
||
#### 测试2:健康检查
|
||
|
||
```bash
|
||
# 后端健康检查(通过前端代理)
|
||
curl http://8.140.53.236/api/v1/health
|
||
# 或
|
||
curl http://172.17.173.73:3001/health
|
||
|
||
# 应该返回:
|
||
{
|
||
"status": "ok",
|
||
"timestamp": "...",
|
||
"services": {
|
||
"database": "connected",
|
||
"cache": "available",
|
||
"queue": "running"
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 测试3:Python服务连接
|
||
|
||
```bash
|
||
# 直接测试Python服务
|
||
curl http://172.17.173.66:8000/api/health
|
||
|
||
# 应该返回:
|
||
{
|
||
"status": "healthy",
|
||
"checks": {
|
||
"pymupdf": {"available": true, "version": "1.26.7"},
|
||
...
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 7.2 业务功能测试
|
||
|
||
#### 测试1:用户登录
|
||
|
||
1. 访问 http://8.140.53.236/
|
||
2. 输入用户名密码
|
||
3. 点击登录
|
||
4. 查看浏览器Network面板:
|
||
```
|
||
Request URL: http://8.140.53.236/api/v1/auth/login
|
||
Status: 200 OK ✅
|
||
Response: { "token": "...", "user": {...} }
|
||
```
|
||
|
||
#### 测试2:数据清洗模块(工具C)
|
||
|
||
1. 进入【数据清洗】→ 【工具C】
|
||
2. 上传Excel文件
|
||
3. 验证上传成功
|
||
4. 测试7大功能之一(如:数值映射):
|
||
- 选择列
|
||
- 配置映射规则
|
||
- 点击【执行映射】
|
||
- 查看结果
|
||
|
||
**关键验证**:
|
||
```
|
||
浏览器Network面板:
|
||
POST http://8.140.53.236/api/v1/dc/tool-c/quick-action
|
||
Status: 200 OK ✅
|
||
|
||
后端日志:
|
||
[QuickActionService] 调用重编码API: 性别
|
||
PythonExecutorService initialized: http://172.17.173.66:8000 ✅
|
||
[QuickActionService] 重编码成功 ✅
|
||
```
|
||
|
||
#### 测试3:文献筛查模块(ASL)
|
||
|
||
1. 进入【文献筛查】模块
|
||
2. 创建项目
|
||
3. 上传文献
|
||
4. 执行智能筛查
|
||
5. 验证结果
|
||
|
||
---
|
||
|
||
### 7.3 性能测试
|
||
|
||
#### 响应时间检查
|
||
|
||
```bash
|
||
# 使用curl测试响应时间
|
||
curl -w "@-" -o /dev/null -s http://8.140.53.236/ <<'EOF'
|
||
time_namelookup: %{time_namelookup}\n
|
||
time_connect: %{time_connect}\n
|
||
time_appconnect: %{time_appconnect}\n
|
||
time_pretransfer: %{time_pretransfer}\n
|
||
time_redirect: %{time_redirect}\n
|
||
time_starttransfer: %{time_starttransfer}\n
|
||
----------\n
|
||
time_total: %{time_total}\n
|
||
EOF
|
||
|
||
# 期望结果:
|
||
# time_total < 1秒(首次访问)
|
||
# time_total < 0.3秒(后续访问)
|
||
```
|
||
|
||
---
|
||
|
||
## 📊 八、部署成果总结
|
||
|
||
### 8.1 已部署服务清单
|
||
|
||
| 服务 | 状态 | 内网地址 | 公网访问 |
|
||
|------|------|---------|---------|
|
||
| RDS PostgreSQL | ✅ | pgm-2zex1m2y3r23hdn5.pg.rds.aliyuncs.com:5432 | ❌ |
|
||
| Python微服务 | ✅ | 172.17.173.66:8000 | ❌ |
|
||
| Node.js后端 | ✅ | 172.17.173.73:3001 | ❌ |
|
||
| 前端Nginx | ✅ | 172.17.173.72:80 | ✅ |
|
||
| CLB负载均衡 | ✅ | - | http://8.140.53.236/ |
|
||
|
||
### 8.2 关键配置速查
|
||
|
||
#### Python微服务环境变量
|
||
```bash
|
||
LOG_LEVEL=INFO
|
||
TEMP_DIR=/tmp/extraction_service
|
||
```
|
||
|
||
#### Node.js后端关键环境变量
|
||
```bash
|
||
NODE_ENV=production
|
||
PORT=3001
|
||
DATABASE_URL=postgresql://airesearch:Xibahe%40fengzhibo117@pgm-2zex1m2y3r23hdn5.pg.rds.aliyuncs.com:5432/ai_clinical_research
|
||
EXTRACTION_SERVICE_URL=http://172.17.173.66:8000 # ⚠️ 关键!不是PYTHON_SERVICE_URL
|
||
```
|
||
|
||
#### 前端Nginx关键环境变量
|
||
```bash
|
||
BACKEND_SERVICE_HOST=172.17.173.73 # Node.js后端内网IP
|
||
BACKEND_SERVICE_PORT=3001
|
||
```
|
||
|
||
---
|
||
|
||
## ⚠️ 九、关键经验与注意事项
|
||
|
||
### 9.1 环境变量名必须精确
|
||
|
||
**问题**:工具C的7大功能全部报错
|
||
```
|
||
connect ECONNREFUSED 127.0.0.1:8000
|
||
```
|
||
|
||
**原因**:Node.js代码使用 `EXTRACTION_SERVICE_URL`,但SAE配置了 `PYTHON_SERVICE_URL`
|
||
|
||
**解决**:
|
||
```bash
|
||
# ❌ 错误
|
||
PYTHON_SERVICE_URL=http://172.17.173.66:8000
|
||
|
||
# ✅ 正确
|
||
EXTRACTION_SERVICE_URL=http://172.17.173.66:8000
|
||
```
|
||
|
||
**教训**:环境变量名必须与代码完全一致,一个字母都不能错!
|
||
|
||
---
|
||
|
||
### 9.2 "重启应用" vs "部署应用"
|
||
|
||
**问题**:点击"部署应用"导致IP地址变更
|
||
|
||
| 操作 | 用途 | IP是否变 | 何时使用 |
|
||
|------|------|---------|---------|
|
||
| **重启应用** | 重启容器 | ❌ 不会 | 修改环境变量后 |
|
||
| **部署应用** | 更新镜像 | ✅ 会变 | 更新代码/镜像时 |
|
||
|
||
**教训**:
|
||
- 只修改环境变量 → 用"重启应用"
|
||
- 更新代码/镜像 → 用"部署应用"
|
||
|
||
---
|
||
|
||
### 9.3 Dockerfile必须包含config目录
|
||
|
||
**问题**:
|
||
```
|
||
ENOENT: no such file or directory, open '/app/config/agents.yaml'
|
||
```
|
||
|
||
**解决**:
|
||
```dockerfile
|
||
# ✅ 必须添加
|
||
COPY config ./config
|
||
```
|
||
|
||
---
|
||
|
||
### 9.4 pino-pretty仅用于开发环境
|
||
|
||
**问题**:
|
||
```
|
||
Error: unable to determine transport target for "pino-pretty"
|
||
```
|
||
|
||
**原因**:`pino-pretty`是devDependencies,生产环境没有安装
|
||
|
||
**解决**:条件判断环境
|
||
```typescript
|
||
logger: config.nodeEnv === 'production'
|
||
? { level: config.logLevel }
|
||
: { level: config.logLevel, transport: { target: 'pino-pretty', ... } }
|
||
```
|
||
|
||
---
|
||
|
||
### 9.5 ES Module兼容性
|
||
|
||
**问题**:
|
||
```
|
||
ReferenceError: require is not defined in ES module
|
||
```
|
||
|
||
**解决**:
|
||
```typescript
|
||
// ❌ 错误
|
||
require('os').loadavg()
|
||
|
||
// ✅ 正确
|
||
import os from 'os';
|
||
os.loadavg()
|
||
```
|
||
|
||
---
|
||
|
||
### 9.6 Alpine Linux没有bash
|
||
|
||
**问题**:
|
||
```
|
||
executable '/bin/bash' not found in $PATH
|
||
```
|
||
|
||
**解决**:
|
||
- SAE启动命令留空
|
||
- 或使用 `/bin/sh` 代替
|
||
|
||
---
|
||
|
||
### 9.7 数据库URL中的@符号
|
||
|
||
**格式**:
|
||
```bash
|
||
# ✅ 正确(URL编码)
|
||
DATABASE_URL=postgresql://airesearch:Xibahe%40fengzhibo117@pgm-xxx.pg.rds.aliyuncs.com:5432/ai_clinical_research
|
||
|
||
# ❌ 错误(未编码)
|
||
DATABASE_URL=postgresql://airesearch:Xibahe@fengzhibo117@pgm-xxx.pg.rds.aliyuncs.com:5432/ai_clinical_research
|
||
```
|
||
|
||
**规则**:密码中的 `@` 必须编码为 `%40`
|
||
|
||
---
|
||
|
||
### 9.8 使用VPC镜像地址(SAE拉取)
|
||
|
||
**SAE部署时选择镜像**:
|
||
```bash
|
||
# ✅ 正确(VPC地址,免流量费)
|
||
crpi-cd5ij4pjt65mweeo-vpc.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/backend-service:v1.3
|
||
|
||
# ❌ 不推荐(公网地址,收流量费)
|
||
crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/backend-service:v1.3
|
||
```
|
||
|
||
**规则**:
|
||
- 本地推送镜像 → 使用公网地址
|
||
- SAE拉取镜像 → 使用VPC地址
|
||
|
||
---
|
||
|
||
### 9.9 健康检查初始延迟
|
||
|
||
**不同服务的启动时间**:
|
||
|
||
| 服务 | 启动时间 | 初始延迟建议 |
|
||
|------|---------|-------------|
|
||
| Python微服务 | 10秒 | 30秒 |
|
||
| Node.js后端 | 30秒 | 60秒 |
|
||
| 前端Nginx | 5秒 | 10秒 |
|
||
|
||
**教训**:Node.js启动较慢,需要更长的初始延迟
|
||
|
||
---
|
||
|
||
### 9.10 前端动态配置后端地址
|
||
|
||
**架构优势**:
|
||
- 前端使用环境变量 `BACKEND_SERVICE_HOST`
|
||
- 通过 `envsubst` 在容器启动时动态注入
|
||
- 后端IP变更时,只需重启前端应用,无需重新构建镜像
|
||
|
||
**关键文件**:
|
||
- `docker-entrypoint.sh`:动态替换配置
|
||
- `nginx.conf`:使用 `${BACKEND_SERVICE_HOST}` 占位符
|
||
|
||
---
|
||
|
||
## 🚀 十、未来优化建议
|
||
|
||
### 10.1 使用服务发现代替IP地址
|
||
|
||
**当前配置**(使用IP):
|
||
```bash
|
||
BACKEND_SERVICE_HOST=172.17.173.73
|
||
EXTRACTION_SERVICE_URL=http://172.17.173.66:8000
|
||
```
|
||
|
||
**优化方案**(使用服务名):
|
||
```bash
|
||
BACKEND_SERVICE_HOST=nodejs-backend-test.cn-beijing:test-airesearch.svc.cluster.local
|
||
EXTRACTION_SERVICE_URL=http://python-extraction-test.cn-beijing:test-airesearch.svc.cluster.local:8000
|
||
```
|
||
|
||
**优点**:
|
||
- ✅ IP变更不影响通信
|
||
- ✅ 自动负载均衡
|
||
- ✅ 更稳定可靠
|
||
|
||
---
|
||
|
||
### 10.2 配置HTTPS
|
||
|
||
**步骤**:
|
||
1. 申请域名
|
||
2. 申请SSL证书(阿里云免费证书或Let's Encrypt)
|
||
3. 在CLB配置HTTPS监听(端口443)
|
||
4. 上传SSL证书
|
||
5. 配置HTTP自动跳转HTTPS
|
||
|
||
---
|
||
|
||
### 10.3 配置自动扩缩容
|
||
|
||
**SAE弹性伸缩**:
|
||
```yaml
|
||
# 根据CPU使用率自动扩缩容
|
||
最小实例数: 1
|
||
最大实例数: 3
|
||
目标CPU使用率: 70%
|
||
```
|
||
|
||
**适用场景**:
|
||
- 流量波动大
|
||
- 高峰期需要更多实例
|
||
- 低峰期节约成本
|
||
|
||
---
|
||
|
||
### 10.4 配置日志分析
|
||
|
||
**阿里云SLS(日志服务)**:
|
||
- 自动收集SAE日志
|
||
- 实时查询和分析
|
||
- 配置告警规则
|
||
|
||
---
|
||
|
||
### 10.5 配置监控告警
|
||
|
||
**云监控配置**:
|
||
```yaml
|
||
CPU使用率 > 80% → 告警
|
||
内存使用率 > 80% → 告警
|
||
健康检查失败 → 告警
|
||
错误日志增多 → 告警
|
||
```
|
||
|
||
---
|
||
|
||
## 📝 十一、快速命令参考
|
||
|
||
### 11.1 Docker镜像管理
|
||
|
||
```bash
|
||
# 登录ACR
|
||
docker login --username=gofeng117@163.com \
|
||
--password=fengzhibo117 \
|
||
crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com
|
||
|
||
# 构建并推送Python镜像
|
||
cd AIclinicalresearch/extraction_service
|
||
docker build -t python-extraction:v1.0 .
|
||
docker tag python-extraction:v1.0 \
|
||
crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/python-extraction:v1.0
|
||
docker push crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/python-extraction:v1.0
|
||
|
||
# 构建并推送Node.js镜像
|
||
cd ../backend
|
||
npm run build
|
||
docker build -t backend-service:v1.3 .
|
||
docker tag backend-service:v1.3 \
|
||
crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/backend-service:v1.3
|
||
docker push crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/backend-service:v1.3
|
||
|
||
# 构建并推送前端镜像
|
||
cd ../frontend-v2
|
||
docker build -t ai-clinical_frontend-nginx:v1.0 .
|
||
docker tag ai-clinical_frontend-nginx:v1.0 \
|
||
crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/ai-clinical_frontend-nginx:v1.0
|
||
docker push crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/ai-clinical_frontend-nginx:v1.0
|
||
```
|
||
|
||
---
|
||
|
||
### 11.2 数据库连接
|
||
|
||
```bash
|
||
# 连接到RDS(临时开启外网)
|
||
docker exec -e PGPASSWORD="Xibahe@fengzhibo117" \
|
||
ai-clinical-postgres psql \
|
||
-h pgm-2zex1m2y3r23hdn5.pg.rds.aliyuncs.com \
|
||
-p 5432 -U airesearch -d ai_clinical_research
|
||
|
||
# 查看Schema列表
|
||
docker exec -e PGPASSWORD="Xibahe@fengzhibo117" \
|
||
ai-clinical-postgres psql \
|
||
-h pgm-2zex1m2y3r23hdn5.pg.rds.aliyuncs.com \
|
||
-p 5432 -U airesearch -d ai_clinical_research \
|
||
-c "SELECT nspname FROM pg_namespace WHERE nspname LIKE '%_schema';"
|
||
```
|
||
|
||
---
|
||
|
||
### 11.3 健康检查
|
||
|
||
```bash
|
||
# Python服务
|
||
curl http://172.17.173.66:8000/api/health
|
||
|
||
# Node.js后端
|
||
curl http://172.17.173.73:3001/health
|
||
|
||
# 前端Nginx
|
||
curl http://172.17.173.72:80/health
|
||
|
||
# 公网访问
|
||
curl http://8.140.53.236/
|
||
```
|
||
|
||
---
|
||
|
||
## 🎉 十二、部署完成检查清单
|
||
|
||
### 最终验证
|
||
|
||
- [ ] ✅ Python微服务健康检查通过
|
||
- [ ] ✅ Node.js后端健康检查通过
|
||
- [ ] ✅ 前端Nginx健康检查通过
|
||
- [ ] ✅ 公网地址可以访问
|
||
- [ ] ✅ 用户可以正常登录
|
||
- [ ] ✅ 文献筛查功能正常
|
||
- [ ] ✅ 数据清洗工具C的7大功能正常
|
||
- [ ] ✅ 文件上传功能正常
|
||
- [ ] ✅ AI对话功能正常
|
||
- [ ] ✅ 没有CORS错误
|
||
- [ ] ✅ 没有502/504错误
|
||
- [ ] ✅ 响应时间 < 1秒
|
||
|
||
### 文档更新
|
||
|
||
- [ ] 更新 `00-部署进度总览.md` 中的内网IP地址
|
||
- [ ] 记录公网访问地址
|
||
- [ ] 记录遇到的问题和解决方案
|
||
- [ ] 更新环境变量清单
|
||
|
||
---
|
||
|
||
## 📞 十三、技术支持
|
||
|
||
### 常见问题排查
|
||
|
||
**问题1:工具C功能报错 "connect ECONNREFUSED 127.0.0.1:8000"**
|
||
- 检查Node.js环境变量 `EXTRACTION_SERVICE_URL`
|
||
- 确保值为 `http://172.17.173.66:8000`
|
||
- 重启Node.js应用
|
||
|
||
**问题2:前端访问后端报502错误**
|
||
- 检查前端环境变量 `BACKEND_SERVICE_HOST`
|
||
- 确保值为Node.js后端的内网IP
|
||
- 重启前端应用
|
||
|
||
**问题3:SAE应用启动失败**
|
||
- 查看实例日志,找到具体错误信息
|
||
- 参考本文档第9节"关键经验与注意事项"
|
||
- 对照检查Dockerfile和环境变量
|
||
|
||
---
|
||
|
||
## 🎯 总结
|
||
|
||
恭喜!您已经完成了AI临床研究平台的完整部署!
|
||
|
||
**部署成果**:
|
||
- ✅ 4个服务全部成功部署(Python、Node.js、前端、数据库)
|
||
- ✅ 所有功能正常运行
|
||
- ✅ 公网可以访问
|
||
- ✅ 生产环境就绪
|
||
|
||
**部署时间**:
|
||
- 预计时间:3.5小时
|
||
- 实际时间:约6小时(包含问题排查)
|
||
|
||
**关键经验**:
|
||
- 环境变量名必须精确匹配
|
||
- 区分"重启应用"和"部署应用"
|
||
- Dockerfile必须包含所有必需文件
|
||
- 使用VPC地址拉取镜像
|
||
- 健康检查初始延迟要足够
|
||
|
||
**下一步**:
|
||
- 配置HTTPS
|
||
- 绑定域名
|
||
- 配置监控告警
|
||
- 优化性能
|
||
- 配置自动备份
|
||
|
||
---
|
||
|
||
> **文档维护**:本文档基于2025-12-25实际部署经历编写,请根据实际情况更新
|
||
> **最后更新**:2025-12-25
|
||
> **部署状态**:✅ 完全成功
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|