文档对齐 React 技术栈,并支持渐进式数据库迁移
将 README 与部署文档从仅 init 改为 001 基线 + 增量迁移约定,并补充 create/status 脚手架与序号校验。
This commit is contained in:
+100
-104
@@ -1,54 +1,89 @@
|
||||
# 部署启动与数据库重建
|
||||
|
||||
本文记录本地开发、数据库重建和 Ubuntu 服务器部署的常用命令。
|
||||
本文记录本地开发、数据库迁移、重建库和 Ubuntu 服务器部署的常用命令。
|
||||
|
||||
项目当前数据库迁移以新库初始化为主,主要结构在:
|
||||
## 数据库迁移策略
|
||||
|
||||
项目使用 `node-pg-migrate`,迁移目录:
|
||||
|
||||
```text
|
||||
apps/backend/src/db/migrations/001_init.sql
|
||||
apps/backend/src/db/migrations/
|
||||
001_init.sql 空库基线(完整结构)
|
||||
002_xxx.sql 后续增量(示例命名)
|
||||
003_xxx.sql
|
||||
...
|
||||
```
|
||||
|
||||
后端启动时会自动执行数据库迁移。迁移记录保存在数据库表 `schema_migrations`。
|
||||
记录表:`schema_migrations`。
|
||||
|
||||
| 场景 | 行为 |
|
||||
| --- | --- |
|
||||
| 全新空库 | 按序号执行 `001_init` → 全部增量 |
|
||||
| 已有库升级 | 只执行尚未记录的增量文件 |
|
||||
| 改历史迁移文件内容 | **不会**自动重跑;已应用文件禁止修改 |
|
||||
|
||||
约定:
|
||||
|
||||
1. `001_init.sql` 只作为基线;上线后结构变更不要改它。
|
||||
2. 每次 schema 变更新增 `NNN_name.sql`(三位序号)。
|
||||
3. 迁移与业务代码同一变更一起提交。
|
||||
4. 后端启动会自动 `up`;也可用命令手动执行。
|
||||
|
||||
### 开发常用命令
|
||||
|
||||
```bash
|
||||
# 查看本地文件与库内已应用记录
|
||||
docker compose -f docker-compose.dev.yml exec -T backend npm run db:migrate:status
|
||||
|
||||
# 手动执行未应用迁移
|
||||
docker compose -f docker-compose.dev.yml exec -T backend npm run db:migrate
|
||||
|
||||
# 创建下一份增量迁移模板
|
||||
docker compose -f docker-compose.dev.yml exec -T backend npm run db:migrate:create -- add_column_example
|
||||
```
|
||||
|
||||
宿主机直连(`postgres` 主机名仅在 Docker 网络内有效):
|
||||
|
||||
```bash
|
||||
cd apps/backend
|
||||
DATABASE_URL=postgres://postgres:postgres@127.0.0.1:5432/order_site npm run db:migrate:status
|
||||
DATABASE_URL=postgres://postgres:postgres@127.0.0.1:5432/order_site npm run db:migrate
|
||||
```
|
||||
|
||||
## 本地开发启动
|
||||
|
||||
首次启动:
|
||||
首次:
|
||||
|
||||
```bash
|
||||
cp .env.mac-docker.example .env
|
||||
docker compose -f docker-compose.dev.yml up -d --build
|
||||
```
|
||||
|
||||
日常启动:
|
||||
日常:
|
||||
|
||||
```bash
|
||||
docker compose -f docker-compose.dev.yml up -d
|
||||
```
|
||||
|
||||
查看服务状态:
|
||||
状态与日志:
|
||||
|
||||
```bash
|
||||
docker compose -f docker-compose.dev.yml ps
|
||||
```
|
||||
|
||||
查看日志:
|
||||
|
||||
```bash
|
||||
docker compose -f docker-compose.dev.yml logs -f backend
|
||||
docker compose -f docker-compose.dev.yml logs -f frontend
|
||||
```
|
||||
|
||||
本地访问入口:
|
||||
本地入口:
|
||||
|
||||
- 前端、后台、领取页:`http://localhost`
|
||||
- 后端健康检查:`http://localhost/health`
|
||||
- 后端就绪检查:`http://localhost/health/ready`
|
||||
- 健康检查:`http://localhost/health`
|
||||
- 就绪检查:`http://localhost/health/ready`
|
||||
|
||||
## 本地重建数据库
|
||||
|
||||
如果迁移基线变化,或者需要清空本地测试数据,可以重建本地开发库。
|
||||
仅在需要清空开发数据,或本地库与迁移历史严重不一致时使用。
|
||||
|
||||
只重建开发数据库,保留源码文件:
|
||||
只重建开发库 volume:
|
||||
|
||||
```bash
|
||||
docker compose -f docker-compose.dev.yml down
|
||||
@@ -56,29 +91,33 @@ docker volume rm order_site_postgres_dev_data
|
||||
docker compose -f docker-compose.dev.yml up -d --build
|
||||
```
|
||||
|
||||
如果提示 volume 不存在,说明本地数据库 volume 名称可能不同,可以先查看:
|
||||
volume 名称不确定时:
|
||||
|
||||
```bash
|
||||
docker volume ls | grep postgres_dev_data
|
||||
```
|
||||
|
||||
也可以直接删除当前 dev compose 创建的所有 volume:
|
||||
删除当前 dev compose 全部 volume(会重装 node_modules volume):
|
||||
|
||||
```bash
|
||||
docker compose -f docker-compose.dev.yml down -v
|
||||
docker compose -f docker-compose.dev.yml up -d --build
|
||||
```
|
||||
|
||||
注意:`down -v` 会同时删除开发环境里的 `postgres_dev_data`、`backend_node_modules`、`frontend_node_modules` 等 volume。下次启动会重新安装依赖。
|
||||
确认迁移记录:
|
||||
|
||||
确认迁移结果:
|
||||
```bash
|
||||
docker compose -f docker-compose.dev.yml exec -T backend npm run db:migrate:status
|
||||
```
|
||||
|
||||
或:
|
||||
|
||||
```bash
|
||||
docker compose -f docker-compose.dev.yml exec -T backend node --input-type=module -e '
|
||||
const { query, closeDb } = await import("./src/db/client.ts");
|
||||
try {
|
||||
const result = await query("SELECT filename FROM schema_migrations ORDER BY filename");
|
||||
console.log(result.rows.map((row) => row.filename).join("\n"));
|
||||
const result = await query("SELECT COALESCE(filename, name) AS name FROM schema_migrations ORDER BY COALESCE(filename, name)");
|
||||
console.log(result.rows.map((row) => row.name).join("\n"));
|
||||
} finally {
|
||||
await closeDb();
|
||||
}
|
||||
@@ -87,39 +126,23 @@ try {
|
||||
|
||||
## 本地验证
|
||||
|
||||
后端:
|
||||
|
||||
```bash
|
||||
docker compose -f docker-compose.dev.yml exec -T backend npm test
|
||||
docker compose -f docker-compose.dev.yml exec -T backend npm run typecheck
|
||||
docker compose -f docker-compose.dev.yml exec -T backend npm run build
|
||||
```
|
||||
|
||||
前端:
|
||||
|
||||
```bash
|
||||
docker compose -f docker-compose.dev.yml exec -T frontend npm run typecheck
|
||||
docker compose -f docker-compose.dev.yml exec -T frontend npm run lint
|
||||
docker compose -f docker-compose.dev.yml exec -T frontend npm run build
|
||||
```
|
||||
|
||||
手动执行迁移:
|
||||
|
||||
```bash
|
||||
docker compose -f docker-compose.dev.yml exec -T backend npm run db:migrate
|
||||
```
|
||||
|
||||
## 服务器首次部署
|
||||
|
||||
服务器建议使用 Ubuntu + Docker Compose。
|
||||
|
||||
进入项目目录后执行:
|
||||
建议 Ubuntu + Docker Compose。
|
||||
|
||||
```bash
|
||||
cp .env.server.example .env
|
||||
```
|
||||
|
||||
编辑 `.env`,至少替换这些值:
|
||||
至少配置:
|
||||
|
||||
```text
|
||||
CADDY_SITE_ADDR
|
||||
@@ -130,66 +153,43 @@ ADMIN_SESSION_SECRET
|
||||
ADMIN_DEFAULT_USERS_JSON
|
||||
```
|
||||
|
||||
生产 Docker 部署时,`DATABASE_URL` 如果连接 compose 内置 PostgreSQL,主机名应使用 `postgres`:
|
||||
容器内连接 Compose PostgreSQL 时,主机名用 `postgres`:
|
||||
|
||||
```text
|
||||
DATABASE_URL=postgres://postgres:你的数据库密码@postgres:5432/order_site
|
||||
```
|
||||
|
||||
不要写成:
|
||||
不要写成容器内的 `127.0.0.1`(那会指向后端容器自己)。
|
||||
|
||||
```text
|
||||
DATABASE_URL=postgres://postgres:你的数据库密码@127.0.0.1:5432/order_site
|
||||
```
|
||||
|
||||
因为后端运行在容器内,容器内的 `127.0.0.1` 指向后端容器自己,不是 PostgreSQL 容器。
|
||||
|
||||
执行部署:
|
||||
部署:
|
||||
|
||||
```bash
|
||||
bash deploy/ubuntu-deploy.sh
|
||||
```
|
||||
|
||||
脚本会自动:
|
||||
|
||||
- 检查 Docker 和 Docker Compose
|
||||
- 检查 `.env` 是否仍有占位值
|
||||
- 检查容器部署时 `DATABASE_URL` 是否误写成本机地址
|
||||
- 修正 `apps/backend/data` 目录权限
|
||||
- 构建并启动服务
|
||||
- 等待健康检查通过
|
||||
- 打印已应用数据库迁移
|
||||
|
||||
部署完成后查看服务:
|
||||
脚本会:检查 Docker、检查 `.env` 占位值、检查 `DATABASE_URL`、修正 `apps/backend/data` 权限、构建启动、等待健康检查、打印已应用迁移。
|
||||
|
||||
```bash
|
||||
docker compose ps
|
||||
```
|
||||
|
||||
查看后端日志:
|
||||
|
||||
```bash
|
||||
docker compose logs -f backend
|
||||
```
|
||||
|
||||
## 服务器日常更新
|
||||
|
||||
拉取或上传新代码后,在项目目录执行:
|
||||
|
||||
```bash
|
||||
bash deploy/ubuntu-deploy.sh
|
||||
```
|
||||
|
||||
后端容器启动时会自动执行迁移,不需要单独手动跑迁移。
|
||||
后端启动时自动执行未应用的增量迁移,一般不必单独跑迁移。
|
||||
|
||||
确认迁移记录:
|
||||
确认:
|
||||
|
||||
```bash
|
||||
docker compose exec -T backend node --input-type=module -e '
|
||||
const { query, closeDb } = await import("./dist/db/client.js");
|
||||
try {
|
||||
const result = await query("SELECT filename FROM schema_migrations ORDER BY filename");
|
||||
console.log(result.rows.map((row) => row.filename).join("\n"));
|
||||
const result = await query("SELECT COALESCE(filename, name) AS name FROM schema_migrations ORDER BY COALESCE(filename, name)");
|
||||
console.log(result.rows.map((row) => row.name).join("\n"));
|
||||
} finally {
|
||||
await closeDb();
|
||||
}
|
||||
@@ -198,46 +198,38 @@ try {
|
||||
|
||||
## 服务器重建数据库
|
||||
|
||||
下面命令会删除生产数据库数据。只适合新开发、测试服务器或确认不需要保留数据的场景。
|
||||
|
||||
停止服务:
|
||||
**会删除生产数据**。仅适合新环境、测试机或确认可丢数据的场景。
|
||||
|
||||
```bash
|
||||
docker compose down
|
||||
```
|
||||
|
||||
只删除 PostgreSQL 数据 volume,保留 Caddy 证书和配置 volume:
|
||||
|
||||
```bash
|
||||
docker volume rm order_site_postgres_data
|
||||
```
|
||||
|
||||
重新部署:
|
||||
|
||||
```bash
|
||||
bash deploy/ubuntu-deploy.sh
|
||||
```
|
||||
|
||||
如果 volume 名称不确定,可以查看:
|
||||
或:
|
||||
|
||||
```bash
|
||||
bash deploy/ubuntu-deploy.sh --reset-db
|
||||
```
|
||||
|
||||
volume 名不确定时:
|
||||
|
||||
```bash
|
||||
docker volume ls | grep postgres_data
|
||||
```
|
||||
|
||||
不建议在生产服务器随手执行:
|
||||
不要随手:
|
||||
|
||||
```bash
|
||||
docker compose down -v
|
||||
```
|
||||
|
||||
因为它会同时删除 `postgres_data`、`caddy_data`、`caddy_config`。这会清空数据库,并可能让 Caddy 重新申请证书。
|
||||
这会连同 `caddy_data` / `caddy_config` 一起删掉,可能触发证书重签。
|
||||
|
||||
## 常见问题
|
||||
|
||||
### 后端一直未 ready
|
||||
|
||||
查看诊断:
|
||||
|
||||
```bash
|
||||
docker compose ps
|
||||
docker compose logs --tail=120 backend
|
||||
@@ -246,23 +238,27 @@ docker compose logs --tail=120 backend
|
||||
常见原因:
|
||||
|
||||
- `.env` 仍有 `change-me` 占位值
|
||||
- `DATABASE_URL` 密码和已有 PostgreSQL volume 初始化密码不一致
|
||||
- `DATABASE_URL` 在容器部署中误写成 `127.0.0.1`
|
||||
- 后端迁移失败
|
||||
- `DATABASE_URL` 密码与已有 PostgreSQL volume 初始化密码不一致
|
||||
- 容器部署里 `DATABASE_URL` 误写 `127.0.0.1`
|
||||
- 某次增量迁移 SQL 失败
|
||||
|
||||
### 修改了 `001_init.sql` 但旧库没有变化
|
||||
### 改了 `001_init.sql` 但旧库没变
|
||||
|
||||
`schema_migrations` 只记录迁移文件是否执行过。已经执行过 `001_init.sql` 的数据库,不会因为文件内容变化自动重跑。
|
||||
已应用过的迁移不会因文件内容变更而重跑。正确做法是 **新增** `002_xxx.sql` 写增量。
|
||||
|
||||
新开发阶段如果不需要保留数据,直接重建数据库即可。
|
||||
仅本地可丢数据时,才用重建 volume 的方式对齐。
|
||||
|
||||
### 如何新增字段 / 索引
|
||||
|
||||
```bash
|
||||
docker compose -f docker-compose.dev.yml exec -T backend \
|
||||
npm run db:migrate:create -- add_orders_note
|
||||
|
||||
# 编辑生成的 apps/backend/src/db/migrations/00N_add_orders_note.sql
|
||||
docker compose -f docker-compose.dev.yml exec -T backend npm run db:migrate
|
||||
docker compose -f docker-compose.dev.yml exec -T backend npm run db:migrate:status
|
||||
```
|
||||
|
||||
### 宿主机手动跑迁移连不上 `postgres`
|
||||
|
||||
`.env` 里的 `postgres` 主机名只在 Docker 网络里有效。宿主机直接跑迁移时需要临时使用宿主机地址:
|
||||
|
||||
```bash
|
||||
cd apps/backend
|
||||
DATABASE_URL=postgres://postgres:postgres@127.0.0.1:5432/order_site npm run db:migrate
|
||||
```
|
||||
|
||||
容器内执行迁移时继续使用 `.env` 中的 `postgres` 服务名即可。
|
||||
`.env` 里的 `postgres` 只在 Docker 网络有效。宿主机请临时改为 `127.0.0.1` 并映射端口。
|
||||
|
||||
Reference in New Issue
Block a user