Files
photo-live/docs/plans/2026-09-24-正式环境双地域部署.md
T
2026-09-24 13:41:47 +08:00

12 KiB
Raw Blame History

2026-09-24 正式环境双地域部署(P5 生产上线)

状态:已执行完毕(2026-09-24,验收记录见 progress/正式环境双地域部署-验收记录.md)。 输入:用户 2026-09-24 指令;记忆双地域方案(跨境 HMAC 同步 + 安全组互白名单 + 全新空库 + 域名证书);G4 验收记录 §4.6/§4.8 全部坑位经验。 用户已拍板(2026-09-24):hnxinyouhe.com 已备案(cn 直接域名+HTTPS); 不接 CDN(A25「图片经全球 CDN」暂不满足,如实标注);OSS 复用现有桶 (G1 凭证,从测试服务器 env 取)。

0. 现状侦察结论(2026-09-24)

SSH 通道

机 IP 通道 状态
ov 境外 47.254.176.10 本机 → ProxyJump root@8.152.213.143(跳板在 ov 安全组白名单)→ root,钥匙 ~/.ssh/id_ed25519(即 cms-cj-deploy,ov 机已装过) ✅ 已通
cn 国内 101.37.116.184 本机直连 root + 同一把钥匙 ⏳ 等公钥装入 authorized_keys(用户进行中)
跳板(老国内机) 8.152.213.143 本机直连 root + 同钥匙 ✅ 已通

写入 ~/.ssh/config:photo-ov(带 ProxyJump)/ photo-cn 两个 Host 条目。

ov 机探测(已完成)

  • Debian 13 / 2C / 7.4G / 40G 盘 83% 用(剩 6.5G + docker builder prune 可回收 ~2G → 部署前清一次,够用)
  • Docker 29.4 + Compose v5.1.3;Docker Hub 直连正常(registry-1.docker.io 401=通)
  • NTP 已同步(阿里云内部 NTP,Stratum 3)——HMAC ±300s 防重放硬前提 ✓
  • 出网:aliyun intl / docker hub / gitea:25311(0.58s) / oss-hangzhou 全通
  • 跨境:ov→cn 22/443 TCP 可达 ✓
  • DNS:inside→cn、outside→ov 解析正确 ✓
  • 机上已有:1Panel 全家桶(OpenResty 占 80/443、MySQL 5.7.44@127.0.0.1:3306、Redis 8.6.2、phpMyAdmin 占 8089、php-fpm)+ tracker / cc-ai-kefu / cms-cj 等项目
  • 本机命令样例:ssh photo-ov '…' / scp … photo-ov:/opt/…

坑位(G4 §4.6/§4.8 经验,全部纳入流程)

  1. web 容器随 api 容器重建后必须一并 restart(nginx 缓存旧上游容器 IP → 502)。
  2. nginx:alpine 最新 digest 的 10-listen-on-ipv6 entrypoint 卡死——本次 T0 把补丁行正式进仓库 Dockerfile。
  3. 本机 Docker Hub 抽风预案:构建挪服务器(ov 直连 Hub;cn 若不通走 1Panel 加速器,探测时确认 /etc/docker/daemon.json)。
  4. MySQL 8.4 trigger/cursor 为保留字,手工 SQL 全部反引号。
  5. .env.production-* chmod 600、不入库不入镜像。

1. 目标形态

cn 101.37.116.184 (live-album.inside.hnxinyouhe.com, 已备案)
  └ photo-live-cn 栈:api-cn / worker / sync / web + 自管 mysql:8.4 + redis:7
ov 47.254.176.10 (live-album.outside.hnxinyouhe.com)
  └ photo-live-ov 栈:api-ov / web-ov + 自管 mysql:8.4 + redis:7
跨境链路:
  sync 推送/对账:cn sync → https://live-album.outside.hnxinyouhe.com(HMAC)
  统计回传读库:cn sync → 47.254.176.10:13306(ov mysql,安全组仅放行 cn IP)
入口:两机各自 1Panel OpenResty 建站点 → 反代 127.0.0.1 回环端口 → Let's Encrypt 证书

2. 任务序

T0 仓库准备(本机,先行)

  • docker/web.Dockerfile:FROM nginx:alpine 后加 RUN rm -f /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh(§4.8 事件 B 补丁正式化,钉版本列为后续待办)。
  • 服务器 compose 适配(两台各自 /opt/photo-live/deploy/,不进仓库):基于 infra/deploy/docker-compose-ov.yml / -cn.yml 改三点—— ① web 主机端口:ov 127.0.0.1:18089(8089 被 phpMyAdmin 占),cn 127.0.0.1:18088(避冲突统一 18xxx); ② 增自管服务 mysql(mysql:8.4 + utf8mb4_0900_bin + named volume)与 redis(redis:7-alpine); ③ 网络改独立桥 photo-net(不挂 1panel-network——不复用 1Panel 的 MySQL5.7/Redis)。 ov mysql 额外映射 0.0.0.0:13306:3306(跨境 sync 读库,安全组仅放行 cn IP)。
  • commit + push gitea(两台服务器 git pull 用)。
  • 验收:flutter/后端零改动,docker build 本机两镜像可构建(顺带验证 Hub 状态)。

