10 KiB
10 KiB
vps.git Docker 迁移方案 v1
目标
把 vps.git 上当前裸机部署的:
- Gitea
- Keycloak
- MySQL
迁移为 Docker 版本,并满足以下约束:
gitea、keycloak、mysql位于同一个 Docker 网络- MySQL 只保留一个容器实例,但实例内分两个独立库:
<gitea_db><keycloak_db>
- 宿主机
nginx架构不变,继续保留在宿主机上 - Gitea 直接挂载现有数据目录
- Keycloak 从 H2 迁移到 MySQL
- 敏感信息统一放在
.env - Docker 部署根目录放在
~/git-kc - 本次迁移不顺手升级大版本,优先保持现有版本基线
- 本次迁移默认先不启用 Git over SSH,仅保证 HTTPS Git 正常
当前现状摘要
服务现状
宿主机当前运行:
nginxgitea.servicekeycloak.servicemysql.service
监听关系
nginx:对外80/443gitea:宿主机监听3000keycloak:宿主机监听8443mysql:宿主机监听localhost:3306
当前数据位置
- Gitea 配置:
/etc/gitea/app.ini - Gitea 数据:
/var/lib/gitea - Keycloak 配置:
/opt/keycloak/conf/keycloak.conf - Keycloak H2 数据:
/opt/keycloak/data/h2 - MySQL 数据:
/var/lib/mysql
当前版本基线
- Gitea:
1.22.4 - Keycloak:
26.0.6 - MySQL:
8.0.x
迁移时保持同代版本,不使用 latest。
目标架构
宿主机保留
nginx- 当前证书与域名
- 宿主机 SSH 运维入口
Docker 内运行
mysqlgiteakeycloak
三者放在同一个 Docker 网络中,例如:
git-kc-net
端口策略
mysql- 不对宿主机发布端口
- 仅允许 Docker 内部网络访问
gitea- 发布到
localhost:3000
- 发布到
keycloak- 发布到
localhost:8080
- 发布到
nginx 反代目标
git.hangman-lab.top→http://localhost:3000login.hangman-lab.top→http://localhost:8080
说明:
- Gitea 迁移后,对外域名不变
- Keycloak 迁移后,对外域名不变
- Keycloak 容器内不再自行持有 HTTPS,TLS 由宿主机 nginx 负责终止
部署目录设计
Docker 部署根目录:
~/git-kc
建议结构:
~/git-kc/compose.yaml~/git-kc/.env~/git-kc/backups/~/git-kc/mysql/~/git-kc/gitea/~/git-kc/keycloak/~/git-kc/keycloak/import/~/git-kc/docs/
用途说明:
compose.yaml:Compose 主文件.env:敏感配置backups/:迁移专用备份gitea/:Gitea 容器使用的配置副本keycloak/import/:Keycloak realm 导入文件docs/:迁移记录与回滚说明
数据与配置保留策略
Gitea
Gitea 采用“保留原数据目录,容器挂载使用”的方式:
- 直接挂载现有数据目录:
/var/lib/gitea
配置文件策略:
- 不直接原地修改宿主机当前使用的
/etc/gitea/app.ini - 先复制一份到:
~/git-kc/gitea/app.ini - Docker Gitea 使用这份配置副本
- 原始
/etc/gitea/app.ini保留不动,用于快速回滚
Keycloak
Keycloak 不直接复用当前运行目录作为 Docker 运行目录,而是:
- 从旧 Keycloak 执行 realm export
- 在 Docker Keycloak 中导入 realm
- 新容器改用 MySQL 存储
旧目录保留:
/opt/keycloak/conf/opt/keycloak/data/h2
MySQL
MySQL 不直接接管旧宿主机 datadir,而采用逻辑导出 / 导入迁移:
- 导出旧
<gitea_db> - 在 Docker MySQL 内创建新实例环境
- 导入
<gitea_db> - 新建
<keycloak_db>
数据库设计
Docker MySQL 容器内使用一个实例,分为两个独立数据库:
<gitea_db><keycloak_db>
分别创建独立账户:
giteakeycloak
权限原则:
gitea仅访问<gitea_db>keycloak仅访问<keycloak_db>
字符集与排序规则保持与当前环境一致:
utf8mb4utf8mb4_0900_ai_ci
说明:
- 是“共用一个 MySQL 容器实例”
- 不是“共用同一个 database/schema”
Gitea 容器设计
运行目标
迁移后保持:
- 域名不变
- 数据目录不变
- 仓库、用户、OIDC、package 等数据保留
- 本次先不启用 Git over SSH
配置原则
基于现有 app.ini 的副本进行调整,重点改动:
[database] HOST- 从
localhost:3306 - 改为
mysql:3306
- 从
其余核心配置尽量保持不变,例如:
ROOT_URLAPP_DATA_PATHrepository ROOToauth2/openidsecurityservicepackage/lfs/queue
端口
- 宿主机:
localhost:3000 - 容器内:
3000
SSH 策略
本次迁移默认:
- 不启用 Git over SSH
- 不抢占宿主机
22 - 所有 Git 操作先走 HTTPS
- Gitea 配置中应显式关闭 SSH(例如
DISABLE_SSH = true;若存在START_SSH_SERVER,则设为false)
后续如需恢复 Git over SSH,再单独设计第二阶段方案。
Keycloak 容器设计
迁移原则
Keycloak 从:
- 裸机
- H2
- 自身提供 HTTPS 8443
迁移为:
- Docker
- MySQL
- 容器内部 HTTP
- 宿主机 nginx 负责 TLS 终止
数据库连接
Keycloak 容器连接:
- Host:
mysql - Port:
3306 - Database:
<keycloak_db>
对外行为保持不变
- 域名:
login.hangman-lab.top - Realm:
Hangman-Lab - OIDC issuer 保持不变
- 尽量保持原有 client 与集成关系不变
端口
- 宿主机:
localhost:8080 - 容器内:
8080
容器配置原则
通过 .env 注入:
KC_DB=mysqlKC_DB_URL_HOST=mysqlKC_DB_URL_DATABASE=<keycloak_db>KC_DB_USERNAMEKC_DB_PASSWORDKC_HOSTNAME=login.hangman-lab.topKC_HTTP_ENABLED=trueKC_PROXY_HEADERS=xforwarded
说明:
- Docker Keycloak 不再自行持有 TLS 证书
- nginx 负责 HTTPS
nginx 变更原则
宿主机 nginx 架构保持不变。
Gitea
继续反代到:
http://localhost:3000
如容器沿用相同宿主端口,Gitea 对应 nginx 配置可能无需变更。
Keycloak
需要把 upstream 从:
https://localhost:8443
改为:
http://localhost:8080
并保留以下头:
HostX-Real-IPX-Forwarded-ForX-Forwarded-Proto
迁移实施步骤
Phase A:准备阶段
- 在
vps.git上安装 Docker Engine 与 Docker Compose Plugin - 创建目录:
~/git-kc~/git-kc/backups~/git-kc/mysql~/git-kc/gitea~/git-kc/keycloak/import~/git-kc/docs
- 编写
compose.yaml与.env - 复制 Gitea 当前配置:
/etc/gitea/app.ini→~/git-kc/gitea/app.ini
- 调整 Gitea 容器配置副本中的数据库地址
- 准备 Keycloak 容器参数
- 预拉取固定版本镜像
Phase B:备份阶段
正式切换前执行迁移专用备份:
- 备份
/etc/gitea/app.ini - 记录并确认
/var/lib/gitea当前状态 - 导出 Gitea 数据库:
mysqldump <gitea_db> - 从旧 Keycloak 导出 realm / users
- 备份 nginx 相关站点配置
说明:
- 即使整机已有备份,仍建议保留迁移专用备份,以便快速回滚
Phase C:切换阶段
建议顺序:
- 进入维护窗口
- 停止旧 Gitea:
systemctl stop gitea - 停止旧 Keycloak:
systemctl stop keycloak - 执行 Gitea 最终 SQL 导出
- 执行 Keycloak 最终 export
- 停止旧 MySQL:
systemctl stop mysql - 启动 Docker MySQL
- 初始化 Docker MySQL:
- 创建
<gitea_db> - 创建
<keycloak_db> - 创建
gitea用户 - 创建
keycloak用户
- 创建
- 导入 Gitea SQL 到 Docker MySQL
- 启动 Docker Keycloak,并导入 realm
- 启动 Docker Gitea
- 修改 nginx 的 Keycloak upstream:
- 从
https://localhost:8443 - 改为
http://localhost:8080
- 执行
nginx -t - 执行
systemctl reload nginx - 执行完整验证
验证清单
Gitea
https://git.hangman-lab.top/可访问- 首页正常
- 用户可登录
- 仓库列表正常
- 既有仓库可见
- Package 功能正常
- HTTPS clone 正常
- HTTPS push 正常
- OIDC 登录可正常跳转到 Keycloak 并返回
Keycloak
https://login.hangman-lab.top/可访问- Realm
Hangman-Lab正常 - OIDC discovery 正常
- 管理后台可登录
- 普通用户可登录
- 原有 client 保留
- issuer 与原环境一致
MySQL
<gitea_db>表完整<keycloak_db>表完整- Gitea 可正常连接数据库
- Keycloak 可正常连接数据库
- 容器重启后数据不丢失
nginx
- HTTPS 证书正常
- 无重定向循环
- 无 mixed content
- 代理头工作正常
回滚方案
如果迁移后验证失败,按以下顺序回滚:
- 停止 Docker 容器:
giteakeycloakmysql
- 恢复 nginx 的 Keycloak upstream:
- 改回
https://localhost:8443
- 改回
- 启动旧宿主机服务:
systemctl start mysqlsystemctl start keycloaksystemctl start gitea
- 执行
nginx -t - 执行
systemctl reload nginx
回滚前提:
- 不删除旧数据
- 不覆盖旧宿主配置
- Gitea 使用配置副本而不是原地覆盖
- MySQL 使用逻辑迁移而不是直接接管 datadir
主要风险点
1. Keycloak H2 → MySQL
这是整个迁移中最高风险点。
控制策略:
- 必须走 export / import
- 不采用“直接改 DB 配置试运行”的方式
2. Gitea 与 Keycloak 的 OIDC 一致性
控制策略:
- 不改域名
- 不改 realm 名称
- 不改 issuer
- 尽量不重建 client
3. Gitea 直接挂载旧目录
控制策略:
- 切换时必须先彻底停止旧 Gitea
- 避免新旧环境同时访问同一数据目录
4. Keycloak 容器改为 HTTP
控制策略:
- 确保 nginx 传递正确代理头
- 确保 Keycloak hostname 与 proxy 配置正确
- 仅绑定到
localhost
已确定的关键决策
- 宿主机 nginx 架构不动
- Docker 部署根目录使用
~/git-kc - Gitea 直接挂载现有数据目录
- MySQL 采用逻辑迁移,不直接接管旧 datadir
- Keycloak 改为 MySQL,走 export / import 迁移
- 敏感信息统一放
.env - 版本先保持现状,不升级大版本
- Git over SSH 本次先不启用;必要时后续单独设计第二阶段方案
结论
本方案的核心原则是:
- 先完成 Docker 化迁移
- 保持外部域名与功能语义不变
- 优先控制风险与保留回滚能力
- 不把“迁移”与“升级”混在同一轮进行
在此基础上,下一步可进一步补充:
compose.yaml草案.env模板- 精确到命令级的实施 checklist