Files
2026-05-17 11:58:37 +08:00

561 lines
13 KiB
Markdown

# 权益小助手 - CI/CD 流程规范
## 项目概述
- **项目名称**: 权益小助手 (QuanYiXiaoZhuShou)
- **项目类型**: 微信小程序 + Node.js 后端
- **当前版本**: v0.1.0
- **Git 仓库**: https://git.dxz99wyr.cn/Superuser/miniapp-api
## 项目结构
```
QuanYiXiaoZhuShou/
├── backend/ # Node.js 后端服务
│ ├── src/ # 源代码
│ ├── Dockerfile # Docker 构建文件
│ ├── docker-compose.yml # Docker Compose 配置
│ ├── nginx-api.conf # Nginx 反向代理配置
│ └── package.json # 依赖管理
├── miniapp/ # 微信小程序前端
│ ├── pages/ # 页面代码
│ ├── utils/ # 工具函数
│ └── app.js # 小程序入口
└── test/ # 测试相关
```
## 技术栈
### 后端 (Backend)
- **Runtime**: Node.js >= 18.0.0
- **Framework**: Express.js 4.18.2
- **Database**: MongoDB 7.0
- **Process Manager**: PM2
- **Container**: Docker + Docker Compose
- **Web Server**: Nginx (反向代理)
### 前端 (Miniapp)
- **Platform**: 微信小程序
- **Language**: JavaScript
- **Build Tool**: 微信开发者工具
### 服务器环境
- **OS**: Ubuntu/Debian (推测)
- **Server IP**: 8.136.137.59
- **Domain**: api-miniapp.dxz99wyr.cn
- **SSL**: 已配置
- **Deployment Path**: /var/www/quanyixiaozhushou-app
## 当前部署状态
### 服务器部署方式
当前使用 **Docker** 容器部署,包含两个容器:
| 容器名称 | 服务 | 端口 | 状态 |
|---------|------|------|------|
| `quanyixiaozhushou-app` | Node.js 后端 | 3000 | 运行中 |
| `quanyixiaozhushou-mongo` | MongoDB 7.0 | 27018 | 运行中 |
```bash
# 查看容器状态
docker ps
# 查看后端日志
docker logs quanyixiaozhushou-app
# 查看 MongoDB 日志
docker logs quanyixiaozhushou-mongo
```
### 环境变量 (生产环境)
```env
PORT=3000
NODE_ENV=production
WECHAT_APPID=wxa83262674846ca1a
WECHAT_APPSECRET=c40e9d356438f92d10091a115ee50172
MONGODB_URI=mongodb://localhost:27017/quanyixiaozhushou
JWT_SECRET=your_jwt_secret_key_here_change_in_production
JWT_EXPIRES_IN=7d
LOG_LEVEL=info
```
## CI/CD 流程设计
### 1. Git 工作流
```
[Developer] → feature branch → Pull Request → [Code Review] → merge to master → [CI/CD Pipeline] → Deploy
```
### 2. 分支策略
| 分支 | 用途 | 保护规则 |
|------|------|----------|
| master | 生产环境分支 | 禁止直接推送,需 PR |
| develop | 开发环境分支 | 需 PR |
| feature/* | 功能开发 | 自由推送 |
| hotfix/* | 紧急修复 | 需 PR 到 master |
### 3. CI/CD Pipeline 流程
```mermaid
graph TD
A[Git Push/PR] --> B[Checkout Code]
B --> C[Install Dependencies]
C --> D[Run Tests]
D --> E[Lint Check]
E --> F[Build Docker Image]
F --> G[Push to Registry]
G --> H[Deploy to Server]
H --> I[Health Check]
I --> J[Notify]
```
## 详细 CI/CD 配置
### Stage 1: 代码检出 (Checkout)
```yaml
# .github/workflows/ci-cd.yml
name: CI/CD Pipeline
on:
push:
branches: [ master, develop ]
pull_request:
branches: [ master ]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
repository: https://git.dxz99wyr.cn/Superuser/miniapp-api
token: ${{ secrets.GIT_ACCESS_TOKEN }}
```
### Stage 2: 依赖安装与测试
```yaml
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
cache: 'npm'
cache-dependency-path: backend/package-lock.json
- name: Install backend dependencies
working-directory: ./backend
run: npm ci
- name: Run backend tests
working-directory: ./backend
run: npm test
continue-on-error: true # 如果没有测试,不阻塞流程
- name: Run backend lint
working-directory: ./backend
run: npm run lint
continue-on-error: true
```
### Stage 3: Docker 构建
```yaml
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Docker Registry
uses: docker/login-action@v3
with:
registry: ghcr.io # 或你的私有仓库
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: ./backend
push: true
tags: |
ghcr.io/${{ github.repository }}/backend:${{ github.sha }}
ghcr.io/${{ github.repository }}/backend:latest
cache-from: type=gha
cache-to: type=gha,mode=max
```
### Stage 4: 部署到服务器
```yaml
- name: Deploy to server
uses: appleboy/ssh-action@v1.0.0
with:
host: 8.136.137.59
username: root
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
# 拉取最新镜像
docker pull ghcr.io/${{ github.repository }}/backend:latest
# 停止旧容器
docker stop quanyi-backend || true
docker rm quanyi-backend || true
# 启动新容器
docker run -d \
--name quanyi-backend \
--restart unless-stopped \
-p 3000:3000 \
-e PORT=3000 \
-e NODE_ENV=production \
-e WECHAT_APPID=${{ secrets.WECHAT_APPID }} \
-e WECHAT_APPSECRET=${{ secrets.WECHAT_APPSECRET }} \
-e MONGODB_URI=${{ secrets.MONGODB_URI }} \
-e JWT_SECRET=${{ secrets.JWT_SECRET }} \
-v /var/www/quanyixiaozhushou-app/public/uploads:/app/public/uploads \
ghcr.io/${{ github.repository }}/backend:latest
# 健康检查
sleep 10
curl -f http://localhost:3000/health || exit 1
```
## 环境变量配置
### GitHub Secrets 需要配置
| Secret Name | Description | Example |
|-------------|-------------|---------|
| `GIT_ACCESS_TOKEN` | Git 仓库访问令牌 | 用于拉取 `https://git.dxz99wyr.cn/Superuser/miniapp-api` |
| `SSH_PRIVATE_KEY` | 服务器 SSH 私钥 | `-----BEGIN OPENSSH PRIVATE KEY-----...` |
| `WECHAT_APPID` | 微信小程序 AppID | `wxa83262674846ca1a` |
| `WECHAT_APPSECRET` | 微信小程序 AppSecret | `c40e9d356438f92d10091a115ee50172` |
| `MONGODB_URI` | MongoDB 连接字符串 | `mongodb://localhost:27017/quanyixiaozhushou` |
| `JWT_SECRET` | JWT 密钥 | `your_jwt_secret_key` |
## 部署脚本 (服务器端)
### 1. 初始化脚本 (首次部署)
```bash
#!/bin/bash
# deploy-init.sh
set -e
PROJECT_DIR="/var/www/quanyixiaozhushou-app"
BACKUP_DIR="/var/backups/quanyixiaozhushou"
# 创建目录
mkdir -p $PROJECT_DIR
mkdir -p $BACKUP_DIR
mkdir -p $PROJECT_DIR/public/uploads
mkdir -p $PROJECT_DIR/public/avatars
# 安装 Docker (如果未安装)
if ! command -v docker &> /dev/null; then
curl -fsSL https://get.docker.com | sh
systemctl enable docker
systemctl start docker
fi
# 安装 Docker Compose
if ! command -v docker-compose &> /dev/null; then
curl -L "https://github.com/docker/compose/releases/download/v2.23.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
fi
echo "初始化完成"
```
### 2. 部署脚本 (日常更新)
```bash
#!/bin/bash
# deploy.sh
set -e
IMAGE_TAG=${1:-latest}
PROJECT_DIR="/var/www/quanyixiaozhushou-app"
BACKUP_DIR="/var/backups/quanyixiaozhushou"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
echo "=== 开始部署 ==="
echo "镜像标签: $IMAGE_TAG"
# 1. 备份当前数据
echo "[1/5] 备份当前数据..."
mkdir -p $BACKUP_DIR/$TIMESTAMP
cp -r $PROJECT_DIR/public/uploads $BACKUP_DIR/$TIMESTAMP/ 2>/dev/null || true
mongodump --db quanyixiaozhushou --out $BACKUP_DIR/$TIMESTAMP/ 2>/dev/null || true
# 2. 拉取最新镜像
echo "[2/5] 拉取最新镜像..."
docker pull ghcr.io/your-repo/quanyixiaozhushou-backend:$IMAGE_TAG
# 3. 停止旧容器
echo "[3/5] 停止旧容器..."
docker stop quanyi-backend 2>/dev/null || true
docker rm quanyi-backend 2>/dev/null || true
# 4. 启动新容器
echo "[4/5] 启动新容器..."
docker run -d \
--name quanyi-backend \
--restart unless-stopped \
-p 3000:3000 \
-e PORT=3000 \
-e NODE_ENV=production \
-e WECHAT_APPID=$WECHAT_APPID \
-e WECHAT_APPSECRET=$WECHAT_APPSECRET \
-e MONGODB_URI=$MONGODB_URI \
-e JWT_SECRET=$JWT_SECRET \
-v $PROJECT_DIR/public/uploads:/app/public/uploads \
-v $PROJECT_DIR/public/avatars:/app/public/avatars \
ghcr.io/your-repo/quanyixiaozhushou-backend:$IMAGE_TAG
# 5. 健康检查
echo "[5/5] 健康检查..."
sleep 5
MAX_RETRIES=10
RETRY_COUNT=0
while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do
if curl -f -s http://localhost:3000/health > /dev/null; then
echo "✅ 服务健康检查通过"
break
fi
RETRY_COUNT=$((RETRY_COUNT + 1))
echo "等待服务启动... ($RETRY_COUNT/$MAX_RETRIES)"
sleep 3
done
if [ $RETRY_COUNT -eq $MAX_RETRIES ]; then
echo "❌ 健康检查失败,执行回滚..."
# 回滚逻辑
docker stop quanyi-backend
docker rm quanyi-backend
# 启动上一个版本
exit 1
fi
# 清理旧镜像
docker image prune -f
echo "=== 部署完成 ==="
echo "备份位置: $BACKUP_DIR/$TIMESTAMP"
```
## 健康检查端点
确保后端有以下健康检查端点:
```javascript
// src/app.js
app.get('/health', (req, res) => {
res.status(200).json({
status: 'ok',
timestamp: new Date().toISOString(),
version: process.env.npm_package_version || '1.0.0'
});
});
```
## 微信小程序 CI/CD
### 自动上传脚本
```yaml
# .github/workflows/miniapp-deploy.yml
name: Miniapp Deploy
on:
push:
branches: [ master ]
paths:
- 'miniapp/**'
jobs:
deploy-miniapp:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
- name: Install miniprogram-ci
run: npm install -g miniprogram-ci
- name: Upload to WeChat
working-directory: ./miniapp
run: |
miniprogram-ci upload \
--pp ./ \
--pkp ${{ secrets.WECHAT_PRIVATE_KEY }} \
--appid ${{ secrets.WECHAT_APPID }} \
--uv ${{ github.run_number }} \
--enable-es6 true
```
## 监控与告警
### 1. 日志监控
```bash
# 查看实时日志
docker logs -f quanyi-backend
# 查看错误日志
docker logs quanyi-backend 2>&1 | grep ERROR
```
### 进程监控
```bash
# Docker 容器监控
docker stats quanyixiaozhushou-app
# 进入容器调试
docker exec -it quanyixiaozhushou-app sh
```
### 3. 告警规则
- 服务 5xx 错误率 > 1%
- 响应时间 > 2s
- 内存使用 > 80%
- CPU 使用 > 80%
- 磁盘使用 > 85%
## 回滚策略
### 自动回滚条件
- 健康检查失败
- 错误率突增
- 部署后 5 分钟内服务不可用
### 回滚脚本
```bash
#!/bin/bash
# rollback.sh
PREVIOUS_IMAGE=$(docker images --format "{{.Repository}}:{{.Tag}}" | grep quanyixiaozhushou-backend | head -2 | tail -1)
echo "回滚到上一个版本: $PREVIOUS_IMAGE"
docker stop quanyi-backend
docker rm quanyi-backend
docker run -d \
--name quanyi-backend \
--restart unless-stopped \
-p 3000:3000 \
-e PORT=3000 \
-e NODE_ENV=production \
-v /var/www/quanyixiaozhushou-app/public/uploads:/app/public/uploads \
$PREVIOUS_IMAGE
echo "回滚完成"
```
## 数据库迁移
### MongoDB 迁移脚本
```javascript
// migrations/001_add_subscription_type.js
const mongoose = require('mongoose');
async function migrate() {
await mongoose.connect(process.env.MONGODB_URI);
// 添加 type 字段到现有订阅记录
await mongoose.connection.collection('usersubscriptions').updateMany(
{ type: { $exists: false } },
{ $set: { type: 'version-update' } }
);
console.log('Migration completed');
process.exit(0);
}
migrate().catch(console.error);
```
## 安全检查清单
- [ ] 环境变量不提交到 Git
- [ ] 使用 secrets 管理敏感信息
- [ ] Docker 镜像使用非 root 用户运行
- [ ] 启用 HTTPS
- [ ] 配置防火墙规则
- [ ] 定期更新依赖
- [ ] 启用日志审计
- [ ] 配置备份策略
## 附录
### A. 常用命令
```bash
# 查看容器状态
docker ps
# 查看容器日志
docker logs quanyi-backend
# 进入容器
docker exec -it quanyi-backend sh
# 重启容器
docker restart quanyi-backend
# 查看资源使用
docker stats quanyi-backend
```
### B. 故障排查
```bash
# 服务无法启动
docker logs quanyi-backend
# MongoDB 连接失败
docker exec -it quanyi-backend node -e "require('mongoose').connect(process.env.MONGODB_URI).then(() => console.log('OK')).catch(e => console.error(e))"
# 端口占用
netstat -tlnp | grep 3000
```
### C. 联系方式与仓库信息
- **Git 仓库**: https://git.dxz99wyr.cn/Superuser/miniapp-api
- **服务器**: 8.136.137.59
- **域名**: api-miniapp.dxz99wyr.cn
- **SSH 密钥**: D:\003_Project\小程序连接.pem
### D. Git 仓库配置命令
```bash
# 添加远程仓库
git remote add origin https://git.dxz99wyr.cn/Superuser/miniapp-api
# 推送代码
git push -u origin master
# 拉取最新代码
git pull origin master
```