feat(0.2.1): 生产切换完成 —— 单端口上线 (3001 + 内网 PG/PowerSync), 迁移 MySQL 全量数据, 补 uuid 镜像触发器
Docker Build and Push / build-image (push) Successful in 2m14s
Docker Build and Push / build-image (push) Successful in 2m14s
This commit is contained in:
+134
-3
@@ -1,8 +1,29 @@
|
||||
# 0.2.1 发布任务 — 目标与现状
|
||||
|
||||
> 最后更新:2026-10-27 07:05
|
||||
> 分支:`dev-0.2`(已推送,与 `origin/dev-0.2` 同步于 `b29be62`)
|
||||
> 状态:**代码与打包全部就绪;生产切换尚未执行(停在"镜像已构建,待起栈+迁移+切域名")**
|
||||
> 最后更新:2026-10-27 08:05
|
||||
> 分支:`dev-0.2`(已推送)
|
||||
> 状态:**生产已切换到 0.2.1 单端口架构并验证通过;剩余 "合 master 发布" 一步**
|
||||
|
||||
## 零、执行结果速览(2026-10-27 已完成)
|
||||
|
||||
| 项目 | 结果 |
|
||||
| --- | --- |
|
||||
| 生产地址 | `https://iboard.honor3.com` → baihu **3001**(NPM + 有效证书) |
|
||||
| 生产架构 | `iboard-prod-app-1`(3001 对外) + `iboard-prod-pg-1`(内网) + `iboard-prod-powersync-1`(内网) |
|
||||
| 端口 | **只剩 3001**;13001 / 13002 / 13443 全部下线 |
|
||||
| 数据迁移 | MySQL → PG 完成:Project 3、Task 25、BoardColumn 12、User 1、CheckIn 17、News 19、IndicatorPoint 245、Mihome 等全部迁入 |
|
||||
| 旧生产 | 容器 `iboard` 已 **stop(未删除)**,`docker start iboard` 可秒级回滚 |
|
||||
| 登录态 | `JWT_SECRET` 沿用 `iboard`,现有用户无需重新登录 |
|
||||
| 米家凭证 | `/app/iboard/cache` → `deploy/prod/data/cache`(`auth.txt` + `apizero/`) |
|
||||
| E2E 验证 | 在线:项目卡片 + `ADMIN-16`/`ADMIN-18` 编号;断网:徽标出现、任务页数据完整、无 fail fetch;恢复:徽标消失 |
|
||||
|
||||
### 迁移过程中踩到并修掉的坑
|
||||
|
||||
1. `prisma/migrations/` 是 **MySQL 语法**(反引号),PG 无法 `migrate deploy` → 改用 `prisma db push --accept-data-loss` 按 schema 建表。
|
||||
2. `db push` 首次因参数不被识别而输出帮助(表结构停在旧 schema,缺 `autoArchive`)→ 去掉错误参数重跑,列已补齐。
|
||||
3. 新库缺 **uuid 镜像触发器**(`projectUuid`/`columnUuid`/`parentUuid`/`taskUuid`)→ 从 0.2.1 验证库导出 5 个函数 + 5 个触发器,落库并入库 `deploy/prod/sql/uuid-triggers.sql`。
|
||||
4. bash 把 `$$` 展开成 PID 导致 TRUNCATE 脚本报错 → 改用 SQL 文件传入。
|
||||
5. baihu 上 `docker build` 缺 buildx → 改用 `docker compose build`。
|
||||
|
||||
---
|
||||
|
||||
@@ -147,6 +168,116 @@ bash /app/iboard-prod/scripts/deploy/prod.sh
|
||||
curl -s https://iboard.honor3.com/api/health
|
||||
```
|
||||
|
||||
## 五之二、后续动作执行步骤(已确认方案,按序执行)
|
||||
|
||||
### 决策确认(2026-10-27)
|
||||
|
||||
| 项 | 决定 |
|
||||
| --- | --- |
|
||||
| PG 密钥 | **不进 Gitea Secrets**,直接写在服务器 `/app/iboard-prod/deploy/prod/.env`(600) |
|
||||
| 迁移时机 | 立即执行 |
|
||||
| 米家凭证 | 保留,`/app/iboard/cache` 搬到新栈 `deploy/prod/data/cache` |
|
||||
| `JWT_SECRET` | 沿用现网值(`iboard`),保持现有登录态 |
|
||||
| 域名 | `iboard.honor3.com` → baihu **3001**(NPM 已配好,SSL 强制) |
|
||||
|
||||
### 步骤 A:准备(不改动现网)
|
||||
|
||||
```bash
|
||||
# A1. 沿用现网 JWT_SECRET (其余密钥保持已生成的随机值)
|
||||
cd /app/iboard-prod/deploy/prod
|
||||
sed -i 's/^JWT_SECRET=.*/JWT_SECRET=iboard/' .env
|
||||
|
||||
# A2. 搬米家缓存 (auth.txt 等)
|
||||
mkdir -p data/cache
|
||||
rsync -a /app/iboard/cache/ data/cache/
|
||||
|
||||
# A3. 保留旧镜像用于回滚
|
||||
docker tag iboard:latest iboard:mysql-final # 需在重新构建前执行; 若已覆盖见"回滚预案"
|
||||
```
|
||||
|
||||
### 步骤 B:起灰度栈(不动现网 3001)
|
||||
|
||||
```bash
|
||||
cd /app/iboard-prod/deploy/prod
|
||||
HOST_PORT=13011 docker compose --project-name iboard-prod \
|
||||
--env-file .env -f docker-compose.yml up -d pg
|
||||
|
||||
# 迁移建表
|
||||
docker run --rm --network iboard-prod_default \
|
||||
-e DATABASE_URL="postgresql://iboard:$(grep ^PG_PASSWORD .env | cut -d= -f2)@pg:5432/iboard" \
|
||||
iboard:latest npx prisma migrate deploy
|
||||
|
||||
# 建 publication (必须在建表之后)
|
||||
docker compose --project-name iboard-prod --env-file .env -f docker-compose.yml exec -T pg \
|
||||
psql -U iboard -d iboard -v ON_ERROR_STOP=1 -f /dev/stdin < sql/publication.sql
|
||||
|
||||
# 起 app + powersync (只有 13011 对外)
|
||||
HOST_PORT=13011 docker compose --project-name iboard-prod \
|
||||
--env-file .env -f docker-compose.yml up -d app powersync
|
||||
|
||||
# 验收
|
||||
curl -s http://127.0.0.1:13011/api/health # {"ok":true,...}
|
||||
ss -tlnp | grep -E ':(13011|5432|8080)\b' # 只应看到 13011
|
||||
```
|
||||
|
||||
### 步骤 C:数据迁移(MySQL → PG)
|
||||
|
||||
```bash
|
||||
docker run --rm --network iboard-prod_default \
|
||||
-e DATABASE_URL="postgresql://iboard:<PG_PASSWORD>@pg:5432/iboard" \
|
||||
-e SRC_DATABASE_URL="mysql://root:<MYSQL_PASSWORD>@<host>:3306/iboard" \
|
||||
iboard:latest node scripts/etl-mariadb-to-pg.mjs
|
||||
|
||||
# 迁移后重启同步服务重建快照
|
||||
docker compose --project-name iboard-prod --env-file .env -f docker-compose.yml restart powersync
|
||||
```
|
||||
|
||||
**验收**:项目 3 个(ADMIN / IBOARD / P3F921)、任务 ~22 条、用户 1 个(admin@iboard.local);
|
||||
`docker compose logs powersync` 显示 replication 已激活且无报错。
|
||||
|
||||
### 步骤 D:功能验证(13011)
|
||||
|
||||
- 登录 `admin@iboard.local`
|
||||
- 任务页:项目卡片、任务编号(如 `ADMIN-16`)
|
||||
- **离线验证**:断网后列表仍可读、左上角出现「离线」徽标,恢复网络自动同步回流
|
||||
- 监控 / 宏观 / 打卡页有数据
|
||||
|
||||
### 步骤 E:切换生产
|
||||
|
||||
```bash
|
||||
# E1. 停旧容器 (MySQL 版)
|
||||
docker rm -vf iboard || true
|
||||
|
||||
# E2. 新栈改绑 3001
|
||||
cd /app/iboard-prod/deploy/prod
|
||||
HOST_PORT=3001 docker compose --project-name iboard-prod \
|
||||
--env-file .env -f docker-compose.yml up -d app
|
||||
curl -s https://iboard.honor3.com/api/health # 经 NPM + 证书
|
||||
|
||||
# E3. 下线 0.2.1 验证栈 (释放 13001/13002/13443)
|
||||
cd /app/iboard-0.2.1/deploy/0.2.1 && docker compose down
|
||||
```
|
||||
|
||||
**验收**:`https://iboard.honor3.com` 可登录、任务正常、离线可编辑;
|
||||
`ss -tlnp` 只剩 3001(外加仅供本机的 3306)。
|
||||
|
||||
### 步骤 F:发布
|
||||
|
||||
```bash
|
||||
git checkout master && git merge dev-0.2 --no-edit
|
||||
git push origin master # 触发 CI: 构建镜像 + OTA
|
||||
```
|
||||
|
||||
CI 未配 PG secrets → 只构建不部署;生产已由步骤 B~E 手工就绪。
|
||||
|
||||
### 回滚预案
|
||||
|
||||
| 场景 | 动作 |
|
||||
| --- | --- |
|
||||
| 新栈起不来 | 旧容器未停,现网不受影响,回步骤 B 排查 |
|
||||
| 迁移数据不对 | 清空 `deploy/prod/data/pg` 后重跑 ETL |
|
||||
| 切换后严重故障 | 用 `iboard:mysql-final` 旧镜像按原 MySQL 参数恢复 3001 |
|
||||
|
||||
## 六、已知遗留
|
||||
|
||||
- `dev-0.2.1` / `dev-windows-0.1` 两个 worktree 分支内容已全部并入 `dev-0.2`,可择机删除。
|
||||
|
||||
Reference in New Issue
Block a user