Initial sanitized deployment snapshot
This commit is contained in:
17
README.md
Normal file
17
README.md
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
# HangmanLab.Server.T0
|
||||||
|
|
||||||
|
Sanitized deployment snapshot for the Dockerized `vps.git` stack.
|
||||||
|
|
||||||
|
Included:
|
||||||
|
- `git-kc/compose.yaml`
|
||||||
|
- `git-kc/env.template`
|
||||||
|
- `git-kc/mysql/init/01-init-databases.sh`
|
||||||
|
- `git-kc/gitea/app.ini.redacted`
|
||||||
|
- `git-kc/docs/`
|
||||||
|
- `logs/VPS_GIT_WORKLOG_2026-03-20.md`
|
||||||
|
|
||||||
|
Excluded on purpose:
|
||||||
|
- `.env`
|
||||||
|
- database dumps / backups
|
||||||
|
- Keycloak realm export files
|
||||||
|
- raw secrets / tokens / passwords
|
||||||
112
git-kc/compose.yaml
Normal file
112
git-kc/compose.yaml
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
# Draft target path on vps.git: ~/git-kc/compose.yaml
|
||||||
|
# Notes:
|
||||||
|
# - Keep nginx on the host.
|
||||||
|
# - Keep MySQL private inside the Docker network.
|
||||||
|
# - First migration run: Keycloak uses --import-realm.
|
||||||
|
# After successful import, you may remove --import-realm for steady-state.
|
||||||
|
# - This draft assumes Gitea SSH is disabled for phase 1.
|
||||||
|
|
||||||
|
services:
|
||||||
|
mysql:
|
||||||
|
image: ${MYSQL_IMAGE}
|
||||||
|
container_name: git-kc-mysql
|
||||||
|
restart: unless-stopped
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
environment:
|
||||||
|
TZ: ${TZ}
|
||||||
|
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
|
||||||
|
command:
|
||||||
|
- --character-set-server=utf8mb4
|
||||||
|
- --collation-server=utf8mb4_0900_ai_ci
|
||||||
|
- --default-authentication-plugin=caching_sha2_password
|
||||||
|
- --skip-name-resolve
|
||||||
|
volumes:
|
||||||
|
- ./mysql/data:/var/lib/mysql
|
||||||
|
- ./mysql/init:/docker-entrypoint-initdb.d:ro
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "mysqladmin ping -uroot -p$$MYSQL_ROOT_PASSWORD --silent"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 12
|
||||||
|
start_period: 20s
|
||||||
|
networks:
|
||||||
|
- git-kc-net
|
||||||
|
|
||||||
|
gitea:
|
||||||
|
image: ${GITEA_IMAGE}
|
||||||
|
container_name: git-kc-gitea
|
||||||
|
restart: unless-stopped
|
||||||
|
depends_on:
|
||||||
|
mysql:
|
||||||
|
condition: service_healthy
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
user: "${GITEA_UID}:${GITEA_GID}"
|
||||||
|
environment:
|
||||||
|
TZ: ${TZ}
|
||||||
|
USER_UID: ${GITEA_UID}
|
||||||
|
USER_GID: ${GITEA_GID}
|
||||||
|
HOME: /home/git
|
||||||
|
GITEA_WORK_DIR: /var/lib/gitea
|
||||||
|
GITEA_CUSTOM: /var/lib/gitea/custom
|
||||||
|
working_dir: /var/lib/gitea
|
||||||
|
command: ["gitea", "web", "--config", "/etc/gitea/app.ini"]
|
||||||
|
ports:
|
||||||
|
- "${GITEA_HOST_BIND}:${GITEA_HTTP_PORT}:3000"
|
||||||
|
volumes:
|
||||||
|
- /var/lib/gitea:/var/lib/gitea
|
||||||
|
- /home/git:/home/git
|
||||||
|
- ./gitea/app.ini:/etc/gitea/app.ini:ro
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "wget -q -O /dev/null http://localhost:3000/ || exit 1"]
|
||||||
|
interval: 15s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 10
|
||||||
|
start_period: 30s
|
||||||
|
networks:
|
||||||
|
- git-kc-net
|
||||||
|
|
||||||
|
keycloak:
|
||||||
|
image: ${KEYCLOAK_IMAGE}
|
||||||
|
container_name: git-kc-keycloak
|
||||||
|
restart: unless-stopped
|
||||||
|
depends_on:
|
||||||
|
mysql:
|
||||||
|
condition: service_healthy
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
environment:
|
||||||
|
TZ: ${TZ}
|
||||||
|
KC_DB: mysql
|
||||||
|
KC_DB_URL_HOST: ${KC_DB_URL_HOST}
|
||||||
|
KC_DB_URL_PORT: ${KC_DB_URL_PORT}
|
||||||
|
KC_DB_URL_DATABASE: ${KC_DB_URL_DATABASE}
|
||||||
|
KC_DB_USERNAME: ${KC_DB_USERNAME}
|
||||||
|
KC_DB_PASSWORD: ${KC_DB_PASSWORD}
|
||||||
|
KC_HOSTNAME: ${KC_HOSTNAME}
|
||||||
|
KC_HTTP_ENABLED: "true"
|
||||||
|
KC_PROXY_HEADERS: xforwarded
|
||||||
|
KC_HEALTH_ENABLED: "true"
|
||||||
|
KC_METRICS_ENABLED: "true"
|
||||||
|
KC_BOOTSTRAP_ADMIN_USERNAME: ${KC_BOOTSTRAP_ADMIN_USERNAME}
|
||||||
|
KC_BOOTSTRAP_ADMIN_PASSWORD: ${KC_BOOTSTRAP_ADMIN_PASSWORD}
|
||||||
|
command:
|
||||||
|
- start
|
||||||
|
ports:
|
||||||
|
- "${KEYCLOAK_HOST_BIND}:${KEYCLOAK_HTTP_PORT}:8080"
|
||||||
|
volumes:
|
||||||
|
- ./keycloak/import:/opt/keycloak/data/import:ro
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "bash -c 'exec 3<>/dev/tcp/localhost/8080' && exit 0 || exit 1"]
|
||||||
|
interval: 15s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 20
|
||||||
|
start_period: 45s
|
||||||
|
networks:
|
||||||
|
- git-kc-net
|
||||||
|
|
||||||
|
networks:
|
||||||
|
git-kc-net:
|
||||||
|
name: ${DOCKER_NETWORK_NAME}
|
||||||
|
driver: bridge
|
||||||
447
git-kc/docs/CHECKLIST.md
Normal file
447
git-kc/docs/CHECKLIST.md
Normal file
@@ -0,0 +1,447 @@
|
|||||||
|
# vps.git Docker 迁移 Checklist
|
||||||
|
|
||||||
|
> 目标:将 `vps.git` 上的 Gitea、Keycloak、MySQL 迁移到 Docker;宿主机 nginx 保持不动。
|
||||||
|
>
|
||||||
|
> 当前约束:
|
||||||
|
> - Gitea / Keycloak / MySQL 进入同一个 Docker 网络
|
||||||
|
> - MySQL 为单实例,内部拆分 `<gitea_db>` / `<keycloak_db>`
|
||||||
|
> - Gitea 直接挂载旧目录
|
||||||
|
> - Keycloak 从 H2 迁移到 MySQL
|
||||||
|
> - 本次先不启用 Git over SSH
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 0. 迁移前确认
|
||||||
|
|
||||||
|
- [ ] 确认维护窗口可开始
|
||||||
|
- [ ] 确认当前整机备份已存在
|
||||||
|
- [ ] 确认当前无人依赖 Git over SSH
|
||||||
|
- [ ] 确认本次不做大版本升级
|
||||||
|
- [ ] 确认宿主机 nginx 保持不动
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. 安装 Docker Engine(vps.git)
|
||||||
|
|
||||||
|
推荐使用 Docker 官方仓库安装。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
apt-get update
|
||||||
|
apt-get install -y ca-certificates curl gnupg
|
||||||
|
install -m 0755 -d /etc/apt/keyrings
|
||||||
|
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
|
||||||
|
chmod a+r /etc/apt/keyrings/docker.gpg
|
||||||
|
|
||||||
|
echo \
|
||||||
|
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
|
||||||
|
$(. /etc/os-release && echo \"$VERSION_CODENAME\") stable" \
|
||||||
|
| tee /etc/apt/sources.list.d/docker.list > /dev/null
|
||||||
|
|
||||||
|
apt-get update
|
||||||
|
apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
|
||||||
|
|
||||||
|
docker --version
|
||||||
|
docker compose version
|
||||||
|
```
|
||||||
|
|
||||||
|
验收:
|
||||||
|
- [ ] `docker --version` 正常
|
||||||
|
- [ ] `docker compose version` 正常
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 准备部署目录
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir -p ~/git-kc/{backups,docs,gitea,keycloak/import,mysql/data,mysql/init}
|
||||||
|
chmod 700 ~/git-kc
|
||||||
|
```
|
||||||
|
|
||||||
|
验收:
|
||||||
|
- [ ] `~/git-kc` 已创建
|
||||||
|
- [ ] 子目录结构完整
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 准备 compose 与 .env
|
||||||
|
|
||||||
|
将以下草案文件放到目标目录:
|
||||||
|
|
||||||
|
- `compose.yaml`
|
||||||
|
- `.env`
|
||||||
|
|
||||||
|
来源建议:
|
||||||
|
- 使用 workspace 内草案:
|
||||||
|
- `VPS_GIT_DOCKER_COMPOSE_DRAFT.yaml`
|
||||||
|
- `VPS_GIT_DOCKER_ENV_TEMPLATE.env`
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp VPS_GIT_DOCKER_COMPOSE_DRAFT.yaml ~/git-kc/compose.yaml
|
||||||
|
cp VPS_GIT_DOCKER_ENV_TEMPLATE.env ~/git-kc/.env
|
||||||
|
chmod 600 ~/git-kc/.env
|
||||||
|
```
|
||||||
|
|
||||||
|
然后填写真实密码,并把 `GITEA_UID/GITEA_GID` 改成宿主机 `git` 用户实际数值:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
id -u git
|
||||||
|
id -g git
|
||||||
|
```
|
||||||
|
|
||||||
|
验收:
|
||||||
|
- [ ] `~/git-kc/compose.yaml` 已就位
|
||||||
|
- [ ] `~/git-kc/.env` 已填写真实密码
|
||||||
|
- [ ] `GITEA_UID/GITEA_GID` 已按实际值修正
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. 准备 Gitea 配置副本
|
||||||
|
|
||||||
|
复制现有配置,不直接原地改 `/etc/gitea/app.ini`。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp /etc/gitea/app.ini ~/git-kc/gitea/app.ini
|
||||||
|
```
|
||||||
|
|
||||||
|
需要修改的核心项:
|
||||||
|
|
||||||
|
- [ ] `[database] HOST = mysql:3306`
|
||||||
|
- [ ] 保持 `DB_TYPE = mysql`
|
||||||
|
- [ ] `NAME = <gitea_db>`
|
||||||
|
- [ ] `USER = gitea`
|
||||||
|
- [ ] `PASSWD = <新的 Docker MySQL 中 gitea 用户密码>`
|
||||||
|
- [ ] 保持 `ROOT_URL = https://git.hangman-lab.top/`
|
||||||
|
- [ ] 本次先不启用 Git over SSH
|
||||||
|
- [ ] 在 `app.ini` 中显式设置 `DISABLE_SSH = true`
|
||||||
|
- [ ] 如存在 `START_SSH_SERVER`,显式设置为 `false`
|
||||||
|
- [ ] 检查页面不再误导用户展示不可用的 SSH clone/push 路径
|
||||||
|
|
||||||
|
建议先备份副本再改:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp ~/git-kc/gitea/app.ini ~/git-kc/gitea/app.ini.bak
|
||||||
|
```
|
||||||
|
|
||||||
|
验收:
|
||||||
|
- [ ] `~/git-kc/gitea/app.ini` 已生成
|
||||||
|
- [ ] DB HOST 已改为 `mysql:3306`
|
||||||
|
- [ ] 其他核心业务配置未误改
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. 准备 MySQL 初始化逻辑
|
||||||
|
|
||||||
|
目标:Docker MySQL 首次启动时自动创建:
|
||||||
|
|
||||||
|
- `<gitea_db>`
|
||||||
|
- `<keycloak_db>`
|
||||||
|
- `gitea@'%'`
|
||||||
|
- `keycloak@'%'`
|
||||||
|
|
||||||
|
建议在 `~/git-kc/mysql/init/` 中放一个首次初始化脚本,例如:
|
||||||
|
|
||||||
|
- `01-init-databases.sh`
|
||||||
|
|
||||||
|
workspace 内已提供草案文件:
|
||||||
|
|
||||||
|
- `VPS_GIT_DOCKER_MYSQL_INIT_DRAFT.sh`
|
||||||
|
|
||||||
|
可直接放到目标位置:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp VPS_GIT_DOCKER_MYSQL_INIT_DRAFT.sh ~/git-kc/mysql/init/01-init-databases.sh
|
||||||
|
chmod 755 ~/git-kc/mysql/init/01-init-databases.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
> 如果实施环境不是当前 workspace 所在机器,也需要先把该草案文件同步到 `vps.git`。
|
||||||
|
|
||||||
|
脚本职责:
|
||||||
|
- [ ] 读取 `.env` 中的变量
|
||||||
|
- [ ] 创建两个 database
|
||||||
|
- [ ] 创建两个用户
|
||||||
|
- [ ] 分配最小权限
|
||||||
|
|
||||||
|
> 注意:`docker-entrypoint-initdb.d` 只会在 **空 datadir 第一次启动** 时执行。
|
||||||
|
|
||||||
|
验收:
|
||||||
|
- [ ] 已准备初始化脚本或确认采用手动 SQL 初始化
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. 准备 Keycloak 导出目录
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir -p ~/git-kc/keycloak/import
|
||||||
|
```
|
||||||
|
|
||||||
|
说明:
|
||||||
|
- 旧 Keycloak 导出的 realm 文件,后续放到这里
|
||||||
|
- Docker Keycloak 首次启动时通过 `--import-realm` 导入
|
||||||
|
|
||||||
|
验收:
|
||||||
|
- [ ] `~/git-kc/keycloak/import` 已存在
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. 预拉取镜像(切换前)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/git-kc
|
||||||
|
docker compose --env-file .env pull
|
||||||
|
```
|
||||||
|
|
||||||
|
验收:
|
||||||
|
- [ ] MySQL 镜像拉取成功
|
||||||
|
- [ ] Gitea 镜像拉取成功
|
||||||
|
- [ ] Keycloak 镜像拉取成功
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. 迁移前备份
|
||||||
|
|
||||||
|
### 8.1 备份 Gitea 配置
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp /etc/gitea/app.ini ~/git-kc/backups/app.ini.$(date +%F-%H%M%S).bak
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] 已备份 `/etc/gitea/app.ini`
|
||||||
|
|
||||||
|
### 8.2 导出 Gitea 数据库
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mysqldump \
|
||||||
|
--single-transaction \
|
||||||
|
--routines \
|
||||||
|
--triggers \
|
||||||
|
--events \
|
||||||
|
<gitea_db> > ~/git-kc/backups/<gitea_db>.$(date +%F-%H%M%S).sql
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] 已导出 `<gitea_db>`
|
||||||
|
|
||||||
|
### 8.3 导出 Keycloak(H2)
|
||||||
|
|
||||||
|
先停止旧 Keycloak,再执行离线导出:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
systemctl stop keycloak
|
||||||
|
sudo -u keycloak /opt/keycloak/bin/kc.sh export \
|
||||||
|
--dir ~/git-kc/keycloak/import \
|
||||||
|
--users realm_file
|
||||||
|
```
|
||||||
|
|
||||||
|
> 如果导出目录权限有问题,可先导出到 `/tmp` 或 keycloak 用户可写目录,再移动到 `~/git-kc/keycloak/import/`。
|
||||||
|
|
||||||
|
- [ ] 已导出 Keycloak realm / users
|
||||||
|
|
||||||
|
### 8.4 备份 nginx 相关配置
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp /etc/nginx/sites-enabled/git.hangman-lab.top ~/git-kc/backups/git.hangman-lab.top.$(date +%F-%H%M%S).bak
|
||||||
|
cp /etc/nginx/sites-enabled/login.hangman-lab.top ~/git-kc/backups/login.hangman-lab.top.$(date +%F-%H%M%S).bak
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] 已备份 nginx 站点配置
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. 切换阶段
|
||||||
|
|
||||||
|
### 9.1 停止旧服务
|
||||||
|
|
||||||
|
```bash
|
||||||
|
systemctl stop gitea
|
||||||
|
systemctl stop keycloak
|
||||||
|
systemctl stop mysql
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] 旧 Gitea 已停
|
||||||
|
- [ ] 旧 Keycloak 已停
|
||||||
|
- [ ] 旧 MySQL 已停
|
||||||
|
|
||||||
|
### 9.2 启动 Docker MySQL
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/git-kc
|
||||||
|
docker compose --env-file .env up -d mysql
|
||||||
|
docker compose ps
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] MySQL 容器已启动
|
||||||
|
- [ ] MySQL healthcheck 正常
|
||||||
|
|
||||||
|
### 9.3 初始化数据库
|
||||||
|
|
||||||
|
如果已准备 `mysql/init` 初始化脚本:
|
||||||
|
- [ ] 确认第一次启动已执行成功
|
||||||
|
|
||||||
|
如果采用手动方式,执行 SQL 初始化:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker exec -it git-kc-mysql mysql -uroot -p
|
||||||
|
```
|
||||||
|
|
||||||
|
手动创建:
|
||||||
|
- [ ] `<gitea_db>`
|
||||||
|
- [ ] `<keycloak_db>`
|
||||||
|
- [ ] `gitea` 用户及权限
|
||||||
|
- [ ] `keycloak` 用户及权限
|
||||||
|
|
||||||
|
### 9.4 导入 Gitea 数据库
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cat ~/git-kc/backups/<gitea_db>.<timestamp>.sql | docker exec -i git-kc-mysql mysql -uroot -p${MYSQL_ROOT_PASSWORD} <gitea_db>
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] `<gitea_db>` 已导入
|
||||||
|
|
||||||
|
### 9.5 启动 Docker Keycloak
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/git-kc
|
||||||
|
docker compose --env-file .env up -d keycloak
|
||||||
|
docker compose logs --tail=200 keycloak
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] Keycloak 容器已启动
|
||||||
|
- [ ] import 完成
|
||||||
|
- [ ] 无明显启动报错
|
||||||
|
|
||||||
|
### 9.6 启动 Docker Gitea
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/git-kc
|
||||||
|
docker compose --env-file .env up -d gitea
|
||||||
|
docker compose logs --tail=200 gitea
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] Gitea 容器已启动
|
||||||
|
- [ ] 无明显启动报错
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10. 修改 nginx(仅 Keycloak upstream)
|
||||||
|
|
||||||
|
目标变更:
|
||||||
|
|
||||||
|
- 从 `proxy_pass https://localhost:8443;`
|
||||||
|
- 改为 `proxy_pass http://localhost:8080;`
|
||||||
|
|
||||||
|
同时确认保留:
|
||||||
|
|
||||||
|
- `proxy_set_header Host $host;`
|
||||||
|
- `proxy_set_header X-Real-IP $remote_addr;`
|
||||||
|
- `proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;`
|
||||||
|
- `proxy_set_header X-Forwarded-Proto $scheme;`
|
||||||
|
|
||||||
|
验证并重载:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nginx -t
|
||||||
|
systemctl reload nginx
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] nginx 配置校验通过
|
||||||
|
- [ ] nginx 已 reload
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 11. 验证阶段
|
||||||
|
|
||||||
|
### 11.1 验证 Gitea
|
||||||
|
|
||||||
|
- [ ] `https://git.hangman-lab.top/` 可访问
|
||||||
|
- [ ] 首页正常
|
||||||
|
- [ ] 用户可登录
|
||||||
|
- [ ] 仓库列表正常
|
||||||
|
- [ ] 现有仓库可见
|
||||||
|
- [ ] HTTPS clone 正常
|
||||||
|
- [ ] HTTPS push 正常
|
||||||
|
- [ ] OIDC 跳转到 Keycloak 正常
|
||||||
|
- [ ] 从 Keycloak 回跳 Gitea 正常
|
||||||
|
|
||||||
|
### 11.2 验证 Keycloak
|
||||||
|
|
||||||
|
- [ ] `https://login.hangman-lab.top/` 可访问
|
||||||
|
- [ ] `/.well-known/openid-configuration` 正常
|
||||||
|
- [ ] `Hangman-Lab` realm 正常
|
||||||
|
- [ ] 管理后台可登录
|
||||||
|
- [ ] 普通用户可登录
|
||||||
|
- [ ] 原 client 保留
|
||||||
|
- [ ] issuer 与原来一致
|
||||||
|
|
||||||
|
### 11.3 验证 MySQL
|
||||||
|
|
||||||
|
- [ ] `<gitea_db>` 表完整
|
||||||
|
- [ ] `<keycloak_db>` 表完整
|
||||||
|
- [ ] Gitea 能正常连接 MySQL
|
||||||
|
- [ ] Keycloak 能正常连接 MySQL
|
||||||
|
|
||||||
|
### 11.4 验证 Docker 重启持久化
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose --env-file ~/git-kc/.env -f ~/git-kc/compose.yaml restart
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] 三个容器重启后仍正常
|
||||||
|
- [ ] 数据未丢失
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 12. 回滚 Checklist
|
||||||
|
|
||||||
|
如果验证失败,执行回滚:
|
||||||
|
|
||||||
|
### 12.1 停止 Docker 服务
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/git-kc
|
||||||
|
docker compose --env-file .env down
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] Docker 容器已停
|
||||||
|
|
||||||
|
### 12.2 恢复 nginx Keycloak upstream
|
||||||
|
|
||||||
|
- [ ] 将 `http://localhost:8080` 改回 `https://localhost:8443`
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nginx -t
|
||||||
|
systemctl reload nginx
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] nginx 已恢复
|
||||||
|
|
||||||
|
### 12.3 启动旧宿主机服务
|
||||||
|
|
||||||
|
```bash
|
||||||
|
systemctl start mysql
|
||||||
|
systemctl start keycloak
|
||||||
|
systemctl start gitea
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] 旧 MySQL 已恢复
|
||||||
|
- [ ] 旧 Keycloak 已恢复
|
||||||
|
- [ ] 旧 Gitea 已恢复
|
||||||
|
|
||||||
|
### 12.4 回滚验证
|
||||||
|
|
||||||
|
- [ ] Gitea 页面恢复
|
||||||
|
- [ ] Keycloak 页面恢复
|
||||||
|
- [ ] Gitea 登录恢复
|
||||||
|
- [ ] OIDC 恢复
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 13. 迁移后待办(非本次切换阻塞项)
|
||||||
|
|
||||||
|
- [ ] 清理 Keycloak 首次导入相关临时文件
|
||||||
|
- [ ] 视情况去掉 Keycloak `--import-realm`
|
||||||
|
- [ ] 评估是否恢复 Git over SSH
|
||||||
|
- [ ] 如需恢复 Git over SSH,单独设计第二阶段方案
|
||||||
|
- [ ] 更新与 Docker 化相关的运维脚本
|
||||||
|
<EFBFBD><EFBFBD>第二阶段方案
|
||||||
|
- [ ] 更新与 Docker 化相关的运维脚本
|
||||||
|
<EFBFBD>案
|
||||||
|
- [ ] 更新与 Docker 化相关的运维脚本
|
||||||
526
git-kc/docs/PLAN.md
Normal file
526
git-kc/docs/PLAN.md
Normal file
@@ -0,0 +1,526 @@
|
|||||||
|
# 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 正常
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 当前现状摘要
|
||||||
|
|
||||||
|
### 服务现状
|
||||||
|
|
||||||
|
宿主机当前运行:
|
||||||
|
|
||||||
|
- `nginx`
|
||||||
|
- `gitea.service`
|
||||||
|
- `keycloak.service`
|
||||||
|
- `mysql.service`
|
||||||
|
|
||||||
|
### 监听关系
|
||||||
|
|
||||||
|
- `nginx`:对外 `80/443`
|
||||||
|
- `gitea`:宿主机监听 `3000`
|
||||||
|
- `keycloak`:宿主机监听 `8443`
|
||||||
|
- `mysql`:宿主机监听 `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 内运行
|
||||||
|
|
||||||
|
- `mysql`
|
||||||
|
- `gitea`
|
||||||
|
- `keycloak`
|
||||||
|
|
||||||
|
三者放在同一个 Docker 网络中,例如:
|
||||||
|
|
||||||
|
- `git-kc-net`
|
||||||
|
|
||||||
|
### 端口策略
|
||||||
|
|
||||||
|
- `mysql`
|
||||||
|
- 不对宿主机发布端口
|
||||||
|
- 仅允许 Docker 内部网络访问
|
||||||
|
- `gitea`
|
||||||
|
- 发布到 `localhost:3000`
|
||||||
|
- `keycloak`
|
||||||
|
- 发布到 `localhost:8080`
|
||||||
|
|
||||||
|
### nginx 反代目标
|
||||||
|
|
||||||
|
- `git.hangman-lab.top` → `http://localhost:3000`
|
||||||
|
- `login.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 运行目录,而是:
|
||||||
|
|
||||||
|
1. 从旧 Keycloak 执行 realm export
|
||||||
|
2. 在 Docker Keycloak 中导入 realm
|
||||||
|
3. 新容器改用 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>`
|
||||||
|
|
||||||
|
分别创建独立账户:
|
||||||
|
|
||||||
|
- `gitea`
|
||||||
|
- `keycloak`
|
||||||
|
|
||||||
|
权限原则:
|
||||||
|
|
||||||
|
- `gitea` 仅访问 `<gitea_db>`
|
||||||
|
- `keycloak` 仅访问 `<keycloak_db>`
|
||||||
|
|
||||||
|
字符集与排序规则保持与当前环境一致:
|
||||||
|
|
||||||
|
- `utf8mb4`
|
||||||
|
- `utf8mb4_0900_ai_ci`
|
||||||
|
|
||||||
|
说明:
|
||||||
|
|
||||||
|
- 是“共用一个 MySQL 容器实例”
|
||||||
|
- 不是“共用同一个 database/schema”
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Gitea 容器设计
|
||||||
|
|
||||||
|
### 运行目标
|
||||||
|
|
||||||
|
迁移后保持:
|
||||||
|
|
||||||
|
- 域名不变
|
||||||
|
- 数据目录不变
|
||||||
|
- 仓库、用户、OIDC、package 等数据保留
|
||||||
|
- 本次先不启用 Git over SSH
|
||||||
|
|
||||||
|
### 配置原则
|
||||||
|
|
||||||
|
基于现有 `app.ini` 的副本进行调整,重点改动:
|
||||||
|
|
||||||
|
- `[database] HOST`
|
||||||
|
- 从 `localhost:3306`
|
||||||
|
- 改为 `mysql:3306`
|
||||||
|
|
||||||
|
其余核心配置尽量保持不变,例如:
|
||||||
|
|
||||||
|
- `ROOT_URL`
|
||||||
|
- `APP_DATA_PATH`
|
||||||
|
- `repository ROOT`
|
||||||
|
- `oauth2/openid`
|
||||||
|
- `security`
|
||||||
|
- `service`
|
||||||
|
- `package/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=mysql`
|
||||||
|
- `KC_DB_URL_HOST=mysql`
|
||||||
|
- `KC_DB_URL_DATABASE=<keycloak_db>`
|
||||||
|
- `KC_DB_USERNAME`
|
||||||
|
- `KC_DB_PASSWORD`
|
||||||
|
- `KC_HOSTNAME=login.hangman-lab.top`
|
||||||
|
- `KC_HTTP_ENABLED=true`
|
||||||
|
- `KC_PROXY_HEADERS=xforwarded`
|
||||||
|
|
||||||
|
说明:
|
||||||
|
|
||||||
|
- Docker Keycloak 不再自行持有 TLS 证书
|
||||||
|
- nginx 负责 HTTPS
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## nginx 变更原则
|
||||||
|
|
||||||
|
宿主机 nginx 架构保持不变。
|
||||||
|
|
||||||
|
### Gitea
|
||||||
|
|
||||||
|
继续反代到:
|
||||||
|
|
||||||
|
- `http://localhost:3000`
|
||||||
|
|
||||||
|
如容器沿用相同宿主端口,Gitea 对应 nginx 配置可能无需变更。
|
||||||
|
|
||||||
|
### Keycloak
|
||||||
|
|
||||||
|
需要把 upstream 从:
|
||||||
|
|
||||||
|
- `https://localhost:8443`
|
||||||
|
|
||||||
|
改为:
|
||||||
|
|
||||||
|
- `http://localhost:8080`
|
||||||
|
|
||||||
|
并保留以下头:
|
||||||
|
|
||||||
|
- `Host`
|
||||||
|
- `X-Real-IP`
|
||||||
|
- `X-Forwarded-For`
|
||||||
|
- `X-Forwarded-Proto`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 迁移实施步骤
|
||||||
|
|
||||||
|
### Phase A:准备阶段
|
||||||
|
|
||||||
|
1. 在 `vps.git` 上安装 Docker Engine 与 Docker Compose Plugin
|
||||||
|
2. 创建目录:
|
||||||
|
- `~/git-kc`
|
||||||
|
- `~/git-kc/backups`
|
||||||
|
- `~/git-kc/mysql`
|
||||||
|
- `~/git-kc/gitea`
|
||||||
|
- `~/git-kc/keycloak/import`
|
||||||
|
- `~/git-kc/docs`
|
||||||
|
3. 编写 `compose.yaml` 与 `.env`
|
||||||
|
4. 复制 Gitea 当前配置:
|
||||||
|
- `/etc/gitea/app.ini` → `~/git-kc/gitea/app.ini`
|
||||||
|
5. 调整 Gitea 容器配置副本中的数据库地址
|
||||||
|
6. 准备 Keycloak 容器参数
|
||||||
|
7. 预拉取固定版本镜像
|
||||||
|
|
||||||
|
### Phase B:备份阶段
|
||||||
|
|
||||||
|
正式切换前执行迁移专用备份:
|
||||||
|
|
||||||
|
1. 备份 `/etc/gitea/app.ini`
|
||||||
|
2. 记录并确认 `/var/lib/gitea` 当前状态
|
||||||
|
3. 导出 Gitea 数据库:`mysqldump <gitea_db>`
|
||||||
|
4. 从旧 Keycloak 导出 realm / users
|
||||||
|
5. 备份 nginx 相关站点配置
|
||||||
|
|
||||||
|
说明:
|
||||||
|
|
||||||
|
- 即使整机已有备份,仍建议保留迁移专用备份,以便快速回滚
|
||||||
|
|
||||||
|
### Phase C:切换阶段
|
||||||
|
|
||||||
|
建议顺序:
|
||||||
|
|
||||||
|
1. 进入维护窗口
|
||||||
|
2. 停止旧 Gitea:`systemctl stop gitea`
|
||||||
|
3. 停止旧 Keycloak:`systemctl stop keycloak`
|
||||||
|
4. 执行 Gitea 最终 SQL 导出
|
||||||
|
5. 执行 Keycloak 最终 export
|
||||||
|
6. 停止旧 MySQL:`systemctl stop mysql`
|
||||||
|
7. 启动 Docker MySQL
|
||||||
|
8. 初始化 Docker MySQL:
|
||||||
|
- 创建 `<gitea_db>`
|
||||||
|
- 创建 `<keycloak_db>`
|
||||||
|
- 创建 `gitea` 用户
|
||||||
|
- 创建 `keycloak` 用户
|
||||||
|
9. 导入 Gitea SQL 到 Docker MySQL
|
||||||
|
10. 启动 Docker Keycloak,并导入 realm
|
||||||
|
11. 启动 Docker Gitea
|
||||||
|
12. 修改 nginx 的 Keycloak upstream:
|
||||||
|
- 从 `https://localhost:8443`
|
||||||
|
- 改为 `http://localhost:8080`
|
||||||
|
13. 执行 `nginx -t`
|
||||||
|
14. 执行 `systemctl reload nginx`
|
||||||
|
15. 执行完整验证
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 验证清单
|
||||||
|
|
||||||
|
### 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
|
||||||
|
- 代理头工作正常
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 回滚方案
|
||||||
|
|
||||||
|
如果迁移后验证失败,按以下顺序回滚:
|
||||||
|
|
||||||
|
1. 停止 Docker 容器:
|
||||||
|
- `gitea`
|
||||||
|
- `keycloak`
|
||||||
|
- `mysql`
|
||||||
|
2. 恢复 nginx 的 Keycloak upstream:
|
||||||
|
- 改回 `https://localhost:8443`
|
||||||
|
3. 启动旧宿主机服务:
|
||||||
|
- `systemctl start mysql`
|
||||||
|
- `systemctl start keycloak`
|
||||||
|
- `systemctl start gitea`
|
||||||
|
4. 执行 `nginx -t`
|
||||||
|
5. 执行 `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
|
||||||
52
git-kc/env.template
Normal file
52
git-kc/env.template
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
# Draft target path on vps.git: ~/git-kc/.env
|
||||||
|
# Fill all placeholders before first docker compose up.
|
||||||
|
|
||||||
|
COMPOSE_PROJECT_NAME=git-kc
|
||||||
|
DOCKER_NETWORK_NAME=git-kc-net
|
||||||
|
TZ=UTC
|
||||||
|
|
||||||
|
# Images (pin versions; do not use latest)
|
||||||
|
MYSQL_IMAGE=mysql:8.0.45
|
||||||
|
GITEA_IMAGE=gitea/gitea:1.22.4
|
||||||
|
KEYCLOAK_IMAGE=quay.io/keycloak/keycloak:26.0.6
|
||||||
|
|
||||||
|
# Host bindings
|
||||||
|
GITEA_HOST_BIND=localhost
|
||||||
|
GITEA_HTTP_PORT=3000
|
||||||
|
KEYCLOAK_HOST_BIND=localhost
|
||||||
|
KEYCLOAK_HTTP_PORT=8080
|
||||||
|
|
||||||
|
# Gitea container runtime user
|
||||||
|
# Replace with: id -u git / id -g git on vps.git
|
||||||
|
GITEA_UID=1001
|
||||||
|
GITEA_GID=1001
|
||||||
|
|
||||||
|
# MySQL root
|
||||||
|
MYSQL_ROOT_PASSWORD=REPLACE_WITH_STRONG_ROOT_PASSWORD
|
||||||
|
|
||||||
|
# Planned logical DB layout inside the single MySQL instance
|
||||||
|
MYSQL_GITEA_DATABASE=<gitea_db>
|
||||||
|
MYSQL_GITEA_USER=gitea
|
||||||
|
MYSQL_GITEA_PASSWORD=REPLACE_WITH_STRONG_GITEA_DB_PASSWORD
|
||||||
|
MYSQL_KEYCLOAK_DATABASE=<keycloak_db>
|
||||||
|
MYSQL_KEYCLOAK_USER=keycloak
|
||||||
|
MYSQL_KEYCLOAK_PASSWORD=REPLACE_WITH_STRONG_KEYCLOAK_DB_PASSWORD
|
||||||
|
|
||||||
|
# Keycloak DB connection
|
||||||
|
KC_DB_URL_HOST=mysql
|
||||||
|
KC_DB_URL_PORT=3306
|
||||||
|
KC_DB_URL_DATABASE=<keycloak_db>
|
||||||
|
KC_DB_USERNAME=keycloak
|
||||||
|
KC_DB_PASSWORD=REPLACE_WITH_STRONG_KEYCLOAK_DB_PASSWORD
|
||||||
|
|
||||||
|
# Keycloak external hostname
|
||||||
|
KC_HOSTNAME=login.hangman-lab.top
|
||||||
|
|
||||||
|
# Bootstrap admin for first start on empty <keycloak_db>
|
||||||
|
# Keep these temporary and rotate/remove after cutover verification if desired.
|
||||||
|
KC_BOOTSTRAP_ADMIN_USERNAME=admin
|
||||||
|
KC_BOOTSTRAP_ADMIN_PASSWORD=REPLACE_WITH_TEMP_BOOTSTRAP_ADMIN_PASSWORD
|
||||||
|
|
||||||
|
# Helpful references (not consumed directly by compose, but useful in ops docs)
|
||||||
|
GITEA_EXTERNAL_URL=https://git.hangman-lab.top/
|
||||||
|
KEYCLOAK_EXTERNAL_URL=https://login.hangman-lab.top/
|
||||||
89
git-kc/gitea/app.ini.redacted
Normal file
89
git-kc/gitea/app.ini.redacted
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
APP_NAME = Hangman-Lab
|
||||||
|
RUN_USER = git
|
||||||
|
WORK_PATH = /var/lib/gitea/
|
||||||
|
RUN_MODE = prod
|
||||||
|
|
||||||
|
[database]
|
||||||
|
DB_TYPE = mysql
|
||||||
|
HOST = mysql:3306
|
||||||
|
NAME = <gitea_db>
|
||||||
|
USER = gitea
|
||||||
|
PASSWD = <redacted>
|
||||||
|
SCHEMA =
|
||||||
|
SSL_MODE = disable
|
||||||
|
PATH = /var/lib/gitea/data/gitea.db
|
||||||
|
LOG_SQL = false
|
||||||
|
|
||||||
|
[repository]
|
||||||
|
ROOT = /var/lib/gitea/data/gitea-repositories
|
||||||
|
ENABLE_PUSH_CREATE_USER = true
|
||||||
|
ENABLE_PUSH_CREATE_ORG = true
|
||||||
|
|
||||||
|
[server]
|
||||||
|
#PROTOCOL = https
|
||||||
|
#CERT_FILE = /etc/letsencrypt/live/git.hangman-lab.top/fullchain.pem
|
||||||
|
#KEY_FILE = /etc/letsencrypt/live/git.hangman-lab.top/privkey.pem
|
||||||
|
SSH_DOMAIN = git.hangman-lab.top
|
||||||
|
DOMAIN = git.hangman-lab.top
|
||||||
|
HTTP_PORT = 3000
|
||||||
|
ROOT_URL = https://git.hangman-lab.top/
|
||||||
|
APP_DATA_PATH = /var/lib/gitea/data
|
||||||
|
DISABLE_SSH = true
|
||||||
|
SSH_PORT = 22
|
||||||
|
LFS_START_SERVER = true
|
||||||
|
LFS_JWT_SECRET = <redacted>
|
||||||
|
OFFLINE_MODE = true
|
||||||
|
|
||||||
|
START_SSH_SERVER = false
|
||||||
|
[lfs]
|
||||||
|
PATH = /var/lib/gitea/data/lfs
|
||||||
|
|
||||||
|
[mailer]
|
||||||
|
ENABLED = false
|
||||||
|
|
||||||
|
[service]
|
||||||
|
REGISTER_EMAIL_CONFIRM = false
|
||||||
|
ENABLE_NOTIFY_MAIL = false
|
||||||
|
DISABLE_REGISTRATION = true
|
||||||
|
ALLOW_ONLY_EXTERNAL_REGISTRATION = false
|
||||||
|
ENABLE_CAPTCHA = false
|
||||||
|
REQUIRE_SIGNIN_VIEW = false
|
||||||
|
DEFAULT_KEEP_EMAIL_PRIVATE = false
|
||||||
|
DEFAULT_ALLOW_CREATE_ORGANIZATION = true
|
||||||
|
DEFAULT_ENABLE_TIMETRACKING = true
|
||||||
|
NO_REPLY_ADDRESS = noreply.localhost
|
||||||
|
|
||||||
|
[openid]
|
||||||
|
ENABLE_OPENID_SIGNIN = false
|
||||||
|
ENABLE_OPENID_SIGNUP = false
|
||||||
|
|
||||||
|
[cron.update_checker]
|
||||||
|
ENABLED = false
|
||||||
|
|
||||||
|
[session]
|
||||||
|
PROVIDER = file
|
||||||
|
|
||||||
|
[log]
|
||||||
|
MODE = file
|
||||||
|
LEVEL = info
|
||||||
|
ROOT_PATH = /var/lib/gitea/log
|
||||||
|
|
||||||
|
[repository.pull-request]
|
||||||
|
DEFAULT_MERGE_STYLE = merge
|
||||||
|
|
||||||
|
[repository.signing]
|
||||||
|
DEFAULT_TRUST_MODEL = committer
|
||||||
|
|
||||||
|
[security]
|
||||||
|
INSTALL_LOCK = true
|
||||||
|
INTERNAL_TOKEN = <redacted>
|
||||||
|
PASSWORD_HASH_ALGO = pbkdf2
|
||||||
|
|
||||||
|
[oauth2]
|
||||||
|
JWT_SECRET = <redacted>
|
||||||
|
ENABLE_OPENID_CONNECT = true
|
||||||
|
ENABLED = true
|
||||||
|
[openid]
|
||||||
|
ENABLE = true
|
||||||
|
[auth]
|
||||||
|
REQUIRE_EXTERNAL_LOGIN = true
|
||||||
59
git-kc/mysql/init/01-init-databases.sh
Executable file
59
git-kc/mysql/init/01-init-databases.sh
Executable file
@@ -0,0 +1,59 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Draft target path on vps.git: ~/git-kc/mysql/init/01-init-databases.sh
|
||||||
|
# Runs inside the official MySQL container on first initialization only
|
||||||
|
# (i.e. only when /var/lib/mysql is empty).
|
||||||
|
|
||||||
|
set -Eeuo pipefail
|
||||||
|
|
||||||
|
required_vars=(
|
||||||
|
MYSQL_ROOT_PASSWORD
|
||||||
|
MYSQL_GITEA_DATABASE
|
||||||
|
MYSQL_GITEA_USER
|
||||||
|
MYSQL_GITEA_PASSWORD
|
||||||
|
MYSQL_KEYCLOAK_DATABASE
|
||||||
|
MYSQL_KEYCLOAK_USER
|
||||||
|
MYSQL_KEYCLOAK_PASSWORD
|
||||||
|
)
|
||||||
|
|
||||||
|
for var in "${required_vars[@]}"; do
|
||||||
|
if [[ -z "${!var:-}" ]]; then
|
||||||
|
echo "[ERROR] Required environment variable is missing: $var" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
sql_escape() {
|
||||||
|
printf '%s' "$1" | sed "s/'/''/g"
|
||||||
|
}
|
||||||
|
|
||||||
|
MYSQL_ROOT_PASSWORD_SQL=$(sql_escape "${MYSQL_ROOT_PASSWORD}")
|
||||||
|
MYSQL_GITEA_PASSWORD_SQL=$(sql_escape "${MYSQL_GITEA_PASSWORD}")
|
||||||
|
MYSQL_KEYCLOAK_PASSWORD_SQL=$(sql_escape "${MYSQL_KEYCLOAK_PASSWORD}")
|
||||||
|
|
||||||
|
cat <<EOF
|
||||||
|
[INFO] Initializing MySQL logical layout...
|
||||||
|
[INFO] Gitea DB: ${MYSQL_GITEA_DATABASE}
|
||||||
|
[INFO] Keycloak DB: ${MYSQL_KEYCLOAK_DATABASE}
|
||||||
|
[INFO] Gitea user: ${MYSQL_GITEA_USER}@'%'
|
||||||
|
[INFO] Keycloak user: ${MYSQL_KEYCLOAK_USER}@'%'
|
||||||
|
EOF
|
||||||
|
|
||||||
|
mysql --protocol=socket -uroot -p"${MYSQL_ROOT_PASSWORD}" <<SQL
|
||||||
|
CREATE DATABASE IF NOT EXISTS \`${MYSQL_GITEA_DATABASE}\`
|
||||||
|
CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
|
||||||
|
|
||||||
|
CREATE DATABASE IF NOT EXISTS \`${MYSQL_KEYCLOAK_DATABASE}\`
|
||||||
|
CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
|
||||||
|
|
||||||
|
CREATE USER IF NOT EXISTS '${MYSQL_GITEA_USER}'@'%' IDENTIFIED BY '${MYSQL_GITEA_PASSWORD_SQL}';
|
||||||
|
ALTER USER '${MYSQL_GITEA_USER}'@'%' IDENTIFIED BY '${MYSQL_GITEA_PASSWORD_SQL}';
|
||||||
|
GRANT ALL PRIVILEGES ON \`${MYSQL_GITEA_DATABASE}\`.* TO '${MYSQL_GITEA_USER}'@'%';
|
||||||
|
|
||||||
|
CREATE USER IF NOT EXISTS '${MYSQL_KEYCLOAK_USER}'@'%' IDENTIFIED BY '${MYSQL_KEYCLOAK_PASSWORD_SQL}';
|
||||||
|
ALTER USER '${MYSQL_KEYCLOAK_USER}'@'%' IDENTIFIED BY '${MYSQL_KEYCLOAK_PASSWORD_SQL}';
|
||||||
|
GRANT ALL PRIVILEGES ON \`${MYSQL_KEYCLOAK_DATABASE}\`.* TO '${MYSQL_KEYCLOAK_USER}'@'%';
|
||||||
|
|
||||||
|
FLUSH PRIVILEGES;
|
||||||
|
SQL
|
||||||
|
|
||||||
|
echo "[INFO] MySQL logical layout initialized successfully."
|
||||||
416
logs/VPS_GIT_WORKLOG_2026-03-20.md
Normal file
416
logs/VPS_GIT_WORKLOG_2026-03-20.md
Normal file
@@ -0,0 +1,416 @@
|
|||||||
|
# vps.git 工作日志(2026-03-20)
|
||||||
|
|
||||||
|
> 记录人:晨曦 / Orion
|
||||||
|
> 范围:今天在 `vps.git` 上执行的排查、迁移、升级与清理操作
|
||||||
|
> 说明:本日志按实际执行顺序整理,便于后续审计、回顾与回滚分析。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. 迁移前探测与现状确认
|
||||||
|
|
||||||
|
对 `vps.git` 做了只读探测,确认了原始部署情况:
|
||||||
|
|
||||||
|
- 宿主机为 Ubuntu 24.04.1 LTS
|
||||||
|
- 原先运行的裸机服务:
|
||||||
|
- `nginx`
|
||||||
|
- `gitea.service`
|
||||||
|
- `keycloak.service`
|
||||||
|
- `mysql.service`
|
||||||
|
- 原始端口/流量结构:
|
||||||
|
- `nginx` 对外提供 80/443
|
||||||
|
- `gitea` 裸机监听 3000,由 nginx 反代
|
||||||
|
- `keycloak` 裸机监听 8443,由 nginx 反代
|
||||||
|
- `mysql` 裸机监听 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.45`
|
||||||
|
|
||||||
|
同时确认:
|
||||||
|
|
||||||
|
- Git over SSH 当前无人使用
|
||||||
|
- Gitea 与 Keycloak 均通过域名正常对外暴露
|
||||||
|
- Keycloak 的 `Hangman-Lab` realm 为后续重点保留对象
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 迁移方案设计与落盘
|
||||||
|
|
||||||
|
在 workspace 中编写并落盘了以下迁移材料:
|
||||||
|
|
||||||
|
- `VPS_GIT_DOCKER_MIGRATION_PLAN.md`
|
||||||
|
- `VPS_GIT_DOCKER_COMPOSE_DRAFT.yaml`
|
||||||
|
- `VPS_GIT_DOCKER_ENV_TEMPLATE.env`
|
||||||
|
- `VPS_GIT_DOCKER_MIGRATION_CHECKLIST.md`
|
||||||
|
- `VPS_GIT_DOCKER_MYSQL_INIT_DRAFT.sh`
|
||||||
|
|
||||||
|
这些材料覆盖了:
|
||||||
|
|
||||||
|
- Docker 化目标架构
|
||||||
|
- compose 草案
|
||||||
|
- `.env` 模板
|
||||||
|
- MySQL 初始化逻辑
|
||||||
|
- 实施顺序与回滚顺序
|
||||||
|
- 验证点与风险点
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 在 vps.git 上安装 Docker 环境
|
||||||
|
|
||||||
|
执行了 Docker 环境准备:
|
||||||
|
|
||||||
|
- 安装 Docker Engine
|
||||||
|
- 安装 Docker Compose Plugin
|
||||||
|
- 验证 `docker --version` 与 `docker compose version`
|
||||||
|
|
||||||
|
然后创建了部署目录:
|
||||||
|
|
||||||
|
- `/root/git-kc`
|
||||||
|
- `/root/git-kc/backups`
|
||||||
|
- `/root/git-kc/docs`
|
||||||
|
- `/root/git-kc/gitea`
|
||||||
|
- `/root/git-kc/keycloak/import`
|
||||||
|
- `/root/git-kc/mysql/data`
|
||||||
|
- `/root/git-kc/mysql/init`
|
||||||
|
|
||||||
|
并把 workspace 里的草案文件同步到 `vps.git`。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. 生成部署配置与准备 Gitea 容器配置
|
||||||
|
|
||||||
|
在 `vps.git` 上:
|
||||||
|
|
||||||
|
- 根据模板生成了 `/root/git-kc/.env`
|
||||||
|
- 为 MySQL root、Gitea DB、Keycloak DB、Keycloak bootstrap admin 生成了随机密码
|
||||||
|
- 将宿主机 `git` 用户的真实 UID/GID 写入 `.env`
|
||||||
|
|
||||||
|
复制并调整了 Gitea 配置:
|
||||||
|
|
||||||
|
- `/etc/gitea/app.ini` → `/root/git-kc/gitea/app.ini`
|
||||||
|
- 将 Gitea 的数据库地址改为:`mysql:3306`
|
||||||
|
- 将 Gitea DB 密码改为 Docker MySQL 内的新密码
|
||||||
|
- 明确关闭了第一阶段的 Git over SSH:
|
||||||
|
- `DISABLE_SSH = true`
|
||||||
|
- `START_SSH_SERVER = false`
|
||||||
|
|
||||||
|
同时对 compose 做了兼容修正,使 Gitea 尽量贴近旧裸机布局:
|
||||||
|
|
||||||
|
- `HOME=/home/git`
|
||||||
|
- `GITEA_WORK_DIR=/var/lib/gitea`
|
||||||
|
- `GITEA_CUSTOM=/var/lib/gitea/custom`
|
||||||
|
- 额外挂载 `/home/git:/home/git`
|
||||||
|
- 显式使用宿主机 `git` 用户 UID/GID 运行容器
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. 迁移前备份
|
||||||
|
|
||||||
|
执行了迁移专用备份:
|
||||||
|
|
||||||
|
- 备份了 Gitea 配置
|
||||||
|
- 备份了 nginx 相关站点配置
|
||||||
|
- 导出了 Gitea MySQL 数据库 `<gitea_db>`
|
||||||
|
- 停止旧 Keycloak 后,导出了 Keycloak realm / users 到目录文件
|
||||||
|
|
||||||
|
Keycloak 导出文件位于:
|
||||||
|
|
||||||
|
- `/root/git-kc/keycloak/import/`
|
||||||
|
|
||||||
|
同时保留了升级前的 SQL dump 与 compose / env / app.ini 备份。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. 启动 Docker MySQL 并迁移 Gitea 数据库
|
||||||
|
|
||||||
|
执行了 MySQL Docker 化:
|
||||||
|
|
||||||
|
- 启动 Docker MySQL 容器
|
||||||
|
- 首次启动时通过 `01-init-databases.sh` 自动创建:
|
||||||
|
- `<gitea_db>`
|
||||||
|
- `<keycloak_db>`
|
||||||
|
- `gitea@'%'`
|
||||||
|
- `keycloak@'%'`
|
||||||
|
- 将原始 Gitea 数据库导入 Docker MySQL
|
||||||
|
|
||||||
|
导入后核对了核心数据:
|
||||||
|
|
||||||
|
- users = 8
|
||||||
|
- repos = 72
|
||||||
|
- - external_login_user = 7
|
||||||
|
|
||||||
|
确认 Gitea 业务主数据迁移成功。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Keycloak H2 → MySQL 迁移与导入问题修复
|
||||||
|
|
||||||
|
### 7.1 初次导入失败原因
|
||||||
|
|
||||||
|
Keycloak 首次导入失败,定位到:
|
||||||
|
|
||||||
|
- `Hangman-Lab` realm 中存在 JS policy
|
||||||
|
- 报错:`Script upload is disabled`
|
||||||
|
|
||||||
|
进一步确认:
|
||||||
|
|
||||||
|
- 不是整个 `authorizationSettings` 无法导入
|
||||||
|
- 而是其中 `type = "js"` 的 policy 被新版本 Keycloak 导入路径拒绝
|
||||||
|
|
||||||
|
具体涉及的 client:
|
||||||
|
|
||||||
|
- `gitea`
|
||||||
|
- `iredmail`
|
||||||
|
- `youtrack-dev`
|
||||||
|
|
||||||
|
脚本内容实际都是同一段默认放行模板:
|
||||||
|
|
||||||
|
```js
|
||||||
|
// by default, grants any permission associated with this policy
|
||||||
|
$evaluation.grant();
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7.2 最小修补
|
||||||
|
|
||||||
|
经确认后,执行了最小修补方案:
|
||||||
|
|
||||||
|
- 移除 `gitea` client 的 `authorizationSettings`
|
||||||
|
- 彻底移除已废弃 client:
|
||||||
|
- `iredmail`
|
||||||
|
- `youtrack-dev`
|
||||||
|
- 同时移除它们的残留引用:
|
||||||
|
- client role definitions
|
||||||
|
- service-account 用户
|
||||||
|
- 相关 client role 映射
|
||||||
|
|
||||||
|
修补仅发生在迁移使用的导出文件中:
|
||||||
|
|
||||||
|
- `/root/git-kc/keycloak/import/Hangman-Lab-realm.json`
|
||||||
|
|
||||||
|
### 7.3 导入成功
|
||||||
|
|
||||||
|
随后:
|
||||||
|
|
||||||
|
- 重建 `<keycloak_db>`
|
||||||
|
- 重新导入 `master` / `Hangman-Lab` / `Dialectic`
|
||||||
|
- 启动 Docker Keycloak 成功
|
||||||
|
- 确认 discovery 文档正常,issuer 正常
|
||||||
|
|
||||||
|
并在导入完成后:
|
||||||
|
|
||||||
|
- 去掉了 compose 中的一次性 `--import-realm`
|
||||||
|
- 去掉了临时加入的 `KC_FEATURES=scripts`
|
||||||
|
|
||||||
|
确保后续 Keycloak 重启不会重复导入。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. Gitea Docker 切换与启动修复
|
||||||
|
|
||||||
|
Gitea 初次容器启动失败,原因是:
|
||||||
|
|
||||||
|
- 容器以 root 身份运行
|
||||||
|
- Gitea 拒绝以 root 启动
|
||||||
|
|
||||||
|
修复措施:
|
||||||
|
|
||||||
|
- 在 compose 中显式设置:
|
||||||
|
- `user: "${GITEA_UID}:${GITEA_GID}"`
|
||||||
|
|
||||||
|
调整后:
|
||||||
|
|
||||||
|
- Gitea 容器成功启动
|
||||||
|
- 健康检查正常
|
||||||
|
- 通过 nginx 暴露的 Gitea 页面可访问
|
||||||
|
- Gitea 的 OIDC 登录入口可正确跳转至 Keycloak
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. nginx 切换
|
||||||
|
|
||||||
|
保留宿主机 nginx 架构不变,仅修改 Keycloak upstream:
|
||||||
|
|
||||||
|
- 从:`https://localhost:8443`
|
||||||
|
- 改为:`http://localhost:8080`
|
||||||
|
|
||||||
|
操作后:
|
||||||
|
|
||||||
|
- 执行 `nginx -t`
|
||||||
|
- reload nginx
|
||||||
|
- 验证 `login.hangman-lab.top` discovery 正常
|
||||||
|
- 验证 `git.hangman-lab.top` 仍正常
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10. 裸机部署清理
|
||||||
|
|
||||||
|
在确认 Docker 版跑通后,删除了旧裸机部署:
|
||||||
|
|
||||||
|
### 已删除
|
||||||
|
|
||||||
|
- Gitea 裸机:
|
||||||
|
- `gitea.service`
|
||||||
|
- `/usr/local/bin/gitea`
|
||||||
|
- `/etc/gitea`
|
||||||
|
- Keycloak 裸机:
|
||||||
|
- `keycloak.service`
|
||||||
|
- `/etc/default/keycloak`
|
||||||
|
- `/opt/keycloak`
|
||||||
|
- MySQL 裸机:
|
||||||
|
- `mysql.service`
|
||||||
|
- 旧 MySQL 包
|
||||||
|
- `/var/lib/mysql`
|
||||||
|
- `/etc/mysql`
|
||||||
|
|
||||||
|
### 保留
|
||||||
|
|
||||||
|
保留了以下正在被 Docker 使用的宿主机路径:
|
||||||
|
|
||||||
|
- `/var/lib/gitea`
|
||||||
|
- `/home/git`
|
||||||
|
|
||||||
|
原因:
|
||||||
|
|
||||||
|
- 这两者属于 Docker Gitea 当前的 live 挂载目录,不是旧垃圾。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 11. 升级到最新版本
|
||||||
|
|
||||||
|
在 Docker 迁移稳定后,继续升级到了当时的最新版本,并保持固定版本写死:
|
||||||
|
|
||||||
|
### Gitea
|
||||||
|
|
||||||
|
- 从:`1.22.4`
|
||||||
|
- 升级到:`1.25.5`
|
||||||
|
|
||||||
|
验证:
|
||||||
|
|
||||||
|
- 容器健康正常
|
||||||
|
- 页面访问正常
|
||||||
|
- OIDC 跳转正常
|
||||||
|
|
||||||
|
### Keycloak
|
||||||
|
|
||||||
|
- 从:`26.0.6`
|
||||||
|
- 升级到:`26.5.6`
|
||||||
|
|
||||||
|
Keycloak 升级期间自动执行了数据库 model migration,日志中可见:
|
||||||
|
|
||||||
|
- `Hangman-Lab` migrated to 26.1.0 / 26.2.0 / 26.3.0 / 26.4.0 / 26.4.3
|
||||||
|
|
||||||
|
升级完成后验证:
|
||||||
|
|
||||||
|
- 容器健康正常
|
||||||
|
- discovery 正常
|
||||||
|
- issuer 正常
|
||||||
|
- Gitea OIDC 跳转正常
|
||||||
|
|
||||||
|
升级前备份保存在:
|
||||||
|
|
||||||
|
- `/root/git-kc/backups/upgrade-2026-03-20-151958/`
|
||||||
|
|
||||||
|
包含:
|
||||||
|
|
||||||
|
- `<gitea_db>.sql`
|
||||||
|
- `<keycloak_db>.sql`
|
||||||
|
- `compose.yaml.bak`
|
||||||
|
- `.env.bak`
|
||||||
|
- `app.ini.bak`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 12. 磁盘清理与空间回收
|
||||||
|
|
||||||
|
后续又做了宿主机空间清理:
|
||||||
|
|
||||||
|
### journald
|
||||||
|
|
||||||
|
- 将 `/var/log/journal` 限制到 `300MB`
|
||||||
|
- 实际回收后 journald 占用约 `252.9MB`
|
||||||
|
|
||||||
|
### Docker 旧镜像
|
||||||
|
|
||||||
|
删除了未使用的旧镜像:
|
||||||
|
|
||||||
|
- `gitea/gitea:1.22.4`
|
||||||
|
- `quay.io/keycloak/keycloak:26.0.6`
|
||||||
|
|
||||||
|
### APT
|
||||||
|
|
||||||
|
- 按要求保留了 apt 元数据和缓存
|
||||||
|
- 同时检查了 `apt-get -s autoremove`
|
||||||
|
- 当前无明显可自动移除的孤儿包
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 13. 当前最终状态(截至日志记录时)
|
||||||
|
|
||||||
|
Docker 正在运行的服务:
|
||||||
|
|
||||||
|
- `mysql:8.0.45`
|
||||||
|
- `gitea/gitea:1.25.5`
|
||||||
|
- `quay.io/keycloak/keycloak:26.5.6`
|
||||||
|
|
||||||
|
验证通过项:
|
||||||
|
|
||||||
|
- `https://git.hangman-lab.top/` 可访问
|
||||||
|
- `https://login.hangman-lab.top/` 可访问
|
||||||
|
- `https://login.hangman-lab.top/realms/Hangman-Lab/.well-known/openid-configuration` 可访问
|
||||||
|
- Gitea 的 OIDC 登录入口会正确跳转至 Keycloak
|
||||||
|
|
||||||
|
当时磁盘空间大致为:
|
||||||
|
|
||||||
|
- 总盘:`23G`
|
||||||
|
- 已用:`12G`
|
||||||
|
- 可用:`11G`
|
||||||
|
- 使用率:约 `53%`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 14. 本次迁移中对业务配置做过的显式变更
|
||||||
|
|
||||||
|
这是后续最需要知道的一部分:
|
||||||
|
|
||||||
|
1. **Gitea 第一阶段明确关闭了 Git over SSH**
|
||||||
|
- `DISABLE_SSH = true`
|
||||||
|
- `START_SSH_SERVER = false`
|
||||||
|
|
||||||
|
2. **Keycloak 导入时对 `Hangman-Lab` realm 做了最小修补**
|
||||||
|
- 移除了 `gitea` 的 `authorizationSettings`
|
||||||
|
- 删除了已废弃 client:
|
||||||
|
- `iredmail`
|
||||||
|
- `youtrack-dev`
|
||||||
|
- 同时删除了它们关联的 service-account / client role 引用
|
||||||
|
|
||||||
|
3. **nginx Keycloak upstream 已改为宿主机本地 HTTP 反代**
|
||||||
|
- `http://localhost:8080`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 15. 后续建议
|
||||||
|
|
||||||
|
- 用浏览器人工完成一次 Gitea → Keycloak SSO 登录验收
|
||||||
|
- 用实际仓库完成一次 HTTPS clone / push 验收
|
||||||
|
- 如未来要恢复 Git over SSH,再单独设计第二阶段方案
|
||||||
|
- 如要继续精简磁盘,可再评估 apt 元数据清理,但本次按要求保留
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 结论
|
||||||
|
|
||||||
|
今天在 `vps.git` 上完成了:
|
||||||
|
|
||||||
|
- 裸机 Gitea / Keycloak / MySQL → Docker 迁移
|
||||||
|
- Keycloak H2 → MySQL 迁移
|
||||||
|
- Gitea / Keycloak 升级到当时最新版本
|
||||||
|
- 旧裸机部署清理
|
||||||
|
- journald 限额与旧镜像清理
|
||||||
|
|
||||||
|
当前服务已切换为 Docker 运行,并完成了基础联通验证。
|
||||||
Reference in New Issue
Block a user