docs: 添加生产环境部署文档
- 01-production-deployment-plan.md: 部署方案 - 02-production-config.md: 生产配置 - 03-data-migration.md: 数据迁移方案 - 04-deployment-checklist.md: 上线检查清单 - docker-compose.prod.yml: Docker Compose配置 - .env.prod.example: 环境变量示例 - nginx/: Nginx配置 - scripts/: 部署脚本 - init-scripts/: 初始化脚本 提交时间: 2026-04-03 提交人: yunying
This commit is contained in:
179
README.md
Normal file
179
README.md
Normal file
@@ -0,0 +1,179 @@
|
||||
# PLM 系统生产环境部署包
|
||||
|
||||
## 📦 包内容说明
|
||||
|
||||
本部署包包含 PLM 系统生产环境部署所需的全部配置文件和文档。
|
||||
|
||||
---
|
||||
|
||||
## 📁 目录结构
|
||||
|
||||
```
|
||||
plm-production-deployment/
|
||||
├── 01-production-deployment-plan.md # 生产环境部署方案
|
||||
├── 02-production-config.md # 生产环境配置文档
|
||||
├── 03-data-migration.md # 数据迁移方案
|
||||
├── 04-deployment-checklist.md # 上线检查清单
|
||||
├── README.md # 本文件
|
||||
├── docker-compose.prod.yml # Docker Compose 生产配置
|
||||
├── .env.prod.example # 环境变量模板
|
||||
├── nginx/ # Nginx 配置
|
||||
│ ├── nginx.conf # Nginx 主配置
|
||||
│ ├── conf.d/
|
||||
│ │ └── production.conf # 站点配置
|
||||
│ ├── ssl/ # SSL 证书目录(需自行放置)
|
||||
│ └── html/ # 静态文件目录
|
||||
├── init-scripts/ # 数据库初始化脚本
|
||||
│ ├── 01-init-db.sql # 数据库初始化
|
||||
│ └── postgres-config.sql # PostgreSQL 优化配置
|
||||
├── scripts/ # 运维脚本
|
||||
│ └── backup.sh # 数据库备份脚本
|
||||
├── backups/ # 备份文件存储目录
|
||||
└── logs/ # 日志目录
|
||||
└── nginx/ # Nginx 日志
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚀 快速部署步骤
|
||||
|
||||
### 1. 准备服务器
|
||||
|
||||
- Ubuntu 20.04+ / CentOS 7+
|
||||
- Docker 20.10+
|
||||
- Docker Compose 2.0+
|
||||
- 4核8G+ 配置
|
||||
- 域名已解析到服务器
|
||||
|
||||
### 2. 上传部署包
|
||||
|
||||
```bash
|
||||
# 在服务器上创建目录
|
||||
mkdir -p /opt/plm-production
|
||||
cd /opt/plm-production
|
||||
|
||||
# 上传本部署包内容到该目录
|
||||
```
|
||||
|
||||
### 3. 配置环境变量
|
||||
|
||||
```bash
|
||||
# 复制环境变量模板
|
||||
cp .env.prod.example .env.prod
|
||||
|
||||
# 编辑 .env.prod,修改所有 CHANGE_THIS_ 开头的值
|
||||
nano .env.prod
|
||||
|
||||
# 设置文件权限
|
||||
chmod 600 .env.prod
|
||||
```
|
||||
|
||||
### 4. 配置 SSL 证书
|
||||
|
||||
```bash
|
||||
# 方式1:使用 Let's Encrypt
|
||||
certbot certonly --standalone -d aifly.ren -d www.aifly.ren
|
||||
|
||||
# 复制证书到 nginx/ssl 目录
|
||||
cp /etc/letsencrypt/live/aifly.ren/fullchain.pem nginx/ssl/aifly.ren.crt
|
||||
cp /etc/letsencrypt/live/aifly.ren/privkey.pem nginx/ssl/aifly.ren.key
|
||||
|
||||
# 方式2:使用自有证书
|
||||
# 直接将证书文件放入 nginx/ssl/ 目录
|
||||
```
|
||||
|
||||
### 5. 启动服务
|
||||
|
||||
```bash
|
||||
# 加载环境变量
|
||||
source .env.prod
|
||||
|
||||
# 启动基础设施(数据库、缓存)
|
||||
docker-compose -f docker-compose.prod.yml up -d postgres redis
|
||||
|
||||
# 等待数据库就绪(约30秒)
|
||||
sleep 30
|
||||
|
||||
# 初始化数据库(首次部署)
|
||||
docker-compose -f docker-compose.prod.yml run --rm backend python -m app.init_db
|
||||
|
||||
# 启动所有服务
|
||||
docker-compose -f docker-compose.prod.yml up -d
|
||||
|
||||
# 检查状态
|
||||
docker-compose -f docker-compose.prod.yml ps
|
||||
```
|
||||
|
||||
### 6. 验证部署
|
||||
|
||||
```bash
|
||||
# 健康检查
|
||||
curl https://aifly.ren/health
|
||||
|
||||
# 查看日志
|
||||
docker-compose -f docker-compose.prod.yml logs -f
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📋 重要文档索引
|
||||
|
||||
| 文档 | 用途 | 阅读时机 |
|
||||
|------|------|----------|
|
||||
| [01-production-deployment-plan.md](01-production-deployment-plan.md) | 部署方案、架构设计 | 部署前 |
|
||||
| [02-production-config.md](02-production-config.md) | 详细配置说明 | 配置时 |
|
||||
| [03-data-migration.md](03-data-migration.md) | 数据迁移步骤 | 迁移时 |
|
||||
| [04-deployment-checklist.md](04-deployment-checklist.md) | 上线检查清单 | 上线前 |
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ 安全注意事项
|
||||
|
||||
1. **环境变量**:`.env.prod` 包含敏感信息,务必设置 600 权限
|
||||
2. **SSL 证书**:生产环境必须启用 HTTPS
|
||||
3. **密码策略**:所有密码使用强密码,定期轮换
|
||||
4. **防火墙**:仅开放 80/443/22 端口
|
||||
5. **备份**:定期检查备份是否正常运行
|
||||
|
||||
---
|
||||
|
||||
## 🔧 常用运维命令
|
||||
|
||||
```bash
|
||||
# 查看服务状态
|
||||
docker-compose -f docker-compose.prod.yml ps
|
||||
|
||||
# 查看日志
|
||||
docker-compose -f docker-compose.prod.yml logs -f [service-name]
|
||||
|
||||
# 重启服务
|
||||
docker-compose -f docker-compose.prod.yml restart [service-name]
|
||||
|
||||
# 停止服务
|
||||
docker-compose -f docker-compose.prod.yml down
|
||||
|
||||
# 更新部署
|
||||
docker-compose -f docker-compose.prod.yml pull
|
||||
docker-compose -f docker-compose.prod.yml up -d
|
||||
|
||||
# 手动备份
|
||||
docker-compose -f docker-compose.prod.yml exec backup /backup.sh
|
||||
|
||||
# 进入数据库
|
||||
docker-compose -f docker-compose.prod.yml exec postgres psql -U plm_prod -d plm_production
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📞 技术支持
|
||||
|
||||
- **部署问题**:查看 `01-production-deployment-plan.md`
|
||||
- **配置问题**:查看 `02-production-config.md`
|
||||
- **迁移问题**:查看 `03-data-migration.md`
|
||||
- **上线检查**:查看 `04-deployment-checklist.md`
|
||||
|
||||
---
|
||||
|
||||
**版本**: 1.0.0
|
||||
**更新日期**: 2026-04-03
|
||||
**维护团队**: 运维团队
|
||||
91
docs/deployment/.env.prod.example
Normal file
91
docs/deployment/.env.prod.example
Normal file
@@ -0,0 +1,91 @@
|
||||
# ============================================
|
||||
# PLM System Production Environment Variables
|
||||
# ============================================
|
||||
# 使用说明:
|
||||
# 1. 复制此文件为 .env.prod
|
||||
# 2. 修改所有 CHANGE_THIS_ 开头的值为实际值
|
||||
# 3. 确保文件权限:chmod 600 .env.prod
|
||||
# ============================================
|
||||
|
||||
# Application
|
||||
APP_NAME=PLM System
|
||||
APP_VERSION=1.0.0
|
||||
DEBUG=false
|
||||
ENVIRONMENT=production
|
||||
|
||||
# Server
|
||||
HOST=0.0.0.0
|
||||
PORT=8000
|
||||
WORKERS=4
|
||||
|
||||
# ============================================
|
||||
# Database - PostgreSQL (Production)
|
||||
# ============================================
|
||||
# 注意:生产环境使用强密码,定期轮换
|
||||
# 生成强密码:openssl rand -base64 24
|
||||
POSTGRES_USER=plm_prod
|
||||
POSTGRES_PASSWORD=CHANGE_THIS_TO_STRONG_PASSWORD
|
||||
POSTGRES_DB=plm_production
|
||||
DATABASE_URL=postgresql+asyncpg://plm_prod:CHANGE_THIS_TO_STRONG_PASSWORD@postgres:5432/plm_production
|
||||
DATABASE_SYNC_URL=postgresql://plm_prod:CHANGE_THIS_TO_STRONG_PASSWORD@postgres:5432/plm_production
|
||||
DB_POOL_SIZE=20
|
||||
DB_MAX_OVERFLOW=30
|
||||
|
||||
# ============================================
|
||||
# Redis Cache (Production)
|
||||
# ============================================
|
||||
# 生产环境建议启用密码认证
|
||||
# 生成强密码:openssl rand -base64 24
|
||||
REDIS_PASSWORD=CHANGE_REDIS_PASSWORD
|
||||
REDIS_URL=redis://:CHANGE_REDIS_PASSWORD@redis:6379/0
|
||||
|
||||
# ============================================
|
||||
# JWT Authentication (Production)
|
||||
# ============================================
|
||||
# 重要:生产环境必须使用强随机密钥!
|
||||
# 生成命令:openssl rand -base64 32
|
||||
JWT_SECRET_KEY=CHANGE_THIS_TO_32_BYTE_RANDOM_KEY
|
||||
JWT_ALGORITHM=HS256
|
||||
JWT_ACCESS_TOKEN_EXPIRE_MINUTES=30
|
||||
JWT_REFRESH_TOKEN_EXPIRE_DAYS=7
|
||||
|
||||
# ============================================
|
||||
# CORS Configuration
|
||||
# ============================================
|
||||
CORS_ORIGINS=["https://aifly.ren","https://www.aifly.ren"]
|
||||
|
||||
# ============================================
|
||||
# Domain
|
||||
# ============================================
|
||||
DOMAIN=aifly.ren
|
||||
|
||||
# ============================================
|
||||
# Security Settings
|
||||
# ============================================
|
||||
PASSWORD_MIN_LENGTH=8
|
||||
PASSWORD_REQUIRE_UPPERCASE=true
|
||||
PASSWORD_REQUIRE_LOWERCASE=true
|
||||
PASSWORD_REQUIRE_DIGIT=true
|
||||
PASSWORD_REQUIRE_SPECIAL=true
|
||||
|
||||
# Rate Limiting
|
||||
RATE_LIMIT_REQUESTS=100
|
||||
RATE_LIMIT_PERIOD_SECONDS=60
|
||||
|
||||
# ============================================
|
||||
# File Upload (Production)
|
||||
# ============================================
|
||||
UPLOAD_DIR=/app/uploads
|
||||
MAX_UPLOAD_SIZE=10485760
|
||||
|
||||
# ============================================
|
||||
# Logging
|
||||
# ============================================
|
||||
LOG_LEVEL=INFO
|
||||
LOG_FORMAT=json
|
||||
|
||||
# ============================================
|
||||
# Image Versions
|
||||
# ============================================
|
||||
BACKEND_VERSION=latest
|
||||
FRONTEND_VERSION=latest
|
||||
267
docs/deployment/01-production-deployment-plan.md
Normal file
267
docs/deployment/01-production-deployment-plan.md
Normal file
@@ -0,0 +1,267 @@
|
||||
# PLM 系统生产环境部署方案
|
||||
|
||||
## 📋 文档信息
|
||||
|
||||
- **文档版本**: 1.0.0
|
||||
- **创建时间**: 2026-04-03
|
||||
- **目标环境**: 生产环境 (Production)
|
||||
- **域名**: aifly.ren
|
||||
|
||||
---
|
||||
|
||||
## 一、部署架构选择
|
||||
|
||||
### 1.1 推荐方案:Docker Compose(单节点)
|
||||
|
||||
考虑到当前系统规模和运维复杂度,**推荐使用 Docker Compose 单节点部署方案**。
|
||||
|
||||
| 对比项 | Docker Compose | Kubernetes |
|
||||
|--------|----------------|------------|
|
||||
| 部署复杂度 | ⭐ 简单 | ⭐⭐⭐⭐ 复杂 |
|
||||
| 运维成本 | 低 | 高 |
|
||||
| 扩展性 | 垂直扩展 | 水平扩展 |
|
||||
| 高可用 | 需额外配置 | 原生支持 |
|
||||
| 学习成本 | 低 | 高 |
|
||||
| 资源占用 | 低 | 高 |
|
||||
|
||||
**选择理由**:
|
||||
1. 当前用户量可控,单节点性能充足
|
||||
2. 快速上线,降低部署风险
|
||||
3. 运维简单,便于后期迭代
|
||||
4. 未来可根据业务增长平滑迁移到 K8s
|
||||
|
||||
### 1.2 系统架构图
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 用户访问层 │
|
||||
│ (浏览器 / 移动设备) │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Nginx 反向代理 │
|
||||
│ (SSL 终端、负载均衡、静态资源) │
|
||||
│ 端口: 80, 443 │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
┌─────────────────┴─────────────────┐
|
||||
▼ ▼
|
||||
┌───────────────────────┐ ┌───────────────────────┐
|
||||
│ PLM Frontend │ │ PLM Backend │
|
||||
│ (Next.js/Nginx) │ │ (FastAPI) │
|
||||
│ 端口: 3000 │ │ 端口: 8000 │
|
||||
└───────────────────────┘ └───────────────────────┘
|
||||
│
|
||||
┌─────────────────┬───────────────┘
|
||||
▼ ▼
|
||||
┌──────────────────┐ ┌──────────────────┐
|
||||
│ PostgreSQL │ │ Redis │
|
||||
│ (主数据库) │ │ (缓存/会话) │
|
||||
│ 端口: 5432 │ │ 端口: 6379 │
|
||||
└──────────────────┘ └──────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 二、服务器规格建议
|
||||
|
||||
### 2.1 最低配置
|
||||
|
||||
| 组件 | 规格 |
|
||||
|------|------|
|
||||
| CPU | 4 核 |
|
||||
| 内存 | 8 GB |
|
||||
| 磁盘 | 100 GB SSD |
|
||||
| 带宽 | 10 Mbps |
|
||||
|
||||
### 2.2 推荐配置
|
||||
|
||||
| 组件 | 规格 |
|
||||
|------|------|
|
||||
| CPU | 8 核 |
|
||||
| 内存 | 16 GB |
|
||||
| 磁盘 | 200 GB SSD |
|
||||
| 带宽 | 50 Mbps |
|
||||
|
||||
### 2.3 资源分配
|
||||
|
||||
| 服务 | CPU | 内存 | 说明 |
|
||||
|------|-----|------|------|
|
||||
| Nginx | 0.5 核 | 256 MB | 反向代理 |
|
||||
| Backend | 2 核 | 2 GB | FastAPI 应用 |
|
||||
| Frontend | 0.5 核 | 512 MB | Next.js/静态页面 |
|
||||
| PostgreSQL | 2 核 | 4 GB | 主数据库 |
|
||||
| Redis | 0.5 核 | 512 MB | 缓存服务 |
|
||||
| 系统预留 | 2.5 核 | 8.7 GB | 操作系统/缓冲 |
|
||||
|
||||
---
|
||||
|
||||
## 三、部署步骤
|
||||
|
||||
### 3.1 前置准备
|
||||
|
||||
```bash
|
||||
# 1. 更新系统
|
||||
sudo apt update && sudo apt upgrade -y
|
||||
|
||||
# 2. 安装 Docker
|
||||
sudo apt install -y docker.io docker-compose-plugin
|
||||
|
||||
# 3. 配置 Docker 开机启动
|
||||
sudo systemctl enable docker
|
||||
sudo systemctl start docker
|
||||
|
||||
# 4. 创建部署目录
|
||||
mkdir -p /opt/plm-production
|
||||
cd /opt/plm-production
|
||||
|
||||
# 5. 创建数据目录
|
||||
mkdir -p data/postgres data/redis data/backups data/uploads
|
||||
chmod 755 data/postgres data/redis
|
||||
```
|
||||
|
||||
### 3.2 部署文件清单
|
||||
|
||||
| 文件 | 用途 | 来源 |
|
||||
|------|------|------|
|
||||
| `docker-compose.prod.yml` | 生产环境编排 | 新建 |
|
||||
| `.env.prod` | 生产环境变量 | 新建 |
|
||||
| `nginx/nginx.conf` | Nginx 主配置 | 复制修改 |
|
||||
| `nginx/conf.d/prod.conf` | 站点配置 | 复制修改 |
|
||||
| `nginx/ssl/` | SSL 证书目录 | 新建 |
|
||||
| `init-scripts/` | 数据库初始化 | 可选 |
|
||||
|
||||
### 3.3 启动命令
|
||||
|
||||
```bash
|
||||
# 1. 加载环境变量
|
||||
source .env.prod
|
||||
|
||||
# 2. 启动服务
|
||||
docker-compose -f docker-compose.prod.yml up -d
|
||||
|
||||
# 3. 检查状态
|
||||
docker-compose -f docker-compose.prod.yml ps
|
||||
|
||||
# 4. 查看日志
|
||||
docker-compose -f docker-compose.prod.yml logs -f
|
||||
|
||||
# 5. 初始化数据库(首次部署)
|
||||
docker-compose -f docker-compose.prod.yml exec backend python -m app.init_db
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 四、高可用与扩展方案
|
||||
|
||||
### 4.1 单节点高可用
|
||||
|
||||
- 使用 Docker Restart Policy: `unless-stopped`
|
||||
- 配置健康检查自动重启
|
||||
- 使用 Supervisor 或 systemd 管理 Docker 服务
|
||||
|
||||
### 4.2 未来扩展路径
|
||||
|
||||
```
|
||||
阶段1: 单节点 Docker Compose (当前)
|
||||
↓
|
||||
阶段2: 多节点 Docker Swarm
|
||||
↓
|
||||
阶段3: Kubernetes 集群
|
||||
```
|
||||
|
||||
### 4.3 水平扩展准备
|
||||
|
||||
- 应用层:无状态设计,支持多实例
|
||||
- 数据库:预留主从复制配置
|
||||
- 缓存:Redis Cluster 预留
|
||||
- 文件存储:使用对象存储(OSS/S3)
|
||||
|
||||
---
|
||||
|
||||
## 五、安全加固
|
||||
|
||||
### 5.1 网络安全
|
||||
|
||||
- 配置防火墙(UFW/iptables)
|
||||
- 仅开放必要端口:80, 443, 22(SSH)
|
||||
- 使用 fail2ban 防止暴力破解
|
||||
|
||||
### 5.2 应用安全
|
||||
|
||||
- 强制 HTTPS
|
||||
- JWT Secret 定期轮换
|
||||
- 数据库密码复杂度要求
|
||||
- API 限流保护
|
||||
|
||||
### 5.3 数据安全
|
||||
|
||||
- 定期备份策略
|
||||
- 敏感数据加密存储
|
||||
- 访问日志审计
|
||||
|
||||
---
|
||||
|
||||
## 六、监控与告警
|
||||
|
||||
### 6.1 基础监控
|
||||
|
||||
```bash
|
||||
# 容器资源使用
|
||||
docker stats
|
||||
|
||||
# 系统资源
|
||||
top / htop
|
||||
|
||||
# 磁盘使用
|
||||
df -h
|
||||
du -sh /opt/plm-production/data/*
|
||||
```
|
||||
|
||||
### 6.2 推荐监控工具
|
||||
|
||||
- **Prometheus + Grafana**: 指标监控
|
||||
- **ELK Stack**: 日志收集分析
|
||||
- **Uptime Kuma**: 服务可用性监控
|
||||
|
||||
---
|
||||
|
||||
## 七、回滚策略
|
||||
|
||||
### 7.1 版本控制
|
||||
|
||||
```bash
|
||||
# 标记版本
|
||||
docker tag plm-backend:latest plm-backend:v1.0.0
|
||||
|
||||
# 备份当前配置
|
||||
cp docker-compose.prod.yml docker-compose.prod.yml.backup.$(date +%Y%m%d)
|
||||
```
|
||||
|
||||
### 7.2 快速回滚
|
||||
|
||||
```bash
|
||||
# 回滚到上一版本
|
||||
docker-compose -f docker-compose.prod.yml down
|
||||
docker-compose -f docker-compose.prod.yml up -d --build
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 八、验收标准
|
||||
|
||||
- [ ] 所有服务正常启动无报错
|
||||
- [ ] 健康检查接口返回正常
|
||||
- [ ] 数据库连接正常
|
||||
- [ ] 缓存服务正常
|
||||
- [ ] 外部访问域名正常
|
||||
- [ ] SSL 证书配置正确
|
||||
- [ ] 日志记录正常
|
||||
- [ ] 备份策略已配置
|
||||
|
||||
---
|
||||
|
||||
**文档维护**: 运维团队
|
||||
**审核**: CTO/架构师
|
||||
**生效日期**: 2026-04-03
|
||||
540
docs/deployment/02-production-config.md
Normal file
540
docs/deployment/02-production-config.md
Normal file
@@ -0,0 +1,540 @@
|
||||
# PLM 系统生产环境配置文档
|
||||
|
||||
## 📋 文档信息
|
||||
|
||||
- **文档版本**: 1.0.0
|
||||
- **环境**: Production
|
||||
- **域名**: aifly.ren
|
||||
|
||||
---
|
||||
|
||||
## 一、环境变量配置 (.env.prod)
|
||||
|
||||
```bash
|
||||
# ============================================
|
||||
# PLM System Production Environment Variables
|
||||
# ============================================
|
||||
|
||||
# Application
|
||||
APP_NAME=PLM System
|
||||
APP_VERSION=1.0.0
|
||||
DEBUG=false
|
||||
ENVIRONMENT=production
|
||||
|
||||
# Server
|
||||
HOST=0.0.0.0
|
||||
PORT=8000
|
||||
WORKERS=4
|
||||
|
||||
# ============================================
|
||||
# Database - PostgreSQL (Production)
|
||||
# ============================================
|
||||
# 注意:生产环境使用强密码,定期轮换
|
||||
DATABASE_URL=postgresql+asyncpg://plm_prod:CHANGE_THIS_TO_STRONG_PASSWORD@postgres:5432/plm_production
|
||||
DATABASE_SYNC_URL=postgresql://plm_prod:CHANGE_THIS_TO_STRONG_PASSWORD@postgres:5432/plm_production
|
||||
DB_POOL_SIZE=20
|
||||
DB_MAX_OVERFLOW=30
|
||||
|
||||
# ============================================
|
||||
# Redis Cache (Production)
|
||||
# ============================================
|
||||
# 生产环境建议启用密码认证
|
||||
REDIS_URL=redis://:CHANGE_REDIS_PASSWORD@redis:6379/0
|
||||
REDIS_PASSWORD=CHANGE_REDIS_PASSWORD
|
||||
|
||||
# ============================================
|
||||
# JWT Authentication (Production)
|
||||
# ============================================
|
||||
# 重要:生产环境必须使用强随机密钥!
|
||||
# 生成命令: openssl rand -base64 32
|
||||
JWT_SECRET_KEY=CHANGE_THIS_TO_32_BYTE_RANDOM_KEY
|
||||
JWT_ALGORITHM=HS256
|
||||
JWT_ACCESS_TOKEN_EXPIRE_MINUTES=30
|
||||
JWT_REFRESH_TOKEN_EXPIRE_DAYS=7
|
||||
|
||||
# ============================================
|
||||
# CORS Configuration
|
||||
# ============================================
|
||||
CORS_ORIGINS=["https://aifly.ren","https://www.aifly.ren"]
|
||||
|
||||
# ============================================
|
||||
# Domain
|
||||
# ============================================
|
||||
DOMAIN=aifly.ren
|
||||
|
||||
# ============================================
|
||||
# Security Settings
|
||||
# ============================================
|
||||
PASSWORD_MIN_LENGTH=8
|
||||
PASSWORD_REQUIRE_UPPERCASE=true
|
||||
PASSWORD_REQUIRE_LOWERCASE=true
|
||||
PASSWORD_REQUIRE_DIGIT=true
|
||||
PASSWORD_REQUIRE_SPECIAL=true
|
||||
|
||||
# Rate Limiting
|
||||
RATE_LIMIT_REQUESTS=100
|
||||
RATE_LIMIT_PERIOD_SECONDS=60
|
||||
|
||||
# ============================================
|
||||
# File Upload (Production)
|
||||
# ============================================
|
||||
# 文件上传路径(容器内)
|
||||
UPLOAD_DIR=/app/uploads
|
||||
MAX_UPLOAD_SIZE=10485760
|
||||
|
||||
# ============================================
|
||||
# Logging
|
||||
# ============================================
|
||||
LOG_LEVEL=INFO
|
||||
LOG_FORMAT=json
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 二、Docker Compose 配置 (docker-compose.prod.yml)
|
||||
|
||||
```yaml
|
||||
# PLM Production Environment Docker Compose
|
||||
# 生产环境部署配置
|
||||
# 域名: https://aifly.ren
|
||||
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
# ============================================
|
||||
# PostgreSQL 14 Database (Production)
|
||||
# ============================================
|
||||
postgres:
|
||||
image: postgres:14-alpine
|
||||
container_name: plm-prod-postgres
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
POSTGRES_USER: ${POSTGRES_USER:-plm_prod}
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-CHANGE_THIS_PASSWORD}
|
||||
POSTGRES_DB: ${POSTGRES_DB:-plm_production}
|
||||
PGDATA: /var/lib/postgresql/data/pgdata
|
||||
# 性能优化
|
||||
POSTGRES_INITDB_ARGS: "--encoding=UTF8 --locale=en_US.UTF-8"
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
- ./backups:/backups
|
||||
- ./init-scripts:/docker-entrypoint-initdb.d
|
||||
# 生产环境不暴露端口,仅内部网络访问
|
||||
networks:
|
||||
- plm-prod-network
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-plm_prod} -d ${POSTGRES_DB:-plm_production}"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 30s
|
||||
# 资源限制
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '2.0'
|
||||
memory: 4G
|
||||
reservations:
|
||||
cpus: '1.0'
|
||||
memory: 2G
|
||||
|
||||
# ============================================
|
||||
# Redis 7 Cache (Production)
|
||||
# ============================================
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
container_name: plm-prod-redis
|
||||
restart: unless-stopped
|
||||
command: >
|
||||
redis-server
|
||||
--appendonly yes
|
||||
--requirepass ${REDIS_PASSWORD:-CHANGE_REDIS_PASSWORD}
|
||||
--maxmemory 512mb
|
||||
--maxmemory-policy allkeys-lru
|
||||
volumes:
|
||||
- redis_data:/data
|
||||
# 生产环境不暴露端口,仅内部网络访问
|
||||
networks:
|
||||
- plm-prod-network
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD:-CHANGE_REDIS_PASSWORD}", "ping"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '0.5'
|
||||
memory: 512M
|
||||
reservations:
|
||||
cpus: '0.25'
|
||||
memory: 256M
|
||||
|
||||
# ============================================
|
||||
# PLM Backend Service (Production)
|
||||
# ============================================
|
||||
backend:
|
||||
image: plm-backend:${BACKEND_VERSION:-latest}
|
||||
container_name: plm-prod-backend
|
||||
restart: unless-stopped
|
||||
env_file:
|
||||
- .env.prod
|
||||
environment:
|
||||
# 覆盖开发环境配置
|
||||
DEBUG: "false"
|
||||
ENVIRONMENT: "production"
|
||||
WORKERS: "4"
|
||||
# 数据库连接(使用服务名)
|
||||
DATABASE_URL: postgresql+asyncpg://${POSTGRES_USER:-plm_prod}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-plm_production}
|
||||
DATABASE_SYNC_URL: postgresql://${POSTGRES_USER:-plm_prod}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-plm_production}
|
||||
# Redis 连接
|
||||
REDIS_URL: redis://:${REDIS_PASSWORD}@redis:6379/0
|
||||
volumes:
|
||||
- uploads_data:/app/uploads
|
||||
- ./logs:/app/logs
|
||||
networks:
|
||||
- plm-prod-network
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 60s
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '2.0'
|
||||
memory: 2G
|
||||
reservations:
|
||||
cpus: '1.0'
|
||||
memory: 1G
|
||||
|
||||
# ============================================
|
||||
# PLM Frontend Service (Production)
|
||||
# ============================================
|
||||
frontend:
|
||||
image: plm-frontend:${FRONTEND_VERSION:-latest}
|
||||
container_name: plm-prod-frontend
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- plm-prod-network
|
||||
depends_on:
|
||||
- backend
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '0.5'
|
||||
memory: 512M
|
||||
reservations:
|
||||
cpus: '0.25'
|
||||
memory: 256M
|
||||
|
||||
# ============================================
|
||||
# Nginx Reverse Proxy (Production)
|
||||
# ============================================
|
||||
nginx:
|
||||
image: nginx:alpine
|
||||
container_name: plm-prod-nginx
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
volumes:
|
||||
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
|
||||
- ./nginx/conf.d:/etc/nginx/conf.d:ro
|
||||
- ./nginx/ssl:/etc/nginx/ssl:ro
|
||||
- ./nginx/html:/usr/share/nginx/html:ro
|
||||
- ./logs/nginx:/var/log/nginx
|
||||
networks:
|
||||
- plm-prod-network
|
||||
depends_on:
|
||||
- backend
|
||||
- frontend
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost/health"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '0.5'
|
||||
memory: 256M
|
||||
reservations:
|
||||
cpus: '0.25'
|
||||
memory: 128M
|
||||
|
||||
# ============================================
|
||||
# Database Backup Service (Production)
|
||||
# ============================================
|
||||
backup:
|
||||
image: postgres:14-alpine
|
||||
container_name: plm-prod-backup
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
POSTGRES_USER: ${POSTGRES_USER:-plm_prod}
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
||||
POSTGRES_DB: ${POSTGRES_DB:-plm_production}
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data:ro
|
||||
- ./backups:/backups
|
||||
- ./scripts/backup.sh:/backup.sh:ro
|
||||
command: >
|
||||
sh -c "echo '0 2 * * * /backup.sh' | crontab - && crond -f"
|
||||
networks:
|
||||
- plm-prod-network
|
||||
depends_on:
|
||||
- postgres
|
||||
|
||||
networks:
|
||||
plm-prod-network:
|
||||
driver: bridge
|
||||
ipam:
|
||||
config:
|
||||
- subnet: 172.20.0.0/16
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
driver: local
|
||||
redis_data:
|
||||
driver: local
|
||||
uploads_data:
|
||||
driver: local
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 三、Nginx 生产配置
|
||||
|
||||
### 3.1 nginx.conf (主配置)
|
||||
|
||||
```nginx
|
||||
user nginx;
|
||||
worker_processes auto;
|
||||
error_log /var/log/nginx/error.log warn;
|
||||
pid /var/run/nginx.pid;
|
||||
|
||||
events {
|
||||
worker_connections 2048;
|
||||
use epoll;
|
||||
multi_accept on;
|
||||
}
|
||||
|
||||
http {
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
# Logging
|
||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" "$http_x_forwarded_for" '
|
||||
'$request_time $upstream_response_time';
|
||||
access_log /var/log/nginx/access.log main;
|
||||
|
||||
# Performance
|
||||
sendfile on;
|
||||
tcp_nopush on;
|
||||
tcp_nodelay on;
|
||||
keepalive_timeout 65;
|
||||
types_hash_max_size 2048;
|
||||
client_max_body_size 50M;
|
||||
|
||||
# Gzip
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
gzip_proxied any;
|
||||
gzip_comp_level 6;
|
||||
gzip_types text/plain text/css text/xml application/json
|
||||
application/javascript application/rss+xml
|
||||
application/atom+xml image/svg+xml;
|
||||
|
||||
# Rate limiting
|
||||
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
|
||||
limit_req_zone $binary_remote_addr zone=login:10m rate=1r/m;
|
||||
|
||||
# Include server configs
|
||||
include /etc/nginx/conf.d/*.conf;
|
||||
}
|
||||
```
|
||||
|
||||
### 3.2 conf.d/production.conf (站点配置)
|
||||
|
||||
```nginx
|
||||
# PLM System Production - aifly.ren
|
||||
# 生产环境 Nginx 配置
|
||||
|
||||
upstream plm_backend {
|
||||
server backend:8000;
|
||||
keepalive 64;
|
||||
}
|
||||
|
||||
upstream plm_frontend {
|
||||
server frontend:3000;
|
||||
keepalive 32;
|
||||
}
|
||||
|
||||
# HTTP Server - Redirect to HTTPS
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name aifly.ren www.aifly.ren;
|
||||
|
||||
# ACME challenge for Let's Encrypt
|
||||
location /.well-known/acme-challenge/ {
|
||||
root /var/www/certbot;
|
||||
}
|
||||
|
||||
# Redirect all HTTP to HTTPS
|
||||
location / {
|
||||
return 301 https://$server_name$request_uri;
|
||||
}
|
||||
}
|
||||
|
||||
# HTTPS Server
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
listen [::]:443 ssl http2;
|
||||
server_name aifly.ren www.aifly.ren;
|
||||
|
||||
# SSL Certificate (Let's Encrypt)
|
||||
ssl_certificate /etc/nginx/ssl/aifly.ren.crt;
|
||||
ssl_certificate_key /etc/nginx/ssl/aifly.ren.key;
|
||||
|
||||
# SSL Configuration
|
||||
ssl_session_timeout 1d;
|
||||
ssl_session_cache shared:SSL:50m;
|
||||
ssl_session_tickets off;
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
|
||||
ssl_prefer_server_ciphers off;
|
||||
|
||||
# Security Headers
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
||||
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:;" always;
|
||||
|
||||
# Health check endpoint
|
||||
location /health {
|
||||
access_log off;
|
||||
return 200 "healthy\n";
|
||||
add_header Content-Type text/plain;
|
||||
}
|
||||
|
||||
# API proxy with rate limiting
|
||||
location /api/ {
|
||||
limit_req zone=api burst=20 nodelay;
|
||||
|
||||
proxy_pass http://plm_backend;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection 'upgrade';
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
proxy_read_timeout 86400;
|
||||
proxy_buffering off;
|
||||
}
|
||||
|
||||
# Auth endpoints - stricter rate limit
|
||||
location /api/auth/login {
|
||||
limit_req zone=login burst=5 nodelay;
|
||||
|
||||
proxy_pass http://plm_backend;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
# Frontend static files
|
||||
location / {
|
||||
proxy_pass http://plm_frontend;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection 'upgrade';
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
}
|
||||
|
||||
# Static assets caching
|
||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
||||
proxy_pass http://plm_frontend;
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 四、数据库配置优化
|
||||
|
||||
### 4.1 PostgreSQL 性能优化参数
|
||||
|
||||
创建 `init-scripts/postgres-config.sql`:
|
||||
|
||||
```sql
|
||||
-- PostgreSQL Production Configuration
|
||||
-- 适用于 4GB+ 内存的服务器
|
||||
|
||||
-- 连接配置
|
||||
ALTER SYSTEM SET max_connections = '200';
|
||||
ALTER SYSTEM SET shared_buffers = '1GB';
|
||||
ALTER SYSTEM SET effective_cache_size = '3GB';
|
||||
ALTER SYSTEM SET maintenance_work_mem = '256MB';
|
||||
ALTER SYSTEM SET work_mem = '10MB';
|
||||
|
||||
-- WAL 配置
|
||||
ALTER SYSTEM SET wal_buffers = '16MB';
|
||||
ALTER SYSTEM SET checkpoint_completion_target = '0.9';
|
||||
ALTER SYSTEM SET random_page_cost = '1.1';
|
||||
ALTER SYSTEM SET effective_io_concurrency = '200';
|
||||
|
||||
-- 查询优化
|
||||
ALTER SYSTEM SET default_statistics_target = '100';
|
||||
ALTER SYSTEM SET seq_page_cost = '1.0';
|
||||
|
||||
-- 日志配置
|
||||
ALTER SYSTEM SET log_duration = 'on';
|
||||
ALTER SYSTEM SET log_min_duration_statement = '1000';
|
||||
ALTER SYSTEM SET log_checkpoints = 'on';
|
||||
ALTER SYSTEM SET log_connections = 'on';
|
||||
ALTER SYSTEM SET log_disconnections = 'on';
|
||||
ALTER SYSTEM SET log_lock_waits = 'on';
|
||||
|
||||
-- 应用配置
|
||||
SELECT pg_reload_conf();
|
||||
```
|
||||
|
||||
### 4.2 数据库初始化脚本
|
||||
|
||||
创建 `init-scripts/01-init-db.sql`:
|
||||
|
||||
```sql
|
||||
-- 创建生产数据库
|
||||
CREATE DATABASE plm_production WITH ENCODING = 'UTF8';
|
||||
|
||||
-- 创建应用用户(使用强密码)
|
||||
-- 注意:实际密码在环境变量中设置
|
||||
-- CREATE USER plm_prod WITH PASSWORD 'STRONG_PASSWORD_HERE';
|
||||
|
||||
-- 授权
|
||||
-- GRANT ALL PRIVILEGES ON DATABASE plm_production TO plm_prod;
|
||||
|
||||
-- 创建扩展
|
||||
\c plm_production;
|
||||
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
||||
CREATE EXTENSION IF NOT EXISTS
|
||||
348
docs/deployment/03-data-migration.md
Normal file
348
docs/deployment/03-data-migration.md
Normal file
@@ -0,0 +1,348 @@
|
||||
# PLM 系统数据迁移方案
|
||||
|
||||
## 📋 文档信息
|
||||
|
||||
- **文档版本**: 1.0.0
|
||||
- **源环境**: 测试环境 (docker-compose.test.yml)
|
||||
- **目标环境**: 生产环境 (docker-compose.prod.yml)
|
||||
- **迁移时间窗口**: 建议低峰期(凌晨 2:00 - 4:00)
|
||||
|
||||
---
|
||||
|
||||
## 一、迁移策略概述
|
||||
|
||||
### 1.1 迁移范围
|
||||
|
||||
| 数据类型 | 是否迁移 | 说明 |
|
||||
|----------|----------|------|
|
||||
| 用户数据 | ✅ 是 | 管理员账户、基础用户 |
|
||||
| 项目数据 | ✅ 是 | 项目配置、模板数据 |
|
||||
| 系统配置 | ✅ 是 | 系统参数、字典数据 |
|
||||
| 审计日志 | ⚠️ 可选 | 建议保留最近3个月 |
|
||||
| 测试数据 | ❌ 否 | 清理后重新生成 |
|
||||
| 会话/缓存 | ❌ 否 | Redis 数据不迁移 |
|
||||
|
||||
### 1.2 迁移方式选择
|
||||
|
||||
**推荐方案:离线迁移(停机迁移)**
|
||||
|
||||
```
|
||||
测试环境 生产环境
|
||||
┌─────────┐ ┌─────────┐
|
||||
│ 源数据库 │ ──导出──▶ │ 导入目标 │
|
||||
│ plm_dev │ pg_dump │ plm_prod│
|
||||
└─────────┘ └─────────┘
|
||||
```
|
||||
|
||||
**选择理由**:
|
||||
1. 数据一致性高,无增量同步复杂度
|
||||
2. 操作简单,风险可控
|
||||
3. 适合首次上线场景
|
||||
4. 迁移时间窗口可控(预计 30 分钟内完成)
|
||||
|
||||
---
|
||||
|
||||
## 二、迁移前准备
|
||||
|
||||
### 2.1 检查清单
|
||||
|
||||
- [ ] 确认测试环境数据库版本与生产一致(PostgreSQL 14)
|
||||
- [ ] 确认生产环境已部署完成,服务可正常启动
|
||||
- [ ] 备份测试环境数据(以防万一)
|
||||
- [ ] 确认迁移时间窗口,通知相关人员
|
||||
- [ ] 准备回滚方案
|
||||
|
||||
### 2.2 环境信息确认
|
||||
|
||||
```bash
|
||||
# 测试环境信息
|
||||
TEST_DB_HOST=localhost
|
||||
TEST_DB_PORT=5432
|
||||
TEST_DB_NAME=plm_dev
|
||||
TEST_DB_USER=plm
|
||||
TEST_DB_PASS=plm123456
|
||||
|
||||
# 生产环境信息
|
||||
PROD_DB_HOST=postgres # Docker 服务名
|
||||
PROD_DB_PORT=5432
|
||||
PROD_DB_NAME=plm_production
|
||||
PROD_DB_USER=plm_prod
|
||||
PROD_DB_PASS=<生产环境强密码>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 三、迁移步骤
|
||||
|
||||
### 步骤 1:停止测试环境写入(可选)
|
||||
|
||||
```bash
|
||||
# 进入测试环境目录
|
||||
cd /home/serveradmin/plm-system
|
||||
|
||||
# 可选:停止前端访问,保留数据库运行
|
||||
docker-compose stop frontend backend
|
||||
```
|
||||
|
||||
### 步骤 2:导出测试环境数据
|
||||
|
||||
```bash
|
||||
# 创建迁移目录
|
||||
mkdir -p /opt/plm-migration
|
||||
cd /opt/plm-migration
|
||||
|
||||
# 导出数据(结构 + 数据)
|
||||
docker exec plm-test-postgres pg_dump \
|
||||
-h localhost \
|
||||
-U plm \
|
||||
-d plm_dev \
|
||||
--verbose \
|
||||
--blobs \
|
||||
--no-owner \
|
||||
--no-privileges \
|
||||
> plm_dev_backup_$(date +%Y%m%d_%H%M%S).sql
|
||||
|
||||
# 压缩备份文件
|
||||
gzip plm_dev_backup_*.sql
|
||||
|
||||
# 验证备份
|
||||
ls -lh plm_dev_backup_*.sql.gz
|
||||
```
|
||||
|
||||
### 步骤 3:数据清洗(可选)
|
||||
|
||||
创建 `cleanup-script.sql` 清理测试数据:
|
||||
|
||||
```sql
|
||||
-- 清理测试数据脚本
|
||||
-- 执行前请确认!
|
||||
|
||||
-- 删除测试用户(保留管理员)
|
||||
DELETE FROM users WHERE email LIKE '%test%' OR username LIKE '%test%';
|
||||
DELETE FROM users WHERE created_at < '2024-01-01' AND role != 'admin';
|
||||
|
||||
-- 删除测试项目
|
||||
DELETE FROM projects WHERE name LIKE '%test%' OR name LIKE '%Test%';
|
||||
DELETE FROM projects WHERE status = 'archived' AND updated_at < NOW() - INTERVAL '90 days';
|
||||
|
||||
-- 清理审计日志(保留最近3个月)
|
||||
DELETE FROM audit_logs WHERE created_at < NOW() - INTERVAL '90 days';
|
||||
|
||||
-- 重置序列号
|
||||
SELECT setval('users_id_seq', (SELECT MAX(id) FROM users));
|
||||
SELECT setval('projects_id_seq', (SELECT MAX(id) FROM projects));
|
||||
```
|
||||
|
||||
### 步骤 4:准备生产环境
|
||||
|
||||
```bash
|
||||
# 进入生产环境目录
|
||||
cd /opt/plm-production
|
||||
|
||||
# 启动基础设施服务(仅数据库和缓存)
|
||||
docker-compose -f docker-compose.prod.yml up -d postgres redis
|
||||
|
||||
# 等待数据库就绪
|
||||
docker-compose -f docker-compose.prod.yml exec postgres pg_isready -U plm_prod
|
||||
```
|
||||
|
||||
### 步骤 5:导入数据到生产环境
|
||||
|
||||
```bash
|
||||
# 复制备份文件到生产环境
|
||||
cp /opt/plm-migration/plm_dev_backup_*.sql.gz /opt/plm-production/backups/
|
||||
|
||||
# 解压
|
||||
cd /opt/plm-production
|
||||
gunzip backups/plm_dev_backup_*.sql.gz
|
||||
|
||||
# 导入数据
|
||||
docker-compose -f docker-compose.prod.yml exec -T postgres psql \
|
||||
-U plm_prod \
|
||||
-d plm_production \
|
||||
< backups/plm_dev_backup_*.sql
|
||||
|
||||
# 验证导入
|
||||
docker-compose -f docker-compose.prod.yml exec postgres psql \
|
||||
-U plm_prod \
|
||||
-d plm_production \
|
||||
-c "SELECT COUNT(*) FROM users;"
|
||||
|
||||
docker-compose -f docker-compose.prod.yml exec postgres psql \
|
||||
-U plm_prod \
|
||||
-d plm_production \
|
||||
-c "SELECT COUNT(*) FROM projects;"
|
||||
```
|
||||
|
||||
### 步骤 6:更新生产环境配置
|
||||
|
||||
```bash
|
||||
# 更新管理员密码(强制修改)
|
||||
docker-compose -f docker-compose.prod.yml exec postgres psql \
|
||||
-U plm_prod \
|
||||
-d plm_production \
|
||||
-c "UPDATE users SET password_hash = '<新密码哈希>' WHERE username = 'admin';"
|
||||
|
||||
# 更新 JWT Secret(使测试环境 token 失效)
|
||||
# 在 .env.prod 中更新 JWT_SECRET_KEY
|
||||
```
|
||||
|
||||
### 步骤 7:启动完整服务
|
||||
|
||||
```bash
|
||||
# 启动所有服务
|
||||
docker-compose -f docker-compose.prod.yml up -d
|
||||
|
||||
# 检查服务状态
|
||||
docker-compose -f docker-compose.prod.yml ps
|
||||
|
||||
# 查看日志
|
||||
docker-compose -f docker-compose.prod.yml logs -f
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 四、数据验证
|
||||
|
||||
### 4.1 基础数据验证
|
||||
|
||||
```bash
|
||||
# 连接生产数据库
|
||||
docker-compose -f docker-compose.prod.yml exec postgres psql -U plm_prod -d plm_production
|
||||
|
||||
-- 验证表结构
|
||||
\dt
|
||||
|
||||
-- 验证用户数据
|
||||
SELECT COUNT(*) AS total_users FROM users;
|
||||
SELECT username, email, role, status FROM users WHERE role = 'admin';
|
||||
|
||||
-- 验证项目数据
|
||||
SELECT COUNT(*) AS total_projects FROM projects;
|
||||
SELECT status, COUNT(*) FROM projects GROUP BY status;
|
||||
|
||||
-- 验证配置数据
|
||||
SELECT COUNT(*) AS total_configs FROM system_configs;
|
||||
SELECT category, COUNT(*) FROM system_configs GROUP BY category;
|
||||
```
|
||||
|
||||
### 4.2 API 功能验证
|
||||
|
||||
```bash
|
||||
# 健康检查
|
||||
curl https://aifly.ren/health
|
||||
|
||||
# 登录测试(使用管理员账户)
|
||||
curl -X POST https://aifly.ren/api/auth/login \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"username":"admin","password":"新密码"}'
|
||||
|
||||
# 获取用户列表(需要 token)
|
||||
curl https://aifly.ren/api/users \
|
||||
-H "Authorization: Bearer <token>"
|
||||
```
|
||||
|
||||
### 4.3 业务功能验证
|
||||
|
||||
- [ ] 管理员登录正常
|
||||
- [ ] 用户列表可正常查看
|
||||
- [ ] 项目列表可正常查看
|
||||
- [ ] 系统配置可正常读取
|
||||
- [ ] 新建用户/项目功能正常
|
||||
|
||||
---
|
||||
|
||||
## 五、回滚方案
|
||||
|
||||
### 5.1 触发条件
|
||||
|
||||
- 数据导入失败
|
||||
- 服务启动异常
|
||||
- API 功能验证失败
|
||||
- 严重数据不一致
|
||||
|
||||
### 5.2 回滚步骤
|
||||
|
||||
```bash
|
||||
# 1. 停止生产服务
|
||||
cd /opt/plm-production
|
||||
docker-compose -f docker-compose.prod.yml down
|
||||
|
||||
# 2. 清理数据卷
|
||||
docker volume rm plm-production_postgres_data
|
||||
|
||||
# 3. 重新初始化数据库
|
||||
docker-compose -f docker-compose.prod.yml up -d postgres
|
||||
|
||||
# 4. 初始化空数据库
|
||||
docker-compose -f docker-compose.prod.yml exec backend python -m app.init_db
|
||||
|
||||
# 5. 重新创建管理员账户
|
||||
# 使用应用提供的初始化命令
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 六、迁移后清理
|
||||
|
||||
### 6.1 测试环境处理
|
||||
|
||||
```bash
|
||||
# 可选:清理测试环境敏感数据
|
||||
cd /home/serveradmin/plm-system
|
||||
|
||||
# 重置测试数据库
|
||||
docker-compose exec postgres psql -U plm -d plm_dev -c "TRUNCATE TABLE users, projects CASCADE;"
|
||||
|
||||
# 或者完全重置
|
||||
docker-compose down -v
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
### 6.2 备份文件管理
|
||||
|
||||
```bash
|
||||
# 加密备份文件并归档
|
||||
gpg --symmetric --cipher-algo AES256 /opt/plm-migration/plm_dev_backup_*.sql
|
||||
|
||||
# 移动到安全存储
|
||||
mv /opt/plm-migration/*.gpg /secure-backup-location/
|
||||
|
||||
# 清理临时文件
|
||||
rm -rf /opt/plm-migration
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 七、迁移时间表
|
||||
|
||||
| 时间 | 任务 | 负责人 | 预计时长 |
|
||||
|------|------|--------|----------|
|
||||
T-30min | 通知相关人员,准备环境 | 运维 | 30min |
|
||||
T-0 | 停止测试环境写入 | 运维 | 5min |
|
||||
T+5min | 导出测试数据 | 运维 | 10min |
|
||||
T+15min | 数据清洗(可选) | 运维 | 10min |
|
||||
T+25min | 导入生产数据库 | 运维 | 15min |
|
||||
T+40min | 启动生产服务 | 运维 | 5min |
|
||||
T+45min | 数据验证 | 运维/测试 | 15min |
|
||||
T+60min | 功能验证 | 测试 | 30min |
|
||||
T+90min | 上线完成,发送通知 | 运维 | 5min |
|
||||
|
||||
**总计预计时间**: 90 分钟(含验证)
|
||||
|
||||
---
|
||||
|
||||
## 八、注意事项
|
||||
|
||||
1. **密码安全**:迁移后必须修改所有默认密码
|
||||
2. **Token 失效**:更新 JWT_SECRET_KEY 使测试环境 token 失效
|
||||
3. **数据敏感**:备份文件包含敏感数据,需加密存储
|
||||
4. **时间窗口**:选择业务低峰期进行迁移
|
||||
5. **双人复核**:关键步骤建议双人确认
|
||||
6. **监控告警**:迁移期间加强监控
|
||||
|
||||
---
|
||||
|
||||
**文档维护**: 运维团队
|
||||
**审核**: CTO/架构师
|
||||
**生效日期**: 2026-04-03
|
||||
311
docs/deployment/04-deployment-checklist.md
Normal file
311
docs/deployment/04-deployment-checklist.md
Normal file
@@ -0,0 +1,311 @@
|
||||
# PLM 系统上线检查清单
|
||||
|
||||
## 📋 文档信息
|
||||
|
||||
- **文档版本**: 1.0.0
|
||||
- **适用环境**: Production
|
||||
- **域名**: aifly.ren
|
||||
|
||||
---
|
||||
|
||||
## 一、部署前检查
|
||||
|
||||
### 1.1 服务器环境检查
|
||||
|
||||
| 检查项 | 检查命令 | 预期结果 | 状态 |
|
||||
|--------|----------|----------|------|
|
||||
| 操作系统版本 | `lsb_release -a` | Ubuntu 20.04+ / CentOS 7+ | ⬜ |
|
||||
| Docker 版本 | `docker --version` | 20.10+ | ⬜ |
|
||||
| Docker Compose | `docker compose version` | 2.0+ | ⬜ |
|
||||
| 磁盘空间 | `df -h /` | > 50GB 可用 | ⬜ |
|
||||
| 内存容量 | `free -h` | > 8GB 可用 | ⬜ |
|
||||
| CPU 核心 | `nproc` | >= 4 核 | ⬜ |
|
||||
| 系统时间 | `timedatectl status` | 时区正确,NTP 同步 | ⬜ |
|
||||
|
||||
### 1.2 网络配置检查
|
||||
|
||||
| 检查项 | 检查命令 | 预期结果 | 状态 |
|
||||
|--------|----------|----------|------|
|
||||
| 域名解析 | `nslookup aifly.ren` | 解析到服务器 IP | ⬜ |
|
||||
| 端口开放 | `sudo ufw status` | 80, 443 开放 | ⬜ |
|
||||
| 防火墙规则 | `sudo iptables -L` | 规则正确 | ⬜ |
|
||||
| 外网访问 | `curl ifconfig.me` | 获取公网 IP | ⬜ |
|
||||
|
||||
### 1.3 SSL 证书检查
|
||||
|
||||
| 检查项 | 检查命令 | 预期结果 | 状态 |
|
||||
|--------|----------|----------|------|
|
||||
| 证书文件 | `ls -la nginx/ssl/` | 证书文件存在 | ⬜ |
|
||||
| 证书有效期 | `openssl x509 -in nginx/ssl/aifly.ren.crt -noout -dates` | 未过期 | ⬜ |
|
||||
| 证书域名 | `openssl x509 -in nginx/ssl/aifly.ren.crt -noout -subject` | 包含 aifly.ren | ⬜ |
|
||||
|
||||
---
|
||||
|
||||
## 二、配置文件检查
|
||||
|
||||
### 2.1 环境变量检查 (.env.prod)
|
||||
|
||||
| 配置项 | 检查点 | 预期值 | 状态 |
|
||||
|--------|--------|--------|------|
|
||||
| DEBUG | 是否关闭 | false | ⬜ |
|
||||
| ENVIRONMENT | 环境标识 | production | ⬜ |
|
||||
| JWT_SECRET_KEY | 是否已修改 | 非默认值 | ⬜ |
|
||||
| DATABASE_URL | 数据库连接 | 指向生产库 | ⬜ |
|
||||
| REDIS_PASSWORD | 是否设置 | 已设置强密码 | ⬜ |
|
||||
| CORS_ORIGINS | 跨域配置 | 仅生产域名 | ⬜ |
|
||||
|
||||
### 2.2 Docker Compose 检查
|
||||
|
||||
| 检查项 | 检查点 | 状态 |
|
||||
|--------|--------|------|
|
||||
| 镜像版本 | 使用特定版本标签,非 latest | ⬜ |
|
||||
| 资源限制 | CPU/内存限制已配置 | ⬜ |
|
||||
| 健康检查 | 所有服务配置健康检查 | ⬜ |
|
||||
| 重启策略 | 配置 unless-stopped | ⬜ |
|
||||
| 日志配置 | 日志限制已配置 | ⬜ |
|
||||
|
||||
### 2.3 Nginx 配置检查
|
||||
|
||||
| 检查项 | 检查点 | 状态 |
|
||||
|--------|--------|------|
|
||||
| HTTPS 强制 | HTTP 自动跳转 HTTPS | ⬜ |
|
||||
| SSL 配置 | TLS 1.2+,强加密套件 | ⬜ |
|
||||
| 安全头 | X-Frame-Options 等已配置 | ⬜ |
|
||||
| 限流配置 | API 限流规则已配置 | ⬜ |
|
||||
| Gzip 压缩 | 静态资源压缩已启用 | ⬜ |
|
||||
|
||||
---
|
||||
|
||||
## 三、部署过程检查
|
||||
|
||||
### 3.1 服务启动检查
|
||||
|
||||
```bash
|
||||
# 启动服务
|
||||
docker-compose -f docker-compose.prod.yml up -d
|
||||
|
||||
# 检查容器状态
|
||||
docker-compose -f docker-compose.prod.yml ps
|
||||
```
|
||||
|
||||
| 服务 | 容器名 | 状态 | 健康检查 |
|
||||
|------|--------|------|----------|
|
||||
| PostgreSQL | plm-prod-postgres | Up | ⬜ |
|
||||
| Redis | plm-prod-redis | Up | ⬜ |
|
||||
| Backend | plm-prod-backend | Up | ⬜ |
|
||||
| Frontend | plm-prod-frontend | Up | ⬜ |
|
||||
| Nginx | plm-prod-nginx | Up | ⬜ |
|
||||
|
||||
### 3.2 日志检查
|
||||
|
||||
```bash
|
||||
# 查看各服务日志
|
||||
docker-compose -f docker-compose.prod.yml logs --tail=100 [service-name]
|
||||
```
|
||||
|
||||
| 服务 | 检查内容 | 预期结果 | 状态 |
|
||||
|------|----------|----------|------|
|
||||
| PostgreSQL | 启动日志 | 无 ERROR | ⬜ |
|
||||
| Redis | 启动日志 | Ready to accept connections | ⬜ |
|
||||
| Backend | 启动日志 | Application startup complete | ⬜ |
|
||||
| Nginx | 错误日志 | 无 5xx 错误 | ⬜ |
|
||||
|
||||
---
|
||||
|
||||
## 四、功能验证检查
|
||||
|
||||
### 4.1 基础接口检查
|
||||
|
||||
```bash
|
||||
# 健康检查
|
||||
curl -s https://aifly.ren/health | jq .
|
||||
|
||||
# API 文档
|
||||
curl -s https://aifly.ren/docs | head
|
||||
```
|
||||
|
||||
| 接口 | 请求 | 预期响应 | 状态 |
|
||||
|------|------|----------|------|
|
||||
| Health | GET /health | `{"status":"healthy"}` | ⬜ |
|
||||
| API Docs | GET /docs | 返回 Swagger UI | ⬜ |
|
||||
| Redoc | GET /redoc | 返回 ReDoc | ⬜ |
|
||||
|
||||
### 4.2 认证功能检查
|
||||
|
||||
| 功能 | 测试步骤 | 预期结果 | 状态 |
|
||||
|------|----------|----------|------|
|
||||
| 管理员登录 | POST /api/auth/login | 返回 JWT token | ⬜ |
|
||||
| Token 刷新 | POST /api/auth/refresh | 返回新 token | ⬜ |
|
||||
| 获取当前用户 | GET /api/auth/me | 返回用户信息 | ⬜ |
|
||||
| 登出 | POST /api/auth/logout | 成功响应 | ⬜ |
|
||||
|
||||
### 4.3 用户管理检查
|
||||
|
||||
| 功能 | 测试步骤 | 预期结果 | 状态 |
|
||||
|------|----------|----------|------|
|
||||
| 用户列表 | GET /api/users | 返回用户列表 | ⬜ |
|
||||
| 创建用户 | POST /api/users | 创建成功 | ⬜ |
|
||||
| 更新用户 | PUT /api/users/{id} | 更新成功 | ⬜ |
|
||||
| 删除用户 | DELETE /api/users/{id} | 删除成功 | ⬜ |
|
||||
|
||||
### 4.4 项目管理检查
|
||||
|
||||
| 功能 | 测试步骤 | 预期结果 | 状态 |
|
||||
|------|----------|----------|------|
|
||||
| 项目列表 | GET /api/projects | 返回项目列表 | ⬜ |
|
||||
| 创建项目 | POST /api/projects | 创建成功 | ⬜ |
|
||||
| 项目详情 | GET /api/projects/{id} | 返回详情 | ⬜ |
|
||||
| 更新项目 | PUT /api/projects/{id} | 更新成功 | ⬜ |
|
||||
|
||||
### 4.5 配置管理检查
|
||||
|
||||
| 功能 | 测试步骤 | 预期结果 | 状态 |
|
||||
|------|----------|----------|------|
|
||||
| 配置列表 | GET /api/configs | 返回配置列表 | ⬜ |
|
||||
| 创建配置 | POST /api/configs | 创建成功 | ⬜ |
|
||||
| 配置历史 | GET /api/configs/{id}/history | 返回历史记录 | ⬜ |
|
||||
|
||||
---
|
||||
|
||||
## 五、性能检查
|
||||
|
||||
### 5.1 响应时间检查
|
||||
|
||||
```bash
|
||||
# 测试 API 响应时间
|
||||
curl -w "@curl-format.txt" -o /dev/null -s https://aifly.ren/api/health
|
||||
```
|
||||
|
||||
| 接口 | 平均响应时间 | 最大响应时间 | 状态 |
|
||||
|------|-------------|-------------|------|
|
||||
| /health | < 100ms | < 500ms | ⬜ |
|
||||
| /api/auth/login | < 200ms | < 1000ms | ⬜ |
|
||||
| /api/users | < 300ms | < 1500ms | ⬜ |
|
||||
| /api/projects | < 300ms | < 1500ms | ⬜ |
|
||||
|
||||
### 5.2 并发测试
|
||||
|
||||
```bash
|
||||
# 使用 ab 或 wrk 进行压力测试
|
||||
ab -n 1000 -c 10 https://aifly.ren/health
|
||||
```
|
||||
|
||||
| 指标 | 目标值 | 实际值 | 状态 |
|
||||
|------|--------|--------|------|
|
||||
| RPS (Requests/sec) | > 100 | | ⬜ |
|
||||
| 失败率 | < 1% | | ⬜ |
|
||||
| 平均响应时间 | < 200ms | | ⬜ |
|
||||
|
||||
---
|
||||
|
||||
## 六、安全检奁
|
||||
|
||||
### 6.1 端口安全
|
||||
|
||||
| 检查项 | 检查命令 | 预期结果 | 状态 |
|
||||
|--------|----------|----------|------|
|
||||
| 数据库端口 | `nmap -p 5432 aifly.ren` | 关闭/过滤 | ⬜ |
|
||||
| Redis 端口 | `nmap -p 6379 aifly.ren` | 关闭/过滤 | ⬜ |
|
||||
| 后端端口 | `nmap -p 8000 aifly.ren` | 关闭/过滤 | ⬜ |
|
||||
|
||||
### 6.2 HTTPS 安全
|
||||
|
||||
```bash
|
||||
# SSL 检测
|
||||
curl -s https://www.ssllabs.com/ssltest/analyze.html?d=aifly.ren
|
||||
```
|
||||
|
||||
| 检查项 | 预期结果 | 状态 |
|
||||
|--------|----------|------|
|
||||
| SSL 评级 | A+ 或 A | ⬜ |
|
||||
| HSTS | 已启用 | ⬜ |
|
||||
| 证书链 | 完整 | ⬜ |
|
||||
|
||||
### 6.3 安全头检查
|
||||
|
||||
```bash
|
||||
curl -I https://aifly.ren
|
||||
```
|
||||
|
||||
| 响应头 | 预期值 | 状态 |
|
||||
|--------|--------|------|
|
||||
| Strict-Transport-Security | 存在 | ⬜ |
|
||||
| X-Frame-Options | DENY/SAMEORIGIN | ⬜ |
|
||||
| X-Content-Type-Options | nosniff | ⬜ |
|
||||
| X-XSS-Protection | 1; mode=block | ⬜ |
|
||||
|
||||
---
|
||||
|
||||
## 七、备份与监控检查
|
||||
|
||||
### 7.1 备份配置检查
|
||||
|
||||
| 检查项 | 检查命令 | 预期结果 | 状态 |
|
||||
|--------|----------|----------|------|
|
||||
| 备份目录 | `ls -la backups/` | 目录存在 | ⬜ |
|
||||
| 备份脚本 | `ls -la scripts/backup.sh` | 文件存在 | ⬜ |
|
||||
| 定时任务 | `docker exec plm-prod-backup crontab -l` | 任务已配置 | ⬜ |
|
||||
| 手动备份测试 | 执行备份脚本 | 成功生成备份 | ⬜ |
|
||||
|
||||
### 7.2 日志配置检查
|
||||
|
||||
| 检查项 | 检查路径 | 状态 |
|
||||
|--------|----------|------|
|
||||
| Nginx 访问日志 | `logs/nginx/access.log` | ⬜ |
|
||||
| Nginx 错误日志 | `logs/nginx/error.log` | ⬜ |
|
||||
| 应用日志 | `logs/app.log` | ⬜ |
|
||||
| 日志轮转 | 配置 logrotate | ⬜ |
|
||||
|
||||
---
|
||||
|
||||
## 八、最终确认
|
||||
|
||||
### 8.1 上线前最终检查
|
||||
|
||||
- [ ] 所有配置已审核并确认无误
|
||||
- [ ] 数据库迁移已完成并验证
|
||||
- [ ] 所有服务正常运行
|
||||
- [ ] 核心功能测试通过
|
||||
- [ ] 性能测试达标
|
||||
- [ ] 安全检查通过
|
||||
- [ ] 备份策略已配置
|
||||
- [ ] 监控告警已配置
|
||||
- [ ] 回滚方案已准备
|
||||
- [ ] 上线通知已发送
|
||||
|
||||
### 8.2 上线后观察项
|
||||
|
||||
| 观察项 | 观察时间 | 负责人 |
|
||||
|--------|----------|--------|
|
||||
| 系统资源使用 | 上线后 24h | 运维 |
|
||||
| 错误日志监控 | 上线后 24h | 运维 |
|
||||
| 用户反馈收集 | 上线后 48h | 产品 |
|
||||
| 性能指标监控 | 上线后 1周 | 运维 |
|
||||
|
||||
---
|
||||
|
||||
## 九、应急联系
|
||||
|
||||
| 角色 | 姓名 | 联系方式 | 职责 |
|
||||
|------|------|----------|------|
|
||||
| 运维负责人 | | | 技术问题处理 |
|
||||
| 开发负责人 | | | 代码问题修复 |
|
||||
| 产品经理 | | | 业务决策 |
|
||||
| 测试负责人 | | | 验证确认 |
|
||||
|
||||
---
|
||||
|
||||
## 十、签字确认
|
||||
|
||||
| 角色 | 签字 | 日期 |
|
||||
|------|------|------|
|
||||
| 运维工程师 | | |
|
||||
| 开发工程师 | | |
|
||||
| 测试工程师 | | |
|
||||
| 产品经理 | | |
|
||||
| 技术负责人 | | |
|
||||
|
||||
---
|
||||
|
||||
**文档维护**: 运维团队
|
||||
**生效日期**: 2026-04-03
|
||||
179
docs/deployment/README.md
Normal file
179
docs/deployment/README.md
Normal file
@@ -0,0 +1,179 @@
|
||||
# PLM 系统生产环境部署包
|
||||
|
||||
## 📦 包内容说明
|
||||
|
||||
本部署包包含 PLM 系统生产环境部署所需的全部配置文件和文档。
|
||||
|
||||
---
|
||||
|
||||
## 📁 目录结构
|
||||
|
||||
```
|
||||
plm-production-deployment/
|
||||
├── 01-production-deployment-plan.md # 生产环境部署方案
|
||||
├── 02-production-config.md # 生产环境配置文档
|
||||
├── 03-data-migration.md # 数据迁移方案
|
||||
├── 04-deployment-checklist.md # 上线检查清单
|
||||
├── README.md # 本文件
|
||||
├── docker-compose.prod.yml # Docker Compose 生产配置
|
||||
├── .env.prod.example # 环境变量模板
|
||||
├── nginx/ # Nginx 配置
|
||||
│ ├── nginx.conf # Nginx 主配置
|
||||
│ ├── conf.d/
|
||||
│ │ └── production.conf # 站点配置
|
||||
│ ├── ssl/ # SSL 证书目录(需自行放置)
|
||||
│ └── html/ # 静态文件目录
|
||||
├── init-scripts/ # 数据库初始化脚本
|
||||
│ ├── 01-init-db.sql # 数据库初始化
|
||||
│ └── postgres-config.sql # PostgreSQL 优化配置
|
||||
├── scripts/ # 运维脚本
|
||||
│ └── backup.sh # 数据库备份脚本
|
||||
├── backups/ # 备份文件存储目录
|
||||
└── logs/ # 日志目录
|
||||
└── nginx/ # Nginx 日志
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚀 快速部署步骤
|
||||
|
||||
### 1. 准备服务器
|
||||
|
||||
- Ubuntu 20.04+ / CentOS 7+
|
||||
- Docker 20.10+
|
||||
- Docker Compose 2.0+
|
||||
- 4核8G+ 配置
|
||||
- 域名已解析到服务器
|
||||
|
||||
### 2. 上传部署包
|
||||
|
||||
```bash
|
||||
# 在服务器上创建目录
|
||||
mkdir -p /opt/plm-production
|
||||
cd /opt/plm-production
|
||||
|
||||
# 上传本部署包内容到该目录
|
||||
```
|
||||
|
||||
### 3. 配置环境变量
|
||||
|
||||
```bash
|
||||
# 复制环境变量模板
|
||||
cp .env.prod.example .env.prod
|
||||
|
||||
# 编辑 .env.prod,修改所有 CHANGE_THIS_ 开头的值
|
||||
nano .env.prod
|
||||
|
||||
# 设置文件权限
|
||||
chmod 600 .env.prod
|
||||
```
|
||||
|
||||
### 4. 配置 SSL 证书
|
||||
|
||||
```bash
|
||||
# 方式1:使用 Let's Encrypt
|
||||
certbot certonly --standalone -d aifly.ren -d www.aifly.ren
|
||||
|
||||
# 复制证书到 nginx/ssl 目录
|
||||
cp /etc/letsencrypt/live/aifly.ren/fullchain.pem nginx/ssl/aifly.ren.crt
|
||||
cp /etc/letsencrypt/live/aifly.ren/privkey.pem nginx/ssl/aifly.ren.key
|
||||
|
||||
# 方式2:使用自有证书
|
||||
# 直接将证书文件放入 nginx/ssl/ 目录
|
||||
```
|
||||
|
||||
### 5. 启动服务
|
||||
|
||||
```bash
|
||||
# 加载环境变量
|
||||
source .env.prod
|
||||
|
||||
# 启动基础设施(数据库、缓存)
|
||||
docker-compose -f docker-compose.prod.yml up -d postgres redis
|
||||
|
||||
# 等待数据库就绪(约30秒)
|
||||
sleep 30
|
||||
|
||||
# 初始化数据库(首次部署)
|
||||
docker-compose -f docker-compose.prod.yml run --rm backend python -m app.init_db
|
||||
|
||||
# 启动所有服务
|
||||
docker-compose -f docker-compose.prod.yml up -d
|
||||
|
||||
# 检查状态
|
||||
docker-compose -f docker-compose.prod.yml ps
|
||||
```
|
||||
|
||||
### 6. 验证部署
|
||||
|
||||
```bash
|
||||
# 健康检查
|
||||
curl https://aifly.ren/health
|
||||
|
||||
# 查看日志
|
||||
docker-compose -f docker-compose.prod.yml logs -f
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📋 重要文档索引
|
||||
|
||||
| 文档 | 用途 | 阅读时机 |
|
||||
|------|------|----------|
|
||||
| [01-production-deployment-plan.md](01-production-deployment-plan.md) | 部署方案、架构设计 | 部署前 |
|
||||
| [02-production-config.md](02-production-config.md) | 详细配置说明 | 配置时 |
|
||||
| [03-data-migration.md](03-data-migration.md) | 数据迁移步骤 | 迁移时 |
|
||||
| [04-deployment-checklist.md](04-deployment-checklist.md) | 上线检查清单 | 上线前 |
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ 安全注意事项
|
||||
|
||||
1. **环境变量**:`.env.prod` 包含敏感信息,务必设置 600 权限
|
||||
2. **SSL 证书**:生产环境必须启用 HTTPS
|
||||
3. **密码策略**:所有密码使用强密码,定期轮换
|
||||
4. **防火墙**:仅开放 80/443/22 端口
|
||||
5. **备份**:定期检查备份是否正常运行
|
||||
|
||||
---
|
||||
|
||||
## 🔧 常用运维命令
|
||||
|
||||
```bash
|
||||
# 查看服务状态
|
||||
docker-compose -f docker-compose.prod.yml ps
|
||||
|
||||
# 查看日志
|
||||
docker-compose -f docker-compose.prod.yml logs -f [service-name]
|
||||
|
||||
# 重启服务
|
||||
docker-compose -f docker-compose.prod.yml restart [service-name]
|
||||
|
||||
# 停止服务
|
||||
docker-compose -f docker-compose.prod.yml down
|
||||
|
||||
# 更新部署
|
||||
docker-compose -f docker-compose.prod.yml pull
|
||||
docker-compose -f docker-compose.prod.yml up -d
|
||||
|
||||
# 手动备份
|
||||
docker-compose -f docker-compose.prod.yml exec backup /backup.sh
|
||||
|
||||
# 进入数据库
|
||||
docker-compose -f docker-compose.prod.yml exec postgres psql -U plm_prod -d plm_production
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📞 技术支持
|
||||
|
||||
- **部署问题**:查看 `01-production-deployment-plan.md`
|
||||
- **配置问题**:查看 `02-production-config.md`
|
||||
- **迁移问题**:查看 `03-data-migration.md`
|
||||
- **上线检查**:查看 `04-deployment-checklist.md`
|
||||
|
||||
---
|
||||
|
||||
**版本**: 1.0.0
|
||||
**更新日期**: 2026-04-03
|
||||
**维护团队**: 运维团队
|
||||
211
docs/deployment/docker-compose.prod.yml
Normal file
211
docs/deployment/docker-compose.prod.yml
Normal file
@@ -0,0 +1,211 @@
|
||||
# PLM Production Environment Docker Compose
|
||||
# 生产环境部署配置
|
||||
# 域名: https://aifly.ren
|
||||
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
# ============================================
|
||||
# PostgreSQL 14 Database (Production)
|
||||
# ============================================
|
||||
postgres:
|
||||
image: postgres:14-alpine
|
||||
container_name: plm-prod-postgres
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
POSTGRES_USER: ${POSTGRES_USER:-plm_prod}
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-CHANGE_THIS_PASSWORD}
|
||||
POSTGRES_DB: ${POSTGRES_DB:-plm_production}
|
||||
PGDATA: /var/lib/postgresql/data/pgdata
|
||||
# 性能优化
|
||||
POSTGRES_INITDB_ARGS: "--encoding=UTF8 --locale=en_US.UTF-8"
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
- ./backups:/backups
|
||||
- ./init-scripts:/docker-entrypoint-initdb.d
|
||||
# 生产环境不暴露端口,仅内部网络访问
|
||||
networks:
|
||||
- plm-prod-network
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-plm_prod} -d ${POSTGRES_DB:-plm_production}"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 30s
|
||||
# 资源限制
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '2.0'
|
||||
memory: 4G
|
||||
reservations:
|
||||
cpus: '1.0'
|
||||
memory: 2G
|
||||
|
||||
# ============================================
|
||||
# Redis 7 Cache (Production)
|
||||
# ============================================
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
container_name: plm-prod-redis
|
||||
restart: unless-stopped
|
||||
command: >
|
||||
redis-server
|
||||
--appendonly yes
|
||||
--requirepass ${REDIS_PASSWORD:-CHANGE_REDIS_PASSWORD}
|
||||
--maxmemory 512mb
|
||||
--maxmemory-policy allkeys-lru
|
||||
volumes:
|
||||
- redis_data:/data
|
||||
# 生产环境不暴露端口,仅内部网络访问
|
||||
networks:
|
||||
- plm-prod-network
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD:-CHANGE_REDIS_PASSWORD}", "ping"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '0.5'
|
||||
memory: 512M
|
||||
reservations:
|
||||
cpus: '0.25'
|
||||
memory: 256M
|
||||
|
||||
# ============================================
|
||||
# PLM Backend Service (Production)
|
||||
# ============================================
|
||||
backend:
|
||||
image: plm-backend:${BACKEND_VERSION:-latest}
|
||||
container_name: plm-prod-backend
|
||||
restart: unless-stopped
|
||||
env_file:
|
||||
- .env.prod
|
||||
environment:
|
||||
# 覆盖开发环境配置
|
||||
DEBUG: "false"
|
||||
ENVIRONMENT: "production"
|
||||
WORKERS: "4"
|
||||
# 数据库连接(使用服务名)
|
||||
DATABASE_URL: postgresql+asyncpg://${POSTGRES_USER:-plm_prod}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-plm_production}
|
||||
DATABASE_SYNC_URL: postgresql://${POSTGRES_USER:-plm_prod}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-plm_production}
|
||||
# Redis 连接
|
||||
REDIS_URL: redis://:${REDIS_PASSWORD}@redis:6379/0
|
||||
volumes:
|
||||
- uploads_data:/app/uploads
|
||||
- ./logs:/app/logs
|
||||
networks:
|
||||
- plm-prod-network
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 60s
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '2.0'
|
||||
memory: 2G
|
||||
reservations:
|
||||
cpus: '1.0'
|
||||
memory: 1G
|
||||
|
||||
# ============================================
|
||||
# PLM Frontend Service (Production)
|
||||
# ============================================
|
||||
frontend:
|
||||
image: plm-frontend:${FRONTEND_VERSION:-latest}
|
||||
container_name: plm-prod-frontend
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- plm-prod-network
|
||||
depends_on:
|
||||
- backend
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '0.5'
|
||||
memory: 512M
|
||||
reservations:
|
||||
cpus: '0.25'
|
||||
memory: 256M
|
||||
|
||||
# ============================================
|
||||
# Nginx Reverse Proxy (Production)
|
||||
# ============================================
|
||||
nginx:
|
||||
image: nginx:alpine
|
||||
container_name: plm-prod-nginx
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
volumes:
|
||||
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
|
||||
- ./nginx/conf.d:/etc/nginx/conf.d:ro
|
||||
- ./nginx/ssl:/etc/nginx/ssl:ro
|
||||
- ./nginx/html:/usr/share/nginx/html:ro
|
||||
- ./logs/nginx:/var/log/nginx
|
||||
networks:
|
||||
- plm-prod-network
|
||||
depends_on:
|
||||
- backend
|
||||
- frontend
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost/health"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '0.5'
|
||||
memory: 256M
|
||||
reservations:
|
||||
cpus: '0.25'
|
||||
memory: 128M
|
||||
|
||||
# ============================================
|
||||
# Database Backup Service (Production)
|
||||
# ============================================
|
||||
backup:
|
||||
image: postgres:14-alpine
|
||||
container_name: plm-prod-backup
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
POSTGRES_USER: ${POSTGRES_USER:-plm_prod}
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
||||
POSTGRES_DB: ${POSTGRES_DB:-plm_production}
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data:ro
|
||||
- ./backups:/backups
|
||||
- ./scripts/backup.sh:/backup.sh:ro
|
||||
command: >
|
||||
sh -c "echo '0 2 * * * /backup.sh' | crontab - && crond -f"
|
||||
networks:
|
||||
- plm-prod-network
|
||||
depends_on:
|
||||
- postgres
|
||||
|
||||
networks:
|
||||
plm-prod-network:
|
||||
driver: bridge
|
||||
ipam:
|
||||
config:
|
||||
- subnet: 172.20.0.0/16
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
driver: local
|
||||
redis_data:
|
||||
driver: local
|
||||
uploads_data:
|
||||
driver: local
|
||||
15
docs/deployment/init-scripts/01-init-db.sql
Normal file
15
docs/deployment/init-scripts/01-init-db.sql
Normal file
@@ -0,0 +1,15 @@
|
||||
-- PLM Production Database Initialization
|
||||
-- 生产环境数据库初始化脚本
|
||||
|
||||
-- 创建扩展
|
||||
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
||||
CREATE EXTENSION IF NOT EXISTS "pg_stat_statements";
|
||||
|
||||
-- 设置时区
|
||||
SET TIMEZONE = 'Asia/Shanghai';
|
||||
|
||||
-- 性能优化配置(需要超级权限)
|
||||
-- 这些配置也可以在 postgresql.conf 中设置
|
||||
|
||||
-- 记录初始化完成
|
||||
\echo 'Database initialization completed for PLM Production'
|
||||
33
docs/deployment/init-scripts/postgres-config.sql
Normal file
33
docs/deployment/init-scripts/postgres-config.sql
Normal file
@@ -0,0 +1,33 @@
|
||||
-- PostgreSQL Production Configuration
|
||||
-- 适用于 4GB+ 内存的服务器
|
||||
-- 执行方式:连接到数据库后执行
|
||||
|
||||
-- 连接配置
|
||||
ALTER SYSTEM SET max_connections = '200';
|
||||
ALTER SYSTEM SET shared_buffers = '1GB';
|
||||
ALTER SYSTEM SET effective_cache_size = '3GB';
|
||||
ALTER SYSTEM SET maintenance_work_mem = '256MB';
|
||||
ALTER SYSTEM SET work_mem = '10MB';
|
||||
|
||||
-- WAL 配置
|
||||
ALTER SYSTEM SET wal_buffers = '16MB';
|
||||
ALTER SYSTEM SET checkpoint_completion_target = '0.9';
|
||||
ALTER SYSTEM SET random_page_cost = '1.1';
|
||||
ALTER SYSTEM SET effective_io_concurrency = '200';
|
||||
|
||||
-- 查询优化
|
||||
ALTER SYSTEM SET default_statistics_target = '100';
|
||||
ALTER SYSTEM SET seq_page_cost = '1.0';
|
||||
|
||||
-- 日志配置
|
||||
ALTER SYSTEM SET log_duration = 'on';
|
||||
ALTER SYSTEM SET log_min_duration_statement = '1000';
|
||||
ALTER SYSTEM SET log_checkpoints = 'on';
|
||||
ALTER SYSTEM SET log_connections = 'on';
|
||||
ALTER SYSTEM SET log_disconnections = 'on';
|
||||
ALTER SYSTEM SET log_lock_waits = 'on';
|
||||
|
||||
-- 应用配置
|
||||
SELECT pg_reload_conf();
|
||||
|
||||
\echo 'PostgreSQL production configuration applied successfully'
|
||||
111
docs/deployment/nginx/conf.d/production.conf
Normal file
111
docs/deployment/nginx/conf.d/production.conf
Normal file
@@ -0,0 +1,111 @@
|
||||
# PLM System Production - aifly.ren
|
||||
# 生产环境 Nginx 配置
|
||||
|
||||
upstream plm_backend {
|
||||
server backend:8000;
|
||||
keepalive 64;
|
||||
}
|
||||
|
||||
upstream plm_frontend {
|
||||
server frontend:3000;
|
||||
keepalive 32;
|
||||
}
|
||||
|
||||
# HTTP Server - Redirect to HTTPS
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name aifly.ren www.aifly.ren;
|
||||
|
||||
# ACME challenge for Let's Encrypt
|
||||
location /.well-known/acme-challenge/ {
|
||||
root /var/www/certbot;
|
||||
}
|
||||
|
||||
# Redirect all HTTP to HTTPS
|
||||
location / {
|
||||
return 301 https://$server_name$request_uri;
|
||||
}
|
||||
}
|
||||
|
||||
# HTTPS Server
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
listen [::]:443 ssl http2;
|
||||
server_name aifly.ren www.aifly.ren;
|
||||
|
||||
# SSL Certificate (Let's Encrypt)
|
||||
ssl_certificate /etc/nginx/ssl/aifly.ren.crt;
|
||||
ssl_certificate_key /etc/nginx/ssl/aifly.ren.key;
|
||||
|
||||
# SSL Configuration
|
||||
ssl_session_timeout 1d;
|
||||
ssl_session_cache shared:SSL:50m;
|
||||
ssl_session_tickets off;
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
|
||||
ssl_prefer_server_ciphers off;
|
||||
|
||||
# Security Headers
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
||||
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:;" always;
|
||||
|
||||
# Health check endpoint
|
||||
location /health {
|
||||
access_log off;
|
||||
return 200 "healthy\n";
|
||||
add_header Content-Type text/plain;
|
||||
}
|
||||
|
||||
# API proxy with rate limiting
|
||||
location /api/ {
|
||||
limit_req zone=api burst=20 nodelay;
|
||||
|
||||
proxy_pass http://plm_backend;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection 'upgrade';
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
proxy_read_timeout 86400;
|
||||
proxy_buffering off;
|
||||
}
|
||||
|
||||
# Auth endpoints - stricter rate limit
|
||||
location /api/auth/login {
|
||||
limit_req zone=login burst=5 nodelay;
|
||||
|
||||
proxy_pass http://plm_backend;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
# Frontend static files
|
||||
location / {
|
||||
proxy_pass http://plm_frontend;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection 'upgrade';
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
}
|
||||
|
||||
# Static assets caching
|
||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
||||
proxy_pass http://plm_frontend;
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
}
|
||||
46
docs/deployment/nginx/nginx.conf
Normal file
46
docs/deployment/nginx/nginx.conf
Normal file
@@ -0,0 +1,46 @@
|
||||
user nginx;
|
||||
worker_processes auto;
|
||||
error_log /var/log/nginx/error.log warn;
|
||||
pid /var/run/nginx.pid;
|
||||
|
||||
events {
|
||||
worker_connections 2048;
|
||||
use epoll;
|
||||
multi_accept on;
|
||||
}
|
||||
|
||||
http {
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
# Logging
|
||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" "$http_x_forwarded_for" '
|
||||
'$request_time $upstream_response_time';
|
||||
access_log /var/log/nginx/access.log main;
|
||||
|
||||
# Performance
|
||||
sendfile on;
|
||||
tcp_nopush on;
|
||||
tcp_nodelay on;
|
||||
keepalive_timeout 65;
|
||||
types_hash_max_size 2048;
|
||||
client_max_body_size 50M;
|
||||
|
||||
# Gzip
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
gzip_proxied any;
|
||||
gzip_comp_level 6;
|
||||
gzip_types text/plain text/css text/xml application/json
|
||||
application/javascript application/rss+xml
|
||||
application/atom+xml image/svg+xml;
|
||||
|
||||
# Rate limiting
|
||||
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
|
||||
limit_req_zone $binary_remote_addr zone=login:10m rate=1r/m;
|
||||
|
||||
# Include server configs
|
||||
include /etc/nginx/conf.d/*.conf;
|
||||
}
|
||||
36
docs/deployment/scripts/backup.sh
Executable file
36
docs/deployment/scripts/backup.sh
Executable file
@@ -0,0 +1,36 @@
|
||||
#!/bin/bash
|
||||
# PLM Production Database Backup Script
|
||||
# 运行方式: 通过 backup 服务定时执行
|
||||
|
||||
set -e
|
||||
|
||||
# 配置
|
||||
BACKUP_DIR="/backups"
|
||||
DB_NAME="${POSTGRES_DB:-plm_production}"
|
||||
DB_USER="${POSTGRES_USER:-plm_prod}"
|
||||
RETENTION_DAYS=30
|
||||
DATE=$(date +%Y%m%d_%H%M%S)
|
||||
BACKUP_FILE="${BACKUP_DIR}/plm_backup_${DATE}.sql.gz"
|
||||
|
||||
# 创建备份目录
|
||||
mkdir -p ${BACKUP_DIR}
|
||||
|
||||
# 执行备份
|
||||
echo "Starting backup at $(date)"
|
||||
pg_dump -h postgres -U ${DB_USER} -d ${DB_NAME} --verbose --blobs | gzip > ${BACKUP_FILE}
|
||||
|
||||
# 验证备份
|
||||
if [ -f "${BACKUP_FILE}" ]; then
|
||||
FILESIZE=$(du -h ${BACKUP_FILE} | cut -f1)
|
||||
echo "Backup completed: ${BACKUP_FILE} (${FILESIZE})"
|
||||
else
|
||||
echo "Backup failed!" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 清理旧备份(保留30天)
|
||||
find ${BACKUP_DIR} -name "plm_backup_*.sql.gz" -mtime +${RETENTION_DAYS} -delete
|
||||
echo "Cleaned up backups older than ${RETENTION_DAYS} days"
|
||||
|
||||
# 记录备份日志
|
||||
echo "$(date): Backup ${BACKUP_FILE} completed (${FILESIZE})" >> ${BACKUP_DIR}/backup.log
|
||||
Reference in New Issue
Block a user