T1 cn 环境探测(公钥装入后立即)

  • 跑与 ov 同一份探测脚本(.tmp-probe.sh):规格/系统/Docker/Compose/加速器/MySQL/NTP/时区/端口占用/出网(Hub、gitea、uniservice、oss)/跨境 cn→ov TCP。
  • 决定 cn 构建路径(本机构建传输 vs 服务器构建)与磁盘是否需清理。
  • 验收:探测记录回填本文档 §0;cn 18088/13306 无端口冲突或改用其它高位端口。

T2 ov 栈部署(先 ov——cn 的 sync 依赖 ov API 可达)

  1. mkdir -p /opt/photo-live/{src,deploy};clone gitea(凭证用令牌,clone 后 remote 去掉令牌或用 deploy 方式)。
  2. docker builder prune -f(回收 ~2G)。
  3. 写 .env.production-ov(600,全新值):
    • DATABASE_URL_OV=mysql://photo_ov:<新强密码>@mysql:3306/photo_ov?connection_limit=10
    • REDIS_URL_OV=redis://redis:6379
    • S3 四元组:从测试服务器 /opt/photo-live/deploy/.env.production-cn 抄 G1 真实值(同桶同凭证,ov 只读现签)
    • CORS_ORIGINS=https://live-album.outside.hnxinyouhe.com
    • SYNC_INTERNAL_KEY=<openssl rand -hex 32 新生成,与 cn 同值>
    • 互动/限速参数按模板缺省
  4. mysql 容器起后建库建账号: CREATE DATABASE photo_ov CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_bin; CREATE USER 'photo_ov'@'%' …GRANT ON photo_ov.*(安全组收口;sync 专用账号 photo_ov_sync@101.37.116.184 后续可拆,首期单账号+% 靠安全组白名单)。
  5. 构建/导入镜像(按 T0 验证结果选路径):
    • 路径 A:本机 docker build → save/gzip → scp -J root@8.152.213.143 直达 ov → docker load
    • 路径 B(本机 Hub 抽风):源码已在 /opt/photo-live/src(git pull)→ ov 服务器 docker build(Hub 直连已验证 OK)
    • tag 约定 <git短sha>-20260924(当前 d331d55,若 T0 有新提交以新 sha 为准);web ov 版带 VITE_VIEWER_BASE=https://live-album.outside.hnxinyouhe.com
  6. docker compose … run --rm <server image> migrate-deploy ov(迁移先于 API)。
  7. SERVER_IMAGE=… WEB_IMAGE=… docker compose -f docker-compose-ov.yml up -d;health {"status":"ok"}。
  8. 1Panel 建网站 live-album.outside.hnxinyouhe.com → 反代 127.0.0.1:18089 → Let's Encrypt 证书(HTTP-01,80 已开)→ 强制 HTTPS;反代配置确认 WebSocket 透传(/v1/realtime Upgrade 头;1Panel 反代开 websocket 选项或手补 proxy_set_header Upgrade/Connection)。
  9. 外网验证:https://live-album.outside.hnxinyouhe.com/v1/health + 观众页 404 兜底正常。
  • 验收:HTTPS 入口通、api-ov healthy、(无数据期)公开端点空态正常。
  • 回滚:docker compose down;全新空库无数据风险;1Panel 站点删除。

