Skip to content

Commit de6c9d5

Browse files
author
huangyf
committed
chore: crawler tools, Docker deployment configs, nginx reverse proxy, production migration guide
1 parent 3e19682 commit de6c9d5

10 files changed

Lines changed: 1017 additions & 32 deletions

File tree

.env.example

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# ============================================================
2+
# Gying Movie - Production Environment Variables
3+
# ============================================================
4+
# Copy this file to .env and fill in your actual values.
5+
# NEVER commit .env to git!
6+
# ============================================================
7+
8+
# --- Database (Cloud MySQL) ---
9+
DB_HOST=your-cloud-mysql-host.com
10+
DB_PORT=3306
11+
DB_NAME=gying
12+
DB_USER=gying_app
13+
DB_PASSWORD=your-strong-db-password
14+
15+
# --- Redis ---
16+
REDIS_HOST=redis
17+
REDIS_PORT=6379
18+
REDIS_PASSWORD=gyingredis2024
19+
20+
# --- Image Storage (Cloud OSS / S3) ---
21+
# Alibaba Cloud OSS example:
22+
# MINIO_URL_PREFIX=https://gying-images.oss-cn-hangzhou.aliyuncs.com/
23+
# Tencent Cloud COS example:
24+
# MINIO_URL_PREFIX=https://gying-images-1234567890.cos.ap-shanghai.myqcloud.com/
25+
# Keep using MinIO:
26+
# MINIO_URL_PREFIX=https://minio.yourdomain.com/gying/
27+
MINIO_URL_PREFIX=https://your-cdn-or-oss-domain.com/
28+
29+
# --- CORS ---
30+
# Your production frontend domain
31+
CORS_ALLOWED_ORIGIN=https://yourdomain.com
32+
33+
# --- JWT ---
34+
# IMPORTANT: Generate a strong random secret (at least 32 bytes)
35+
# Example: openssl rand -base64 48
36+
JWT_SECRET=REPLACE_WITH_A_STRONG_RANDOM_SECRET_AT_LEAST_32_BYTES
37+
JWT_EXPIRATION_MS=86400000

MIGRATION.md

