Major Changes: - Database: Install pg_bigm/pgvector plugins, create test database - Python service: v1.0 -> v1.1, add pymupdf4llm/openpyxl/pypandoc - Node.js backend: v1.3 -> v1.7, fix pino-pretty and ES Module imports - Frontend: v1.2 -> v1.3, skip TypeScript check for deployment - Code recovery: Restore empty files from local backup Technical Fixes: - Fix pino-pretty error in production (conditional loading) - Fix ES Module import paths (add .js extensions) - Fix OSSAdapter TypeScript errors - Update Prisma Schema (63 models, 16 schemas) - Update environment variables (DATABASE_URL, EXTRACTION_SERVICE_URL, OSS) - Remove deprecated variables (REDIS_URL, DIFY_API_URL, DIFY_API_KEY) Documentation: - Create 0126 deployment folder with 8 documents - Update database development standards v2.0 - Update SAE deployment status records Deployment Status: - PostgreSQL: ai_clinical_research_test with plugins - Python: v1.1 @ 172.17.173.84:8000 - Backend: v1.7 @ 172.17.173.89:3001 - Frontend: v1.3 @ 172.17.173.90:80 Tested: All services running successfully on SAE
13 KiB
13 KiB
Node.js 后端 - Docker 镜像构建操作手册
文档版本: v1.0
创建时间: 2024-12-24
适用范围: AIclinicalresearch 平台 - Node.js 后端服务
目标读者: 运维工程师、后端开发工程师
📋 目录
1. 构建概述
1.1 构建策略
本次构建采用改进版方案B(本地编译+Docker打包),相比传统方案有以下优势:
| 对比项 | 传统方案 | 改进版方案B |
|---|---|---|
| TypeScript编译 | Docker中执行 | 本地预编译 ✅ |
| 依赖安装 | 完整依赖 | 仅生产依赖 ✅ |
| 网络依赖 | 高(易超时) | 低(更稳定) ✅ |
| 构建时间 | ~10分钟 | ~5分钟 ✅ |
| 平台兼容性 | 有风险 | 无风险 ✅ |
1.2 构建成果
镜像名称: backend-service:v1.0
镜像大小: 838MB (压缩后 ~186MB)
镜像ID: a4ffb61c15af
构建时间: ~5分钟
ACR地址: crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/backend-service:v1.0
2. 前置准备
2.1 环境检查
# 1. 检查Docker状态
docker --version
docker ps
# 2. 检查Node.js环境
node --version # 应该显示 v22.x
npm --version
# 3. 确认当前目录
cd D:\MyCursor\AIclinicalresearch\backend
2.2 代码准备
✅ 必须完成的步骤
步骤1:Prisma反向同步(必须)
# 设置临时RDS连接环境变量
$env:DATABASE_URL = "postgresql://airesearch:Xibahe%40fengzhibo117@pgm-2zex1m2y3r23hdn5oo.pg.rds.aliyuncs.com:5432/ai_clinical_research?connection_limit=18&pool_timeout=10"
# 执行Prisma反向同步
npx prisma db pull
# 输出应该显示:
# ✔ Introspected 32 models and wrote them into prisma\schema.prisma
步骤2:生成Prisma Client
npx prisma generate
# 输出应该显示:
# ✔ Generated Prisma Client (v6.17.0)
步骤3:TypeScript编译(必须)
# 编译TypeScript代码
npm run build
# 成功输出:
# > ai-clinical-backend@1.0.0 build
# > tsc
# (无错误信息)
# 检查dist目录是否生成
ls dist
⚠️ 重要提示:如果编译失败,必须先修复所有TypeScript错误!
3. 构建流程
3.1 完整构建步骤
# 1. 确保在backend目录
cd D:\MyCursor\AIclinicalresearch\backend
# 2. 检查Dockerfile和.dockerignore
ls Dockerfile
ls .dockerignore
# 3. 开始构建(需要5分钟)
docker build -t backend-service:v1.0 .
# 4. 查看构建结果
docker images backend-service:v1.0
3.2 构建过程说明
阶段1:依赖安装(约4分钟)
FROM node:alpine AS builder
RUN apk add --no-cache openssl
COPY package*.json ./
COPY prisma ./prisma/
RUN npm ci --production # 仅安装生产依赖
RUN npx prisma generate # 生成Prisma Client
阶段2:复制本地编译结果(约10秒)
COPY dist ./dist # 复制本地已编译的TypeScript代码
阶段3:运行镜像打包(约1分钟)
FROM node:alpine
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/prisma ./prisma
3.3 推送到ACR
# 1. 登录ACR(使用个人版实例地址)
echo "fengzhibo117" | docker login --username=gofeng117@163.com --password-stdin crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com
# 输出:Login Succeeded
# 2. 打标签
docker tag backend-service:v1.0 crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/backend-service:v1.0
docker tag backend-service:v1.0 crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/backend-service:latest
# 3. 推送镜像
docker push crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/backend-service:v1.0
docker push crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/backend-service:latest
# 输出:
# v1.0: digest: sha256:a4ffb61c15af... size: 856
# latest: digest: sha256:a4ffb61c15af... size: 856
4. 镜像信息
4.1 镜像地址
VPC内网地址(SAE部署使用):
crpi-cd5ij4pjt65mweeo-vpc.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/backend-service:v1.0
公网地址(查看和拉取):
crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/backend-service:v1.0
4.2 镜像详情
镜像摘要: sha256:a4ffb61c15af1cd1ed9de187b4464a1aab773918e5b41b4df5b8ad96514f9941
大小: 838MB (压缩后 ~186MB)
架构: linux/amd64
基础镜像: node:alpine
Node版本: 22.x
标签: v1.0, latest
4.3 镜像内容
/app/
├── node_modules/ # 生产依赖
├── dist/ # 编译后的JS代码
├── prisma/ # Prisma Schema
│ └── schema.prisma
├── package.json
└── uploads/ # 临时文件目录
4.4 启动命令
CMD ["node", "dist/index.js"]
4.5 健康检查
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
CMD node -e "require('http').get('http://localhost:3001/health', (res) => { process.exit(res.statusCode === 200 ? 0 : 1); })"
5. 故障排查
5.1 常见问题
❌ 问题1:TypeScript编译失败
症状:
error TS2554: Expected 2-3 arguments, but got 1.
error TS2322: Type 'XXX' is not assignable to type 'YYY'.
原因:
- Prisma反向同步后缺少关系字段
- 代码与Prisma生成的类型不匹配
解决方案:
# 1. 重新同步Prisma
npx prisma db pull
npx prisma generate
# 2. 重新编译
npm run build
# 3. 如果还有错误,检查tsconfig.json配置
❌ 问题2:Docker构建网络超时
症状:
npm error code ECONNRESET
npm error network aborted
原因:
- npm镜像源网络不稳定
- npm ci 下载依赖失败
解决方案: ✅ 使用改进版方案B(本次采用的方案)
- 本地预编译,跳过Docker中的编译步骤
- 只安装生产依赖,减少网络传输
❌ 问题3:推送到ACR失败(403 Forbidden)
症状:
Error response from daemon: login attempt to https://registry.cn-beijing.aliyuncs.com/v2/ failed with status: 403 Forbidden
原因:
- 使用了错误的ACR地址
- 应该使用个人版实例地址,不是企业版地址
解决方案:
# ✅ 正确的登录地址(个人版实例)
docker login crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com
# ❌ 错误的登录地址(企业版)
docker login registry.cn-beijing.aliyuncs.com
❌ 问题4:VPC内网地址推送超时
症状:
failed to do request: Head "https://crpi-cd5ij4pjt65mweeo-vpc.cn-beijing.personal.cr.aliyuncs.com/...": net/http: TLS handshake timeout
原因:
- VPC内网地址只能在阿里云VPC内访问
- 本地开发环境无法访问VPC内网
解决方案:
# 本地开发环境使用公网地址推送
docker push crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/backend-service:v1.0
# SAE部署时使用VPC内网地址拉取(在SAE控制台配置)
5.2 验证镜像
# 1. 检查镜像是否存在
docker images backend-service:v1.0
# 2. 查看镜像详细信息
docker inspect backend-service:v1.0
# 3. 测试运行镜像(可选)
docker run -d `
--name backend-test `
-p 3001:3001 `
-e DATABASE_URL="postgresql://..." `
-e NODE_ENV=production `
backend-service:v1.0
# 4. 查看容器日志
docker logs backend-test
# 5. 测试健康检查
curl http://localhost:3001/health
# 6. 清理测试容器
docker stop backend-test
docker rm backend-test
6. 最佳实践
6.1 构建前检查清单
- 已完成Prisma反向同步(
npx prisma db pull) - 已生成Prisma Client(
npx prisma generate) - TypeScript编译成功(
npm run build) - dist目录已生成且包含所有编译后的JS文件
- Docker Desktop已启动并运行
- 网络连接正常
6.2 版本管理
镜像标签规范:
v1.0 - 特定版本(推荐用于生产环境)
latest - 最新版本(用于测试环境)
v1.0.1 - Bug修复版本
v1.1.0 - 功能更新版本
推送策略:
# 生产环境部署(推送特定版本)
docker push crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/backend-service:v1.0
# 测试环境部署(同时推送latest)
docker push crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/backend-service:v1.0
docker push crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/backend-service:latest
6.3 构建优化
1. 利用Docker缓存
# ✅ 先复制package.json,利用依赖缓存
COPY package*.json ./
RUN npm ci --production
# ✅ 最后复制代码,代码变化不影响依赖层缓存
COPY dist ./dist
2. 使用.dockerignore
node_modules
.env
.env.*
dist # 本地dist通过COPY显式复制
test
tests
*.md
.git
3. 多阶段构建
# 阶段1:依赖安装
FROM node:alpine AS builder
...
# 阶段2:运行时镜像(更小)
FROM node:alpine
COPY --from=builder ...
6.4 安全建议
-
不要在镜像中包含敏感信息
- ❌ 不要把
.env文件复制到镜像 - ✅ 使用SAE环境变量注入配置
- ❌ 不要把
-
使用非root用户运行
RUN addgroup -g 1001 -S nodejs && \ adduser -S nodejs -u 1001 USER nodejs -
定期更新基础镜像
FROM node:alpine # 使用最新的Alpine版本
附录A:Dockerfile完整内容
# ==================== 阶段 1: 依赖安装阶段 ====================
FROM node:alpine AS builder
# 替换Alpine镜像源为阿里云镜像(解决网络问题)
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories
# 安装 Prisma 运行时依赖
RUN apk add --no-cache openssl
WORKDIR /app
# 1. 复制依赖文件
COPY package*.json ./
# 2. 复制 Prisma Schema(用于生成Prisma Client)
COPY prisma ./prisma/
# 3. 只安装生产依赖(大幅减少网络传输和安装时间)
RUN npm config set registry https://registry.npmmirror.com && \
npm config set fetch-retry-mintimeout 20000 && \
npm config set fetch-retry-maxtimeout 120000 && \
npm config set fetch-retries 5 && \
npm ci --production --prefer-offline --no-audit
# 4. 生成 Prisma Client(生产环境需要)
RUN npx prisma generate
# 5. 复制本地已编译好的 dist 文件夹(跳过TypeScript编译)
COPY dist ./dist
# ==================== 阶段 2: 运行阶段 ====================
FROM node:alpine
# 替换Alpine镜像源为阿里云镜像(解决网络问题)
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories
# 安装运行时依赖 + 时区数据
RUN apk add --no-cache \
openssl \
curl \
ca-certificates \
tzdata
# ⚠️ 统一时区:Asia/Shanghai
ENV TZ=Asia/Shanghai
# 创建非 root 用户(安全最佳实践)
RUN addgroup -g 1001 -S nodejs && \
adduser -S nodejs -u 1001
WORKDIR /app
# 从构建阶段复制产物
COPY --from=builder --chown=nodejs:nodejs /app/node_modules ./node_modules
COPY --from=builder --chown=nodejs:nodejs /app/dist ./dist
COPY --from=builder --chown=nodejs:nodejs /app/package*.json ./
COPY --from=builder --chown=nodejs:nodejs /app/prisma ./prisma
# 创建上传目录(用于临时文件)
RUN mkdir -p /app/uploads && chown -R nodejs:nodejs /app/uploads
# 切换到非 root 用户
USER nodejs
# 健康检查
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
CMD node -e "require('http').get('http://localhost:3001/health', (res) => { process.exit(res.statusCode === 200 ? 0 : 1); })"
# 暴露端口
EXPOSE 3001
# 🔥 启动命令(仅启动应用,不执行数据库迁移)
CMD ["node", "dist/index.js"]
附录B:.dockerignore完整内容
# Node.js
node_modules
npm-debug.log
yarn-error.log
# 开发文件
.env
.env.*
*.local
# 构建产物(改进方案B:使用本地编译好的dist)
# dist # 暂时注释掉,允许复制本地dist
# 测试文件
test
tests
*.test.ts
*.spec.ts
coverage
# 文档和临时文件
docs
*.md
.vscode
.idea
.DS_Store
Thumbs.db
# 上传文件(运行时生成)
uploads/*
# Git
.git
.gitignore
# 日志
*.log
logs
# 临时文件
temp
tmp
*.swp
*.swo
*~
# 数据库文件(SQLite,如果有)
*.db
*.sqlite
# 脚本文件(仅开发使用)
scripts/*.ts
*.bat
*.ps1
附录C:相关文档
文档维护者: AI Assistant
最后更新: 2024-12-24
版本: v1.0