You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
580 lines
13 KiB
580 lines
13 KiB
|
3 months ago
|
# A股智投分析平台 - 部署文档
|
||
|
|
|
||
|
|
## 一、前端部署
|
||
|
|
|
||
|
|
### 1.1 构建
|
||
|
|
|
||
|
|
```bash
|
||
|
|
cd /mnt/okcomputer/output/app
|
||
|
|
|
||
|
|
# 安装依赖
|
||
|
|
npm install
|
||
|
|
|
||
|
|
# 开发模式
|
||
|
|
npm run dev
|
||
|
|
|
||
|
|
# 构建生产版本
|
||
|
|
npm run build
|
||
|
|
```
|
||
|
|
|
||
|
|
### 1.2 构建输出
|
||
|
|
|
||
|
|
构建完成后,文件位于 `dist/` 目录:
|
||
|
|
|
||
|
|
```
|
||
|
|
dist/
|
||
|
|
├── index.html # 入口HTML
|
||
|
|
├── assets/
|
||
|
|
│ ├── index-xxx.js # JS bundle
|
||
|
|
│ ├── index-xxx.css # CSS bundle
|
||
|
|
│ └── ...
|
||
|
|
└── ...
|
||
|
|
```
|
||
|
|
|
||
|
|
### 1.3 部署方式
|
||
|
|
|
||
|
|
#### 方式一: 静态服务器
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# 使用 serve
|
||
|
|
npx serve dist
|
||
|
|
|
||
|
|
# 使用 Python
|
||
|
|
python -m http.server 8080 --directory dist
|
||
|
|
|
||
|
|
# 使用 Nginx
|
||
|
|
cp -r dist/* /var/www/html/
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 方式二: Nginx 配置
|
||
|
|
|
||
|
|
```nginx
|
||
|
|
server {
|
||
|
|
listen 80;
|
||
|
|
server_name aguzhitou.com;
|
||
|
|
|
||
|
|
root /var/www/aguzhitou;
|
||
|
|
index index.html;
|
||
|
|
|
||
|
|
location / {
|
||
|
|
try_files $uri $uri/ /index.html;
|
||
|
|
}
|
||
|
|
|
||
|
|
location /assets {
|
||
|
|
expires 1y;
|
||
|
|
add_header Cache-Control "public, immutable";
|
||
|
|
}
|
||
|
|
|
||
|
|
# Gzip压缩
|
||
|
|
gzip on;
|
||
|
|
gzip_types text/plain text/css application/json application/javascript;
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 方式三: CDN 部署
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# 阿里云 OSS
|
||
|
|
ossutil cp -r dist/ oss://aguzhitou-bucket/
|
||
|
|
|
||
|
|
# 腾讯云 COS
|
||
|
|
coscmd upload -r dist/ /
|
||
|
|
|
||
|
|
# AWS S3
|
||
|
|
aws s3 sync dist/ s3://aguzhitou-bucket/
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 方式四: Docker 部署
|
||
|
|
|
||
|
|
```dockerfile
|
||
|
|
# Dockerfile
|
||
|
|
FROM nginx:alpine
|
||
|
|
|
||
|
|
COPY dist/ /usr/share/nginx/html/
|
||
|
|
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||
|
|
|
||
|
|
EXPOSE 80
|
||
|
|
|
||
|
|
CMD ["nginx", "-g", "daemon off;"]
|
||
|
|
```
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# 构建镜像
|
||
|
|
docker build -t aguzhitou-frontend .
|
||
|
|
|
||
|
|
# 运行容器
|
||
|
|
docker run -d -p 80:80 --name aguzhitou-frontend aguzhitou-frontend
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 二、后端部署
|
||
|
|
|
||
|
|
### 2.1 环境准备
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# 安装 Node.js 20
|
||
|
|
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
|
||
|
|
sudo apt-get install -y nodejs
|
||
|
|
|
||
|
|
# 安装 MySQL
|
||
|
|
sudo apt-get install mysql-server
|
||
|
|
|
||
|
|
# 安装 Redis
|
||
|
|
sudo apt-get install redis-server
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2.2 数据库初始化
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# 创建数据库
|
||
|
|
mysql -u root -p
|
||
|
|
|
||
|
|
CREATE DATABASE aguzhitou CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||
|
|
CREATE USER 'aguzhitou'@'localhost' IDENTIFIED BY 'your-password';
|
||
|
|
GRANT ALL PRIVILEGES ON aguzhitou.* TO 'aguzhitou'@'localhost';
|
||
|
|
FLUSH PRIVILEGES;
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2.3 后端部署
|
||
|
|
|
||
|
|
```bash
|
||
|
|
cd backend
|
||
|
|
|
||
|
|
# 安装依赖
|
||
|
|
npm install
|
||
|
|
|
||
|
|
# 生成 Prisma Client
|
||
|
|
npx prisma generate
|
||
|
|
|
||
|
|
# 执行数据库迁移
|
||
|
|
npx prisma migrate deploy
|
||
|
|
|
||
|
|
# 构建
|
||
|
|
npm run build
|
||
|
|
|
||
|
|
# 启动
|
||
|
|
npm start
|
||
|
|
|
||
|
|
# 或使用 PM2
|
||
|
|
pm2 start dist/app.js --name aguzhitou-api
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2.4 Docker Compose 部署
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# 启动所有服务
|
||
|
|
docker-compose up -d
|
||
|
|
|
||
|
|
# 查看日志
|
||
|
|
docker-compose logs -f app
|
||
|
|
|
||
|
|
# 停止服务
|
||
|
|
docker-compose down
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 三、完整部署架构
|
||
|
|
|
||
|
|
```
|
||
|
|
┌─────────────────────────────────────┐
|
||
|
|
│ 用户 │
|
||
|
|
└─────────────────────────────────────┘
|
||
|
|
│
|
||
|
|
▼
|
||
|
|
┌─────────────────────────────────────┐
|
||
|
|
│ CDN (静态资源) │
|
||
|
|
│ 阿里云/腾讯云/AWS │
|
||
|
|
└─────────────────────────────────────┘
|
||
|
|
│
|
||
|
|
▼
|
||
|
|
┌─────────────────────────────────────┐
|
||
|
|
│ Nginx (负载均衡) │
|
||
|
|
│ 反向代理 + SSL │
|
||
|
|
└─────────────────────────────────────┘
|
||
|
|
│
|
||
|
|
┌───────────────────┼───────────────────┐
|
||
|
|
│ │ │
|
||
|
|
▼ ▼ ▼
|
||
|
|
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
|
||
|
|
│ Frontend 1 │ │ Frontend 2 │ │ Frontend 3 │
|
||
|
|
│ (Nginx) │ │ (Nginx) │ │ (Nginx) │
|
||
|
|
└────────┬─────────┘ └────────┬─────────┘ └────────┬─────────┘
|
||
|
|
│ │ │
|
||
|
|
└─────────────────────┼─────────────────────┘
|
||
|
|
│
|
||
|
|
▼
|
||
|
|
┌──────────────────────────┐
|
||
|
|
│ Backend API │
|
||
|
|
│ (Node.js) │
|
||
|
|
│ x3 实例 │
|
||
|
|
└───────────┬──────────────┘
|
||
|
|
│
|
||
|
|
┌────────────────┼────────────────┐
|
||
|
|
│ │ │
|
||
|
|
▼ ▼ ▼
|
||
|
|
┌──────────────────┐ ┌──────────────┐ ┌──────────────┐
|
||
|
|
│ MySQL 主从 │ │ Redis │ │ WebSocket │
|
||
|
|
│ (主库+从库) │ │ Cluster │ │ Server │
|
||
|
|
└──────────────────┘ └──────────────┘ └──────────────┘
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 四、环境配置
|
||
|
|
|
||
|
|
### 4.1 生产环境变量
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# /etc/environment
|
||
|
|
|
||
|
|
# 应用配置
|
||
|
|
NODE_ENV=production
|
||
|
|
PORT=3000
|
||
|
|
|
||
|
|
# 数据库
|
||
|
|
DATABASE_URL=mysql://aguzhitou:password@localhost:3306/aguzhitou
|
||
|
|
|
||
|
|
# Redis
|
||
|
|
REDIS_URL=redis://localhost:6379
|
||
|
|
|
||
|
|
# JWT
|
||
|
|
JWT_SECRET=your-super-secret-key-min-32-characters
|
||
|
|
JWT_EXPIRES_IN=7d
|
||
|
|
|
||
|
|
# 日志
|
||
|
|
LOG_LEVEL=info
|
||
|
|
|
||
|
|
# 外部API
|
||
|
|
AKSHARE_URL=http://localhost:8000
|
||
|
|
```
|
||
|
|
|
||
|
|
### 4.2 Nginx 完整配置
|
||
|
|
|
||
|
|
```nginx
|
||
|
|
# /etc/nginx/nginx.conf
|
||
|
|
|
||
|
|
user nginx;
|
||
|
|
worker_processes auto;
|
||
|
|
error_log /var/log/nginx/error.log warn;
|
||
|
|
pid /var/run/nginx.pid;
|
||
|
|
|
||
|
|
events {
|
||
|
|
worker_connections 1024;
|
||
|
|
}
|
||
|
|
|
||
|
|
http {
|
||
|
|
include /etc/nginx/mime.types;
|
||
|
|
default_type application/octet-stream;
|
||
|
|
|
||
|
|
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||
|
|
'$status $body_bytes_sent "$http_referer" '
|
||
|
|
'"$http_user_agent" "$http_x_forwarded_for"';
|
||
|
|
|
||
|
|
access_log /var/log/nginx/access.log main;
|
||
|
|
|
||
|
|
sendfile on;
|
||
|
|
tcp_nopush on;
|
||
|
|
tcp_nodelay on;
|
||
|
|
keepalive_timeout 65;
|
||
|
|
types_hash_max_size 2048;
|
||
|
|
|
||
|
|
# 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;
|
||
|
|
|
||
|
|
# 前端
|
||
|
|
server {
|
||
|
|
listen 80;
|
||
|
|
server_name aguzhitou.com www.aguzhitou.com;
|
||
|
|
|
||
|
|
# 重定向到 HTTPS
|
||
|
|
return 301 https://$server_name$request_uri;
|
||
|
|
}
|
||
|
|
|
||
|
|
server {
|
||
|
|
listen 443 ssl http2;
|
||
|
|
server_name aguzhitou.com www.aguzhitou.com;
|
||
|
|
|
||
|
|
ssl_certificate /etc/nginx/ssl/aguzhitou.crt;
|
||
|
|
ssl_certificate_key /etc/nginx/ssl/aguzhitou.key;
|
||
|
|
ssl_protocols TLSv1.2 TLSv1.3;
|
||
|
|
ssl_ciphers HIGH:!aNULL:!MD5;
|
||
|
|
|
||
|
|
root /var/www/aguzhitou;
|
||
|
|
index index.html;
|
||
|
|
|
||
|
|
location / {
|
||
|
|
try_files $uri $uri/ /index.html;
|
||
|
|
expires -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
location /assets {
|
||
|
|
expires 1y;
|
||
|
|
add_header Cache-Control "public, immutable";
|
||
|
|
}
|
||
|
|
|
||
|
|
# API 代理
|
||
|
|
location /api {
|
||
|
|
proxy_pass http://localhost:3000;
|
||
|
|
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;
|
||
|
|
}
|
||
|
|
|
||
|
|
# WebSocket 代理
|
||
|
|
location /ws {
|
||
|
|
proxy_pass http://localhost:3001;
|
||
|
|
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;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 五、SSL 证书配置
|
||
|
|
|
||
|
|
### 5.1 Let's Encrypt 免费证书
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# 安装 Certbot
|
||
|
|
sudo apt-get install certbot python3-certbot-nginx
|
||
|
|
|
||
|
|
# 获取证书
|
||
|
|
sudo certbot --nginx -d aguzhitou.com -d www.aguzhitou.com
|
||
|
|
|
||
|
|
# 自动续期
|
||
|
|
sudo certbot renew --dry-run
|
||
|
|
```
|
||
|
|
|
||
|
|
### 5.2 阿里云 SSL 证书
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# 下载证书并放置到
|
||
|
|
/etc/nginx/ssl/
|
||
|
|
├── aguzhitou.crt
|
||
|
|
└── aguzhitou.key
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 六、监控与日志
|
||
|
|
|
||
|
|
### 6.1 PM2 进程管理
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# 安装
|
||
|
|
npm install -g pm2
|
||
|
|
|
||
|
|
# 启动
|
||
|
|
pm2 start dist/app.js --name aguzhitou-api
|
||
|
|
|
||
|
|
# 查看状态
|
||
|
|
pm2 status
|
||
|
|
|
||
|
|
# 查看日志
|
||
|
|
pm2 logs aguzhitou-api
|
||
|
|
|
||
|
|
# 重启
|
||
|
|
pm2 restart aguzhitou-api
|
||
|
|
|
||
|
|
# 保存配置
|
||
|
|
pm2 save
|
||
|
|
pm2 startup
|
||
|
|
```
|
||
|
|
|
||
|
|
### 6.2 日志收集 (ELK)
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
# docker-compose.logging.yml
|
||
|
|
version: '3.8'
|
||
|
|
|
||
|
|
services:
|
||
|
|
elasticsearch:
|
||
|
|
image: docker.elastic.co/elasticsearch/elasticsearch:8.0.0
|
||
|
|
environment:
|
||
|
|
- discovery.type=single-node
|
||
|
|
volumes:
|
||
|
|
- es_data:/usr/share/elasticsearch/data
|
||
|
|
|
||
|
|
logstash:
|
||
|
|
image: docker.elastic.co/logstash/logstash:8.0.0
|
||
|
|
volumes:
|
||
|
|
- ./logstash.conf:/usr/share/logstash/pipeline/logstash.conf
|
||
|
|
|
||
|
|
kibana:
|
||
|
|
image: docker.elastic.co/kibana/kibana:8.0.0
|
||
|
|
ports:
|
||
|
|
- "5601:5601"
|
||
|
|
|
||
|
|
volumes:
|
||
|
|
es_data:
|
||
|
|
```
|
||
|
|
|
||
|
|
### 6.3 监控告警 (Prometheus + Grafana)
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
# docker-compose.monitoring.yml
|
||
|
|
version: '3.8'
|
||
|
|
|
||
|
|
services:
|
||
|
|
prometheus:
|
||
|
|
image: prom/prometheus
|
||
|
|
volumes:
|
||
|
|
- ./prometheus.yml:/etc/prometheus/prometheus.yml
|
||
|
|
- prometheus_data:/prometheus
|
||
|
|
ports:
|
||
|
|
- "9090:9090"
|
||
|
|
|
||
|
|
grafana:
|
||
|
|
image: grafana/grafana
|
||
|
|
volumes:
|
||
|
|
- grafana_data:/var/lib/grafana
|
||
|
|
ports:
|
||
|
|
- "3000:3000"
|
||
|
|
|
||
|
|
volumes:
|
||
|
|
prometheus_data:
|
||
|
|
grafana_data:
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 七、备份策略
|
||
|
|
|
||
|
|
### 7.1 数据库备份
|
||
|
|
|
||
|
|
```bash
|
||
|
|
#!/bin/bash
|
||
|
|
# backup.sh
|
||
|
|
|
||
|
|
BACKUP_DIR=/backup/mysql
|
||
|
|
DATE=$(date +%Y%m%d_%H%M%S)
|
||
|
|
|
||
|
|
# 备份
|
||
|
|
mysqldump -u root -p aguzhitou > $BACKUP_DIR/aguzhitou_$DATE.sql
|
||
|
|
|
||
|
|
# 压缩
|
||
|
|
gzip $BACKUP_DIR/aguzhitou_$DATE.sql
|
||
|
|
|
||
|
|
# 保留最近7天
|
||
|
|
find $BACKUP_DIR -name "*.sql.gz" -mtime +7 -delete
|
||
|
|
|
||
|
|
# 上传到云存储
|
||
|
|
ossutil cp $BACKUP_DIR/aguzhitou_$DATE.sql.gz oss://aguzhitou-backup/
|
||
|
|
```
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# 添加定时任务
|
||
|
|
crontab -e
|
||
|
|
|
||
|
|
# 每天凌晨2点备份
|
||
|
|
0 2 * * * /path/to/backup.sh
|
||
|
|
```
|
||
|
|
|
||
|
|
### 7.2 Redis 备份
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# 开启 RDB 持久化
|
||
|
|
# redis.conf
|
||
|
|
save 900 1
|
||
|
|
save 300 10
|
||
|
|
save 60 10000
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 八、故障排查
|
||
|
|
|
||
|
|
### 8.1 常见问题
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# 1. 端口被占用
|
||
|
|
sudo lsof -i :3000
|
||
|
|
sudo kill -9 <PID>
|
||
|
|
|
||
|
|
# 2. 数据库连接失败
|
||
|
|
mysql -u aguzhitou -p -h localhost
|
||
|
|
|
||
|
|
# 3. Redis 连接失败
|
||
|
|
redis-cli ping
|
||
|
|
|
||
|
|
# 4. 查看日志
|
||
|
|
tail -f /var/log/nginx/error.log
|
||
|
|
tail -f /var/log/aguzhitou/app.log
|
||
|
|
|
||
|
|
# 5. 内存不足
|
||
|
|
free -h
|
||
|
|
ps aux --sort=-%mem | head -10
|
||
|
|
```
|
||
|
|
|
||
|
|
### 8.2 性能优化
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# MySQL 优化
|
||
|
|
# /etc/mysql/mysql.conf.d/mysqld.cnf
|
||
|
|
[mysqld]
|
||
|
|
innodb_buffer_pool_size = 1G
|
||
|
|
max_connections = 200
|
||
|
|
query_cache_size = 64M
|
||
|
|
|
||
|
|
# Redis 优化
|
||
|
|
# /etc/redis/redis.conf
|
||
|
|
maxmemory 512mb
|
||
|
|
maxmemory-policy allkeys-lru
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 九、回滚策略
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# 1. 备份当前版本
|
||
|
|
cp -r /var/www/aguzhitou /var/www/aguzhitou-backup-$(date +%Y%m%d)
|
||
|
|
|
||
|
|
# 2. 部署新版本
|
||
|
|
npm run build
|
||
|
|
cp -r dist/* /var/www/aguzhitou/
|
||
|
|
|
||
|
|
# 3. 如果出现问题,回滚
|
||
|
|
cp -r /var/www/aguzhitou-backup-20240115/* /var/www/aguzhitou/
|
||
|
|
|
||
|
|
# 4. 重启服务
|
||
|
|
pm2 restart aguzhitou-api
|
||
|
|
sudo systemctl restart nginx
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 十、部署检查清单
|
||
|
|
|
||
|
|
- [ ] 服务器环境配置完成
|
||
|
|
- [ ] 数据库创建并初始化
|
||
|
|
- [ ] Redis 服务运行正常
|
||
|
|
- [ ] 后端服务部署成功
|
||
|
|
- [ ] 前端构建并部署
|
||
|
|
- [ ] Nginx 配置正确
|
||
|
|
- [ ] SSL 证书配置
|
||
|
|
- [ ] 域名解析正确
|
||
|
|
- [ ] 日志收集配置
|
||
|
|
- [ ] 监控告警配置
|
||
|
|
- [ ] 备份策略配置
|
||
|
|
- [ ] 性能测试通过
|
||
|
|
- [ ] 安全扫描通过
|