Lines changed: 348 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,348 @@
1+
# Gying Movie 上线迁移指南
2+
3+
> 本文档覆盖从本地开发环境迁移到云端生产环境的完整流程。
4+
5+
---
6+
7+
## 一、当前架构总览
8+
9+
```
10+
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
11+
│ Next.js 16 │───▶│ Spring Boot │───▶│ MySQL │
12+
│ (Port 3000) │ │ (Port 8880) │ │ (Port 3306) │
13+
└──────────────┘ └──────┬───────┘ └──────────────┘
14+
15+
┌──────▼───────┐ ┌──────────────┐
16+
│ Redis │ │ MinIO │
17+
│ (Port 6379) │ │ (Port 9000) │
18+
└──────────────┘ └──────────────┘
19+
```
20+
21+
**本地环境配置:**
22+
- MySQL: `localhost:3306`,用户 `root`,数据库 `gying`
23+
- Redis: `localhost:6379`,无密码
24+
- MinIO: Docker 容器 `minio-server`,端口 `9000-9001`,桶名 `gying`
25+
- 图片存储路径: `gying/{category}/{movieId}/384.avif`
26+
27+
---
28+
29+
## 二、生产架构(推荐)
30+
31+
```
32+
┌─────────────────────────────┐
33+
│ Nginx │
34+
│ (80/443 + SSL 终止) │
35+
│ /api/** → Backend │
36+
│ /* → Frontend │
37+
└──────┬──────────┬───────────┘
38+
│ │
39+
┌──────▼───┐ ┌───▼──────────┐
40+
│ Next.js │ │ Spring Boot │
41+
│ (容器) │ │ (容器) │
42+
└──────────┘ └──┬─────┬──────┘
43+
│ │
44+
┌────────▼┐ ┌──▼──────────┐
45+
│ Cloud │ │ Cloud Redis │
46+
│ MySQL │ │ │
47+
└─────────┘ └──────────────┘
48+
49+
图片 CDN/OSS ← 用户浏览器直接访问(不经过 Nginx)
50+
```
51+
52+
---
53+
54+
## 三、数据库迁移(MySQL → 云端 MySQL)
55+
56+
### 3.1 推荐的云数据库服务
57+
58+
| 云厂商 | 产品 | 最低规格 | 参考价格 |
59+
|--------|------|---------|---------|
60+
| 阿里云 | RDS MySQL | 1核1G | ~¥50/月 |
61+
| 腾讯云 | CDB MySQL | 1核1G | ~¥45/月 |
62+
| 华为云 | RDS MySQL | 1核1G | ~¥50/月 |
63+
64+
### 3.2 导出数据
65+
66+
在本地 WSL 或 Docker 中执行:
67+
68+
```bash
69+
# 导出整个数据库(含数据)
70+
mysqldump -u root -p'Root@123' \
71+
--single-transaction \
72+
--routines \
73+
--triggers \
74+
--set-gtid-purged=OFF \
75+
gying > gying_backup_$(date +%Y%m%d).sql
76+
77+
# 只导出表结构(不含数据,用于初始化)
78+
mysqldump -u root -p'Root@123' --no-data gying > gying_schema.sql
79+
```
80+
81+
### 3.3 云端数据库初始化
82+
83+
```bash
84+
# 1. 创建数据库和用户
85+
mysql -h <cloud-host> -u <admin-user> -p <<EOF
86+
CREATE DATABASE gying CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
87+
CREATE USER 'gying_app'@'%' IDENTIFIED BY '<strong-password>';
88+
GRANT ALL PRIVILEGES ON gying.* TO 'gying_app'@'%';
89+
FLUSH PRIVILEGES;
90+
EOF
91+
92+
# 2. 导入数据
93+
mysql -h <cloud-host> -u gying_app -p gying < gying_backup_20260611.sql
94+
```
95+
96+
### 3.4 注意事项
97+
98+
- 云端 MySQL 一般**强制 SSL**`application-prod.yml` 已配置 `useSSL=true`
99+
- 创建专用数据库用户,**不要用 root**
100+
- 确保 `serverTimezone=Asia/Shanghai`
101+
- 建议开启自动备份(云厂商一般提供)
102+
103+
---
104+
105+
## 四、图片存储迁移(MinIO → 云端 OSS)
106+
107+
### 4.1 方案对比
108+
109+
| 方案 | 优点 | 缺点 |
110+
|------|------|------|
111+
| **阿里云 OSS** | 国内速度快、CDN 集成好 | 需备案域名 |
112+
| **腾讯云 COS** | 与腾讯云生态集成 | 需备案域名 |
113+
| **继续用 MinIO** | 无迁移成本、S3 兼容 | 需自己维护服务器 |
114+
| **Cloudflare R2** | 免出口流量费、全球 CDN | 国内访问可能偏慢 |
115+
116+
### 4.2 迁移到阿里云 OSS(推荐)
117+
118+
#### Step 1: 创建 OSS Bucket
119+
120+
```
121+
Bucket 名称: gying-images
122+
地域: 华东1(杭州)或与云服务器同地域
123+
读写权限: 公共读(Public Read)
124+
存储类型: 标准存储
125+
```
126+
127+
#### Step 2: 批量迁移 MinIO 中的图片
128+
129+
```bash
130+
# 安装 rclone(通用 S3 迁移工具)
131+
curl https://rclone.org/install.sh | sudo bash
132+
133+
# 配置 MinIO 源
134+
rclone config create minio s3 \
135+
provider=Minio \
136+
access_key_id=admin \
137+
secret_access_key=miniopassword \
138+
endpoint=http://localhost:9000
139+
140+
# 配置阿里云 OSS 目标
141+
rclone config create alioss s3 \
142+
provider=Alibaba \
143+
access_key_id=<your-ak> \
144+
secret_access_key=<your-sk> \
145+
endpoint=https://oss-cn-hangzhou.aliyuncs.com
146+
147+
# 执行迁移(同步所有文件)
148+
rclone sync minio:gying alioss:gying-images --progress
149+
150+
# 验证
151+
rclone ls alioss:gying-images | head -20
152+
```
153+
154+
#### Step 3: 更新后端配置
155+
156+
`.env` 中设置:
157+
158+
```bash
159+
# 阿里云 OSS 公网域名
160+
MINIO_URL_PREFIX=https://gying-images.oss-cn-hangzhou.aliyuncs.com/
161+
162+
# 如果绑定了 CDN 域名(推荐)
163+
MINIO_URL_PREFIX=https://img.yourdomain.com/
164+
```
165+
166+
**无需修改后端代码!** `processMovieUrl()` 只拼接前缀,数据库中的相对路径 `tv/1Znq/384.avif` 保持不变。
167+
168+
#### Step 4: 更新爬虫脚本
169+
170+
```python
171+
# crawler/gying_crawler.py 中修改:
172+
173+
# 方案 A:直接上传到 OSS(使用 oss2 SDK)
174+
import oss2
175+
auth = oss2.Auth('<AccessKeyId>', '<AccessKeySecret>')
176+
bucket = oss2.Bucket(auth, 'https://oss-cn-hangzhou.aliyuncs.com', 'gying-images')
177+
178+
def upload_image_to_oss(type_code, movie_id):
179+
object_name = f"{type_code}/{movie_id}/384.avif"
180+
target_url = f"https://s.tutu.pm/img/{type_code}/{movie_id}/384.avif"
181+
resp = requests.get(target_url, headers=HEADERS, timeout=10)
182+
if resp.status_code == 200:
183+
bucket.put_object(object_name, resp.content)
184+
return object_name
185+
186+
# 方案 B:继续使用 MinIO + rclone 定期同步
187+
# 保持现有爬虫不变,用 crontab 定期 rclone sync
188+
```
189+
190+
---
191+
192+
## 五、应用部署
193+
194+
### 5.1 服务器准备
195+
196+
推荐配置(入门级):
197+
198+
| 项目 | 规格 |
199+
|------|------|
200+
| CPU | 2 核 |
201+
| 内存 | 4 GB |
202+
| 系统盘 | 50 GB SSD |
203+
| 带宽 | 3-5 Mbps(或按量付费) |
204+
| 系统 | Ubuntu 22.04 / Debian 12 |
205+
206+
### 5.2 安装 Docker
207+
208+
```bash
209+
# 安装 Docker + Docker Compose
210+
curl -fsSL https://get.docker.com | sh
211+
sudo usermod -aG docker $USER
212+
213+
# 验证
214+
docker --version
215+
docker compose version
216+
```
217+
218+
### 5.3 部署应用
219+
220+
```bash
221+
# 1. 上传项目到服务器
222+
scp -r ./gying-movie user@server:/opt/
223+
224+
# 2. SSH 到服务器
225+
ssh user@server
226+
227+
# 3. 配置环境变量
228+
cd /opt/gying-movie
229+
cp .env.example .env
230+
nano .env # 填入实际值
231+
232+
# 4. 构建并启动
233+
docker compose -f docker-compose.prod.yml up -d --build
234+
235+
# 5. 检查状态
236+
docker compose -f docker-compose.prod.yml ps
237+
docker compose -f docker-compose.prod.yml logs -f backend
238+
```
239+
240+
### 5.4 配置 HTTPS
241+
242+
```bash
243+
# 使用 Let's Encrypt 免费证书
244+
apt install certbot
245+
certbot certonly --standalone -d yourdomain.com
246+
247+
# 将证书复制到 nginx 目录
248+
mkdir -p nginx/ssl
249+
cp /etc/letsencrypt/live/yourdomain.com/fullchain.pem nginx/ssl/
250+
cp /etc/letsencrypt/live/yourdomain.com/privkey.pem nginx/ssl/
251+
252+
# 取消 nginx.conf 中 HTTPS 部分的注释,然后重启
253+
docker compose -f docker-compose.prod.yml restart nginx
254+
255+
# 设置自动续期
256+
crontab -e
257+
# 添加:0 3 * * * certbot renew --quiet && docker compose -f /opt/gying-movie/docker-compose.prod.yml restart nginx
258+
```
259+
260+
---
261+
262+
## 六、环境变量速查表
263+
264+
| 变量 | 说明 | 示例值 |
265+
|------|------|--------|
266+
| `DB_HOST` | 云端 MySQL 地址 | `rm-xxx.mysql.rds.aliyuncs.com` |
267+
| `DB_PORT` | MySQL 端口 | `3306` |
268+
| `DB_NAME` | 数据库名 | `gying` |
269+
| `DB_USER` | 数据库用户 | `gying_app` |
270+
| `DB_PASSWORD` | 数据库密码 | `***` |
271+
| `REDIS_HOST` | Redis 地址 | `redis`(compose 内部) |
272+
| `REDIS_PASSWORD` | Redis 密码 | `***` |
273+
| `MINIO_URL_PREFIX` | 图片 URL 前缀 | `https://img.yourdomain.com/` |
274+
| `CORS_ALLOWED_ORIGIN` | 允许的前端域名 | `https://yourdomain.com` |
275+
| `JWT_SECRET` | JWT 签名密钥 | `openssl rand -base64 48` 生成 |
276+
| `JWT_EXPIRATION_MS` | Token 过期时间 | `86400000`(24小时) |
277+
278+
---
279+
280+
## 七、上线前检查清单
281+
282+
### 安全项
283+
- [ ] JWT Secret 已替换为强随机值(≥32 字节)
284+
- [ ] 数据库密码已修改,不使用 root 用户
285+
- [ ] Redis 设置了密码
286+
- [ ] `.env` 文件未提交到 Git(已在 `.gitignore` 中)
287+
- [ ] CORS 仅允许生产域名,移除了 `http://localhost:*`
288+
- [ ] HTTPS 已启用
289+
290+
### 数据项
291+
- [ ] 数据库已导入到云端 MySQL
292+
- [ ] MinIO 图片已同步到 OSS
293+
- [ ] `MINIO_URL_PREFIX` 指向正确的 CDN/OSS 域名
294+
- [ ] 测试了图片加载是否正常
295+
296+
### 功能验证
297+
- [ ] 首页电影列表加载正常
298+
- [ ] 电影详情页显示完整
299+
- [ ] 搜索功能正常
300+
- [ ] 登录/注册功能正常
301+
- [ ] 发表评论/回复正常
302+
- [ ] 资源下载链接可点击
303+
- [ ] 管理后台功能正常
304+
305+
### 性能项
306+
- [ ] Nginx Gzip 压缩已开启
307+
- [ ] 静态资源缓存已配置(30天)
308+
- [ ] HikariCP 连接池参数合理
309+
310+
---
311+
312+
## 八、后续优化建议
313+
314+
| 优先级 | 项目 | 说明 |
315+
|--------|------|------|
316+
| P1 | **接口缓存** | 电影列表/详情加 Redis 缓存,TTL 10-30 分钟,降低数据库压力 |
317+
| P1 | **图片懒加载** | 首页 MovieCard 使用 `loading="lazy"` + 低质量占位图 |
318+
| P2 | **全文搜索** | 接入 Elasticsearch 替代 `LIKE` 模糊查询,提升搜索精度和速度 |
319+
| P2 | **CDN 加速** | 前端静态资源上 CDN(Vercel / Cloudflare Pages) |
320+
| P2 | **日志监控** | 接入阿里云 SLS 或 Grafana + Loki,实时监控错误和性能 |
321+
| P3 | **CI/CD** | GitHub Actions 自动构建 Docker 镜像并部署 |
322+
| P3 | **定时任务** | 资源链接有效性检测,自动标记失效链接 |
323+
| P3 | **国际化完善** | 补充缺失的翻译 key,增加日语等语言 |
324+
325+
---
326+
327+
## 九、常用运维命令
328+
329+
```bash
330+
# 查看所有服务状态
331+
docker compose -f docker-compose.prod.yml ps
332+
333+
# 查看后端日志(最近 100 行 + 实时跟踪)
334+
docker compose -f docker-compose.prod.yml logs -f --tail=100 backend
335+
336+
# 重启单个服务
337+
docker compose -f docker-compose.prod.yml restart backend
338+
339+
# 更新部署(拉取新代码后)
340+
git pull
341+
docker compose -f docker-compose.prod.yml up -d --build
342+
343+
# 数据库备份
344+
docker exec -it <mysql-container> mysqldump -u gying_app -p gying > backup_$(date +%Y%m%d).sql
345+
346+
# 清理无用 Docker 镜像
347+
docker image prune -f
348+
```

0 commit comments

Comments
 (0)