docs(deploy): single-server dual-stack test deployment plan
Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,156 @@
|
||||
# 测试服务器部署方案(国内 ECS · 单机双栈)
|
||||
|
||||
日期:2026-09-21 · 目标:把完整系统(cn 管理栈 + ov 观众栈)部署到国内测试 ECS,真实 OSS、可从外网访问、App/浏览器可联调。
|
||||
|
||||
服务器画像(已确认):国内阿里云 ECS,已装 1Panel + Docker + MySQL 容器。OSS 凭证已验证(G1 通过)。
|
||||
|
||||
**单机双栈说明**:cn 与 ov 两套栈同机部署——ov 的 MySQL 库(photo_ov)也建在同一 1Panel MySQL 实例里,sync 走本机回环连双库,**无需跨境链路**。功能与生产架构完全同构(观众走 ov、管理走 cn、跨境同步本机化),仅地域拆分这一维度被测试环境折叠。
|
||||
|
||||
---
|
||||
|
||||
## 0. 前置检查(2 分钟)
|
||||
|
||||
在 1Panel 终端执行:
|
||||
|
||||
```bash
|
||||
# MySQL 版本必须 ≥ 8.0.30(utf8mb4_0900_bin 校对门槛,需求 §5/D12)
|
||||
docker exec $(docker ps --format '{{.Names}}' | grep -i mysql | head -1) mysql -uroot -p'你的MySQL root密码' -e "SELECT VERSION();"
|
||||
# Redis 是否已装(应用商店装一个即可,记下容器名)
|
||||
docker ps --format '{{.Names}}' | grep -i redis || echo "需要装 Redis(1Panel 应用商店 → Redis,任意版本)"
|
||||
```
|
||||
|
||||
版本 < 8.0.30 → 先升级 MySQL 容器或改用 utf8mb4_bin(改 infra 迁移脚本四处 CREATE TABLE 的 collation + 重建本地验证,通知我处理)。
|
||||
|
||||
## 1. 本地导出镜像(开发机执行)
|
||||
|
||||
```bash
|
||||
cd /d/project/photo
|
||||
TAG=test-20260921
|
||||
docker build -f docker/server.Dockerfile -t photo-live-server:$TAG .
|
||||
docker build -f docker/web.Dockerfile -t photo-live-web:$TAG .
|
||||
docker save photo-live-server:$TAG photo-live-web:$TAG | gzip > /d/photo-live-$TAG.tar.gz
|
||||
ls -lh /d/photo-live-$TAG.tar.gz # 约 700-900MB(gzip 后)
|
||||
```
|
||||
|
||||
## 2. 传输与导入
|
||||
|
||||
```bash
|
||||
# 开发机 → 服务器(1Panel 终端也能看 scp 命令;或用宝塔式上传到 /opt)
|
||||
scp /d/photo-live-test-20260921.tar.gz root@<服务器IP>:/opt/
|
||||
|
||||
# 服务器上导入
|
||||
docker load < /opt/photo-live-test-20260921.tar.gz
|
||||
docker images | grep photo-live # 确认两个镜像
|
||||
```
|
||||
|
||||
## 3. MySQL 建库授权(1Panel 终端)
|
||||
|
||||
```sql
|
||||
-- 1Panel → 数据库 → 终端,或 docker exec 进 MySQL 容器
|
||||
CREATE DATABASE photo_cn CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_bin;
|
||||
CREATE DATABASE photo_ov CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_bin;
|
||||
CREATE USER 'photo'@'%' IDENTIFIED BY '<给 photo 用户设一个强密码>';
|
||||
GRANT ALL PRIVILEGES ON photo_cn.* TO 'photo'@'%';
|
||||
GRANT ALL PRIVILEGES ON photo_ov.* TO 'photo'@'%';
|
||||
FLUSH PRIVILEGES;
|
||||
```
|
||||
|
||||
Redis:1Panel 应用商店装 Redis(无密码即可起步;容器在 1panel-network 网络里,服务经容器名访问)。
|
||||
|
||||
## 4. 目录与 env(服务器执行)
|
||||
|
||||
```bash
|
||||
mkdir -p /opt/photo-live && cd /opt/photo-live
|
||||
```
|
||||
|
||||
**`.env.cn`**(关键项;完整清单见仓库 `.env.production.example-cn`——复制后改以下值):
|
||||
|
||||
```env
|
||||
# 数据库:容器名取决于 1Panel 实例名(docker ps 查,替换 mysql 的实际容器名)
|
||||
DATABASE_URL_CN=mysql://photo:<上面设的密码>@<mysql容器名>:3306/photo_cn?connection_limit=10
|
||||
DATABASE_URL_OV=mysql://photo:<密码>@<mysql容器名>:3306/photo_ov?connection_limit=10
|
||||
REDIS_URL_CN=redis://<redis容器名>:6379
|
||||
# OSS(G1 已验证的定案形态)
|
||||
S3_ENDPOINT=https://oss-cn-beijing.aliyuncs.com
|
||||
S3_REGION=oss-cn-beijing
|
||||
S3_ACCESS_KEY=<你的AK>
|
||||
S3_SECRET_KEY=<你的SK>
|
||||
S3_BUCKET=live-album
|
||||
S3_FORCE_PATH_STYLE=false
|
||||
# 同步密钥(生成:openssl rand -hex 32)
|
||||
SYNC_INTERNAL_KEY=<openssl rand -hex 32 的结果>
|
||||
OV_API_URL=http://api-cn:8081 # 同机:sync 直连 api-ov 容器
|
||||
CN_API_URL=http://api-cn:8080
|
||||
PORT=8080
|
||||
PORT_OV=8081
|
||||
# 管理员种子
|
||||
ADMIN_ACCOUNT=admin
|
||||
ADMIN_PASSWORD=<设一个初始管理员密码>
|
||||
# 测试环境:允许跨源(有正式域名后收窄)
|
||||
CORS_ORIGINS=*
|
||||
```
|
||||
|
||||
**`.env.ov`**:同文件的 OSS 段 + `DATABASE_URL_OV` + `REDIS_URL_OV=redis://<redis容器名>:6379` + `PORT_OV=8081`(完整清单见 `.env.production.example-ov`)。
|
||||
|
||||
## 5. 编排启动
|
||||
|
||||
把仓库的 `infra/deploy/docker-compose-cn.yml`、`docker-compose-ov.yml` 上传到 `/opt/photo-live/`,然后:
|
||||
|
||||
```bash
|
||||
cd /opt/photo-live
|
||||
# 1Panel → 容器 → 编排 → 创建 → 粘贴 compose 内容(界面化路径)
|
||||
# 或命令行(compose 文件里 SERVER_IMAGE/WEB_IMAGE 环境变量指定 tag):
|
||||
SERVER_IMAGE=photo-live-server:test-20260921 WEB_IMAGE=photo-live-web:test-20260921 \
|
||||
docker compose -f docker-compose-cn.yml up -d
|
||||
SERVER_IMAGE=photo-live-server:test-20260921 WEB_IMAGE=photo-live-web:test-20260921 \
|
||||
docker compose -f docker-compose-ov.yml up -d
|
||||
```
|
||||
|
||||
compose 默认连接 `1panel-network` 外部网络;若你的网络名不同(`docker network ls` 查),改 compose 尾部 networks 段。
|
||||
|
||||
## 6. 数据库迁移 + 管理员种子(一次性)
|
||||
|
||||
```bash
|
||||
docker run --rm --network 1panel-network --env-file .env.cn \
|
||||
photo-live-server:test-20260921 migrate-deploy all
|
||||
docker run --rm --network 1panel-network --env-file .env.cn \
|
||||
photo-live-server:test-20260921 seed-admin
|
||||
```
|
||||
|
||||
## 7. 验证(冒烟四点)
|
||||
|
||||
```bash
|
||||
# 服务器上:
|
||||
bash scripts/prod-smoke.sh http://127.0.0.1:8080 http://127.0.0.1:8081 admin '<ADMIN_PASSWORD>'
|
||||
# 开发机上(外网可达性;先在 ECS 安全组放行 8088/8089):
|
||||
curl http://<服务器IP>:8088/v1/health
|
||||
curl http://<服务器IP>:8089/v1/health
|
||||
```
|
||||
|
||||
通过标志:四点全 PASS + 两个 health 返回 `{"status":"ok"}`。
|
||||
|
||||
## 8. 访问入口与联调
|
||||
|
||||
| 入口 | 地址 | 用途 |
|
||||
|---|---|---|
|
||||
| 观众页(走 ov 栈,真实观众链路) | `http://<IP>:8089/a/<token>` | 浏览/点赞/气泡/热门 |
|
||||
| 管理后台(cn 栈) | `http://<IP>:8088/admin/` | 全功能后台 |
|
||||
| 观众页(cn 只读形态) | `http://<IP>:8088/a/<token>` | 备用 |
|
||||
| App | 构建时 `--dart-define API_BASE=http://<IP>:8080` 或装 debug 包后改配置 | 真机联调 |
|
||||
| 嵌入组件 | 宿主页引 `http://<IP>:8089/embed/v1/loader.js` | 官网接入形态 |
|
||||
|
||||
后续上正式域名:1Panel → 网站 → OpenResty 反代 8088/8089 + 证书,env 的 CORS_ORIGINS 收窄为域名,无需改代码。
|
||||
|
||||
## 9. 安全与运维注意(测试环境基线)
|
||||
|
||||
- 安全组只放行 8088/8089(web);8080/8081/3306/6379 不对公网开放(web 容器同机反代 /v1)。
|
||||
- `.env.cn/.env.ov` 权限 `chmod 600`;AK 建议按此前提醒在稳定后轮换。
|
||||
- 日志:compose 已配 json-file 10m×3;看实时 `docker logs -f photo-api-cn`。
|
||||
- 回滚:`SERVER_IMAGE` 换回旧 tag `docker compose up -d` 即可(迁移向前兼容原则,详见 RUNBOOK.md)。
|
||||
|
||||
---
|
||||
|
||||
## 执行分工(二选一)
|
||||
|
||||
- **你执行**:按 0→8 逐步粘贴(约 30-40 分钟,大头是镜像传输);卡在任何一步叫我。
|
||||
- **我执行**:提供 SSH 访问方式(密钥/密码经安全渠道),我在服务器上跑完全部步骤并回报冒烟结果;镜像 tar 我先在本机备好。
|
||||
Reference in New Issue
Block a user