T3 cn 栈部署

  1. 同 T2 建目录/clone/探测磁盘。
  2. .env.production-cn(600,全新值):
    • DATABASE_URL_CN/REDIS_URL_CN → 自管容器
    • DATABASE_URL_OV=mysql://photo_ov:<ov应用账号密码>@47.254.176.10:13306/photo_ov?connection_limit=10(跨公网直连 ov mysql)
    • S3 同桶同凭证;CORS_ORIGINS=https://live-album.inside.hnxinyouhe.com
    • SYNC_INTERNAL_KEY 同 ov;CN_API_URL=http://api-cn:8080;OV_API_URL=https://live-album.outside.hnxinyouhe.com
    • USER_SYNC_SOURCE=http + uniservice URL/KEY(从测试服务器 env 抄真实值)
    • SYNC_USERS_INTERVAL_MS=43200000(12h,用户既定指令)
    • ADMIN_ACCOUNT=admin + ADMIN_PASSWORD=<新强密码>(seed 后交付用户,建议首次登录即改)
  3. mysql 建库 photo_cn(同 collate)+ 账号。
  4. 镜像同 T2(web cn 版 VITE_VIEWER_BASE=https://live-album.inside.hnxinyouhe.com)。
  5. migrate-deploy cn → seed-admin → up -d(api-cn/worker/sync/web)。
  6. sync 日志核对:推送循环启动、连 ov inbox 通(若 ov API 443 未就绪会重试——T2 已先行则应直通)。
  7. 1Panel 建站点 live-album.inside.hnxinyouhe.com → 反代 127.0.0.1:18088 → 证书(已备案,HTTP-01 可过)→ 强制 HTTPS + WS 透传。
  8. 重建 api 后 restart web 容器(坑位 ①)。
  • 验收:后台可登录(新密码)、health OK、sync 无连接错误。
  • 回滚:同 T2;RUNBOOK 换旧 tag。

T4 跨境链路验证(依赖用户安全组操作)

用户在阿里云控制台操作(唯一外部依赖):

  • ov 安全组:入方向放行 TCP/13306 ← 101.37.116.184(sync 读 ov 库); 建议加 TCP/22 ← 101.37.116.184(cn→ov 备用 SSH 通道)。
  • cn 安全组:确认 80/443 公网放行(站点要通)。

验证序:

  1. cn 容器内 mysql -h 47.254.176.10 -P 13306 连通(或 nc 探测)。
  2. 全链路:后台建相册→上传测试照片→worker 出变体→outbox→sync 推送(~2s)→ ov 公开页 https://live-album.outside…/a/<token> 看到照片、图片 presigned OSS URL 可加载。
  3. 反向:ov 页点赞→统计回传 60s→cn 库计数增长。
  4. 对账循环日志(5min 周期无 diff)。
  5. scripts/prod-smoke.sh 四点冒烟 + CORS 收窄 curl 验证(第三方 Origin 拒)。
  6. uniservice 定时同步:首批手动触发(12h 间隔下重启后首批要等——用后台「手动同步」按钮)。

T5 收尾

  • 验收记录 docs/plans/progress/ 落档(含坑位新增、A25 CDN 标注、跨境外网实测数据)。
  • 密钥交付:.env.production-* 真实文件留存两台服务器(600)+ 本机工作区(.gitignore 已排除);ADMIN 密码/DB 密码清单单独交用户保管。
  • 监控:infra/deploy/monitoring.md 告警项按现状裁剪接入(可后置)。

3. 密钥与凭据清单(全部新生成,唯一复用 = OSS/uniservice)

项 来源 存放
SYNC_INTERNAL_KEY openssl rand -hex 32 新生成 两端 .env(600)
mysql root / photo_cn / photo_ov 应用账号密码 新生成 各机 .env + mysql
ADMIN_PASSWORD 新强密码 cn .env + 交付用户
S3 四元组(同桶) 测试服务器 env 抄 两端 .env
OPEN_API_USERS_URL/KEY 测试服务器 env 抄 cn .env

4. 风险与预案

风险 预案
本机 Docker Hub 抽风(§4.8 事件 A 复发) 路径 B 服务器构建(ov 已验证 Hub 直连;cn 走加速器)
ov 磁盘 6.5G 紧张 部署前 builder prune(~2G);mysql/redis/server/web 镜像+库合计估 ~3G,余量足够;超预期则报告用户扩容
1Panel 反代丢 WS 头 手补 Upgrade/Connection 两行;实测 /v1/realtime 握手
跨境 13306 被扫 高位端口 + 安全组单 IP 白名单 + 账号强密码;后续可加 REQUIRE SSL
cn 公钥迟迟未装 T1-T3 的 cn 部分阻塞,但 T2 ov 全部可先行(本计划顺序已兼容)
测试服务器不受影响 全新机器全新库,零接触;gitea 仅读

5. 与准备件的偏差登记(部署后回填 RUNBOOK/README)

  1. compose 自管 mysql:8.4/redis(1Panel MySQL 是 5.7.44 不满足 utf8mb4_0900_bin/8.4 基线),独立 photo-net 网络。
  2. web 回环端口 18089/18088(8089 与 phpMyAdmin 冲突;18xxx 统一)。
  3. ov mysql 公网映射 13306(模板未含,跨境 sync 读库需要——白名单+SSL 待实测定案项落地)。
  4. docker/web.Dockerfile entrypoint 补丁正式化(钉 nginx 版本仍为待办)。
  5. CDN 不接(用户拍板);OSS 复用 G1 桶(用户拍板)。