Files
gitea/docs/sqlite-to-postgres-migration.md
2026-04-27 22:10:20 +08:00

254 lines
8.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# SQLite 迁移到 PostgreSQL
本文档适用于已有 Gitea 服务仍在使用旧版 Docker Compose 和 SQLite尚未更新到引入 PostgreSQL 的最新 commit 的场景。
迁移目标是把 `data/gitea/gitea.db` 中的业务数据导入到新的 PostgreSQL 数据库同时继续复用现有的仓库、LFS、附件和配置目录。
> `gitea migrate` 不是 SQLite 到 PostgreSQL 的数据搬迁工具。它只会对当前 Gitea 配置指向的数据库执行 Gitea schema migration。
>
> Gitea 自带的跨数据库导出入口是 `gitea dump --database postgres`。Gitea 没有对应的自动 `gitea restore` 命令,恢复或导入 PostgreSQL 时需要手动解压 dump 包,并用 `psql` 导入其中的 `gitea-db.sql`。
## 迁移前准备
- 预留维护窗口。迁移期间必须停止 Gitea避免 SQLite 继续写入。
- 保持 `GITEA_VERSION` 不变。不要在同一次操作中同时升级 Gitea 版本和切换数据库。
- 准备 `.env` 中的 PostgreSQL 配置:
```env
POSTGRES_VERSION=16-alpine
POSTGRES_DB=gitea
POSTGRES_USER=gitea
POSTGRES_PASSWORD=<强密码>
```
- 确认可以运行 `sqlite3``unzip`,并且 PostgreSQL 容器里可以运行 `psql`
- 本文档假设 `docker-compose.yml` 把宿主机 `./data` 挂载到 Gitea 容器内的 `/data`。因此 dump 输出到容器内 `/data/gitea-dump-postgres.zip` 时,宿主机对应文件是 `data/gitea-dump-postgres.zip`
## 1. 停止旧 Gitea
在仍使用 SQLite 的旧版 compose 下停止 Gitea
```bash
docker compose stop gitea
```
如果启用了 Caddy可以保持 Caddy 运行显示维护页,也可以一起停止:
```bash
docker compose stop caddy
```
## 2. 冷备份 SQLite 和数据目录
```bash
ts=$(date +%Y%m%d-%H%M%S)
mkdir -p backups/$ts
cp data/gitea/gitea.db backups/$ts/gitea.db
cp data/gitea/conf/app.ini backups/$ts/app.ini
tar -czf backups/$ts/gitea-data.tar.gz data/git data/gitea
```
备份完成后,记录 SQLite 中的关键表数量,作为迁移后校验基线:
```bash
sqlite3 data/gitea/gitea.db "select 'user', count(*) from user union all select 'repository', count(*) from repository union all select 'lfs_meta_object', count(*) from lfs_meta_object union all select 'public_key', count(*) from public_key union all select 'issue', count(*) from issue union all select 'release', count(*) from release;"
```
## 3. 使用 Gitea dump 导出 PostgreSQL SQL
在仍使用旧 SQLite 配置时运行 `gitea dump`。不要先把 Gitea 配置切到 PostgreSQL否则 dump 会尝试读取新数据库。
```bash
docker compose run --rm --user git gitea \
gitea dump -c /data/gitea/conf/app.ini \
--database postgres \
--file /data/gitea-dump-postgres.zip
```
确认宿主机上已经生成 dump 包:
```bash
ls -lh data/gitea-dump-postgres.zip
```
如果当前镜像或环境不能识别 `git` 用户,可以改用官方镜像常见 UID/GID
```bash
docker compose run --rm --user 1000:1000 gitea \
gitea dump -c /data/gitea/conf/app.ini \
--database postgres \
--file /data/gitea-dump-postgres.zip
```
解压 dump 包,得到 `gitea-db.sql`
```bash
mkdir -p backups/gitea-dump-postgres
unzip -o data/gitea-dump-postgres.zip -d backups/gitea-dump-postgres
ls -lh backups/gitea-dump-postgres/gitea-db.sql
```
## 4. 更新代码并只启动 PostgreSQL
更新到包含 PostgreSQL 服务的最新 commit并补齐 `.env` 中的 PostgreSQL 配置。
```bash
git pull
```
先只启动 PostgreSQL不要启动 Gitea
```bash
docker compose up -d postgres
```
确认 PostgreSQL 可连接:
```bash
docker compose exec -T postgres psql -U gitea -d gitea -c "select version();"
```
## 5. 确认 PostgreSQL 是空库
检查目标库是否已有表:
```bash
docker compose exec -T postgres psql -U gitea -d gitea -c '\dt'
```
如果已经有 Gitea 业务表,先确认这些表不是生产数据。确认可丢弃后,停止 PostgreSQL备份并移走 `data/postgres/`,再重新启动空库:
```bash
docker compose stop postgres
ts=$(date +%Y%m%d-%H%M%S)
mv data/postgres data/postgres.before-migration-$ts
docker compose up -d postgres
```
再次运行 `\dt`,确认目标库为空。
## 6. 导入 dump SQL 到 PostgreSQL
使用 `psql` 导入 `gitea-db.sql`
```bash
docker compose exec -T postgres psql -U gitea -d gitea < backups/gitea-dump-postgres/gitea-db.sql
```
导入完成后,检查目标库关键表数量:
```bash
docker compose exec -T postgres psql -U gitea -d gitea -c "select 'user', count(*) from \"user\" union all select 'repository', count(*) from repository union all select 'lfs_meta_object', count(*) from lfs_meta_object union all select 'public_key', count(*) from public_key union all select 'issue', count(*) from issue union all select 'release', count(*) from release;"
```
这些数量应与第 2 步 SQLite 基线一致。
## 7. 启动 Gitea
确认 `docker-compose.yml` 已通过 `GITEA__database__*` 环境变量指向 PostgreSQL然后启动 Gitea
```bash
docker compose up -d gitea
docker compose logs -f gitea
```
Gitea 启动时会对 PostgreSQL 执行必要的 schema migration。日志中不应出现数据库连接、类型转换、唯一约束或 migration 错误。
如果使用 Caddy
```bash
docker compose up -d caddy
```
## 8. 迁移后验证
- 使用原管理员账号登录 Web UI。
- 确认用户、组织、仓库、Issue、Release、SSH Key 等数据存在。
- 执行一次 HTTP 或 HTTPS clone。
- 执行一次 SSH clone。
- 推送一个普通 commit。
- 如果使用 Git LFS执行一次 LFS push。
- 检查日志:
```bash
docker compose logs gitea postgres
```
## 常见问题
### Gitea is not supposed to be run as root
`docker compose run` 默认可能以 root 用户启动一次性容器,但 Gitea 不允许以 root 运行。给 dump 命令加上 `--user git`
```bash
docker compose run --rm --user git gitea \
gitea dump -c /data/gitea/conf/app.ini \
--database postgres \
--file /data/gitea-dump-postgres.zip
```
如果 `git` 用户不可用,改用:
```bash
docker compose run --rm --user 1000:1000 gitea \
gitea dump -c /data/gitea/conf/app.ini \
--database postgres \
--file /data/gitea-dump-postgres.zip
```
### Unable to create dump file "/gitea-dump-*.zip": permission denied
`gitea dump` 默认会把文件写到容器当前目录。如果当前目录是 `/`,非 root 用户没有写权限。显式指定 `--file /data/gitea-dump-postgres.zip`,让 dump 写入已挂载且可持久化的 `/data` 目录。
### pgloader 备选方案
如果 `gitea dump --database postgres` 在当前版本或数据集上失败,可以把 `pgloader` 作为备选迁移工具。使用前仍然要停止 Gitea、完成冷备份并确认 PostgreSQL 目标库为空。
`<POSTGRES_PASSWORD>` 替换为 `.env` 中的真实密码:
```bash
docker run --rm \
--network gitea_default \
-v "$PWD/data/gitea:/data/gitea:ro" \
dimitri/pgloader:latest \
pgloader sqlite:///data/gitea/gitea.db postgresql://gitea:<POSTGRES_PASSWORD>@postgres:5432/gitea
```
如果 compose project 网络名不是 `gitea_default`,替换 `--network` 参数。
## 回滚
如果迁移后验证失败,先停止新 Gitea
```bash
docker compose stop gitea
```
回滚到旧版 SQLite compose或临时移除 `docker-compose.yml` 中的 `GITEA__database__*` 环境变量,避免它覆盖 `app.ini`
恢复备份:
```bash
cp backups/<备份时间>/gitea.db data/gitea/gitea.db
cp backups/<备份时间>/app.ini data/gitea/conf/app.ini
```
再启动旧 SQLite 版本:
```bash
docker compose up -d gitea
```
在迁移完全确认前,不要删除 `data/gitea/gitea.db``backups/``data/gitea-dump-postgres.zip` 或迁移前的 `data/postgres.before-migration-*`
## 演练建议
正式迁移前,建议在复制出来的目录中完整演练一次:
```bash
cp -a gitea gitea-migration-dry-run
cd gitea-migration-dry-run
```
演练中也要验证 dump 导出、SQL 解压、空库检查、`psql` 导入、表数量对比、Gitea 启动和 Web/Git 操作。演练通过后,再在正式目录执行维护窗口迁移。