5.5 KiB
SQLite 迁移到 PostgreSQL
本文档适用于已有 Gitea 服务仍在使用旧版 Docker Compose 和 SQLite,尚未更新到引入 PostgreSQL 的最新 commit 的场景。
迁移目标是把 data/gitea/gitea.db 中的业务数据导入到新的 PostgreSQL 数据库,同时继续复用现有的仓库、LFS、附件和配置目录。
gitea migrate不是 SQLite 到 PostgreSQL 的数据搬迁工具。它只会对当前 Gitea 配置指向的数据库执行 Gitea schema migration。数据库搬迁应使用pgloader完成。
迁移前准备
- 预留维护窗口。迁移期间必须停止 Gitea,避免 SQLite 继续写入。
- 保持
GITEA_VERSION不变。不要在同一次操作中同时升级 Gitea 版本和切换数据库。 - 准备
.env中的 PostgreSQL 配置:
POSTGRES_VERSION=16-alpine
POSTGRES_DB=gitea
POSTGRES_USER=gitea
POSTGRES_PASSWORD=<强密码>
- 确认可以运行
sqlite3,并能拉取或运行dimitri/pgloader:latest镜像。 - 本文档默认 Docker Compose project 网络名为
gitea_default。如果实际名称不同,用下面命令查看后替换:
docker network ls
1. 停止旧 Gitea
在仍使用 SQLite 的旧版 compose 下停止 Gitea:
docker compose stop gitea
如果启用了 Caddy,可以保持 Caddy 运行显示维护页,也可以一起停止:
docker compose stop caddy
2. 冷备份 SQLite 和数据目录
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 中的关键表数量,作为迁移后校验基线:
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. 更新代码并只启动 PostgreSQL
更新到包含 PostgreSQL 服务的最新 commit,并补齐 .env 中的 PostgreSQL 配置。
git pull
先只启动 PostgreSQL,不要启动 Gitea:
docker compose up -d postgres
确认 PostgreSQL 可连接:
docker compose exec -T postgres psql -U gitea -d gitea -c "select version();"
4. 确认 PostgreSQL 是空库
检查目标库是否已有表:
docker compose exec -T postgres psql -U gitea -d gitea -c '\dt'
如果已经有 Gitea 业务表,先确认这些表不是生产数据。确认可丢弃后,停止 PostgreSQL,备份并移走 data/postgres/,再重新启动空库:
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,确认目标库为空。
5. 使用 pgloader 导入 SQLite
把 <POSTGRES_PASSWORD> 替换为 .env 中的真实密码:
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 参数。
导入完成后,检查目标库关键表数量:
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 基线一致。
6. 启动 Gitea
确认 docker-compose.yml 已通过 GITEA__database__* 环境变量指向 PostgreSQL,然后启动 Gitea:
docker compose up -d gitea
docker compose logs -f gitea
Gitea 启动时会对 PostgreSQL 执行必要的 schema migration。日志中不应出现数据库连接、类型转换、唯一约束或 migration 错误。
如果使用 Caddy:
docker compose up -d caddy
7. 迁移后验证
- 使用原管理员账号登录 Web UI。
- 确认用户、组织、仓库、Issue、Release、SSH Key 等数据存在。
- 执行一次 HTTP 或 HTTPS clone。
- 执行一次 SSH clone。
- 推送一个普通 commit。
- 如果使用 Git LFS,执行一次 LFS push。
- 检查日志:
docker compose logs gitea postgres
回滚
如果迁移后验证失败,先停止新 Gitea:
docker compose stop gitea
回滚到旧版 SQLite compose,或临时移除 docker-compose.yml 中的 GITEA__database__* 环境变量,避免它覆盖 app.ini。
恢复备份:
cp backups/<备份时间>/gitea.db data/gitea/gitea.db
cp backups/<备份时间>/app.ini data/gitea/conf/app.ini
再启动旧 SQLite 版本:
docker compose up -d gitea
在迁移完全确认前,不要删除 data/gitea/gitea.db、backups/ 或迁移前的 data/postgres.before-migration-*。
演练建议
正式迁移前,建议在复制出来的目录中完整演练一次:
cp -a gitea gitea-migration-dry-run
cd gitea-migration-dry-run
演练中也要验证空库检查、pgloader 导入、表数量对比、Gitea 启动和 Web/Git 操作。演练通过后,再在正式目录执行维护窗口迁移。