chore: 砍COS改造(deploy.yml改artifact传递+gitea-backup可移植部署包+改造步骤文档)
This commit is contained in:
1 parent
a74b3c7127
commit
2388694e8a
8 files changed
+729
-147
No files matched your search
@@ -0,0 +1,10 @@
|
||||
# Gitea 部署包 —— 忽略规则
|
||||
|
||||
# 环境变量(含密钥)
|
||||
.env
|
||||
|
||||
# 数据卷(迁移时单独打包,不进 git)
|
||||
data/
|
||||
|
||||
# write-server 运行时产物(若纳入)
|
||||
*.log
|
||||
@@ -0,0 +1,130 @@
|
||||
# Gitea 可移植部署包
|
||||
|
||||
把博客相关的**代码托管(Gitea)+ CI 执行器(act_runner)+ 又拍云同步**打包成一套 docker-compose,
|
||||
目标:**任何一台机器上,复制文件 + 一条命令就能拉起整套环境**,彻底告别「迁移要半天手工操作」。
|
||||
|
||||
> 背景:境外那台 2C2G 服务器(23.254.236.47)十一月到期,且后续可能没时间慢慢迁移。
|
||||
> 这个部署包就是把「迁移成本」从「半天手工」压到「copy + up」。
|
||||
|
||||
---
|
||||
|
||||
## 包含哪些服务
|
||||
|
||||
| 服务 | 镜像 | 说明 |
|
||||
|---|---|---|
|
||||
| **gitea** | `gitea/gitea:1.28.0-rootless` | 代码托管 + CI 调度。SQLite 单文件,数据全在 `data/gitea/` |
|
||||
| **runner** | `gitea/act_runner:0.2.11` | Gitea Actions 执行器,跑博客构建/部署 |
|
||||
| **upyun-sync** | `alpine:3.20` | 又拍云同步(原 1Panel 计划任务「又拍云同步(国内中转)」,容器化后不再依赖面板) |
|
||||
| write-server | (可选,默认注释) | 写作后台,源码在仓库根 `write-server/` |
|
||||
|
||||
**不在本部署包里的**(它们有自己的形态,不适合塞进 compose):
|
||||
|
||||
| 服务 | 形态 | 为什么不在 |
|
||||
|---|---|---|
|
||||
| 博客站点 | 静态文件 + CDN | 构建产物由 runner 推给 EdgeOne / 又拍云,不是常驻服务 |
|
||||
| 评论后端 artalk-cf | Cloudflare Workers | 无服务器,`wrangler deploy` 部署,见 `blog-admin/` |
|
||||
| write-server | 独立 Docker | 可选纳入,见 compose 注释 |
|
||||
|
||||
---
|
||||
|
||||
## 目录结构
|
||||
|
||||
```
|
||||
gitea-backup/
|
||||
├── docker-compose.yml # 核心:三个服务 + 网络
|
||||
├── .env.example # 变量模板(复制成 .env)
|
||||
├── .gitignore # 忽略 .env 和 data/
|
||||
├── README.md # 本文档
|
||||
├── scripts/
|
||||
│ ├── backup.sh # 一键备份:gitea dump + 打包 data 卷
|
||||
│ └── restore.sh # 一键恢复
|
||||
└── data/ # 数据卷(git 忽略,迁移时打包)
|
||||
├── gitea/ # Gitea 数据(gitea.db + app.ini + 仓库)
|
||||
├── runner/ # act_runner 配置
|
||||
└── upyun-sync/ # 同步脚本 + upx + cos_sign.py
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 首次部署(新机器)
|
||||
|
||||
### 1. 准备代码和数据
|
||||
|
||||
```bash
|
||||
# 克隆仓库(含 gitea-backup)
|
||||
git clone <你的仓库> && cd <仓库>/gitea-backup
|
||||
|
||||
# 迁移数据:从旧机器把数据卷 rsync 过来
|
||||
# (旧机器 23.254.236.47 上)
|
||||
rsync -av --progress /opt/gitea/data/ 新机器:/path/to/gitea-backup/data/gitea/
|
||||
# 又拍云同步目录同理:
|
||||
rsync -av --progress /opt/upyun-sync/ 新机器:/path/to/gitea-backup/data/upyun-sync/
|
||||
```
|
||||
|
||||
### 2. 配置
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
# 编辑 .env:填域名、端口、又拍云密码
|
||||
```
|
||||
|
||||
### 3. 启动
|
||||
|
||||
```bash
|
||||
docker compose up -d
|
||||
docker compose ps # 确认三个服务都 healthy/running
|
||||
```
|
||||
|
||||
### 4. 注册 runner(首次必做)
|
||||
|
||||
```bash
|
||||
# 到 Gitea 后台:站点管理 → Actions → Runners → 创建 runner → 复制注册 token
|
||||
# 把 token 填进 .env 的 RUNNER_REGISTRATION_TOKEN,然后:
|
||||
docker compose up -d --force-recreate runner
|
||||
# 回到后台确认 runner 已在线(绿色)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 备份
|
||||
|
||||
```bash
|
||||
bash scripts/backup.sh
|
||||
# 产物:backups/gitea-dump-<时间戳>.zip(含 gitea dump + app.ini)
|
||||
# backups/data-<时间戳>.tar.gz(含完整 data 卷)
|
||||
```
|
||||
|
||||
`gitea dump` 会导出仓库 + 用户 + 配置 + secrets(加密),是最完整的一站式备份。
|
||||
|
||||
## 恢复(灾难场景)
|
||||
|
||||
```bash
|
||||
bash scripts/restore.sh backups/gitea-dump-<时间戳>.zip
|
||||
# 或手动:把 data 卷解回 data/,然后 docker compose up -d
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 从旧机器迁移的完整清单(十一月到期前照着做)
|
||||
|
||||
1. 新机器装 docker + docker compose
|
||||
2. `rsync` 旧机器 `/opt/gitea/data` → 新机器 `data/gitea/`
|
||||
3. `rsync` 旧机器 `/opt/upyun-sync` → 新机器 `data/upyun-sync/`
|
||||
4. `cp .env.example .env` 并填好
|
||||
5. `docker compose up -d`
|
||||
6. 后台重新注册 runner(token 会变)
|
||||
7. DNS 把 `gitea.usj.cc` 指向新机器 IP
|
||||
8. 验证:`git push` 一次,看 Actions 是否正常构建部署
|
||||
|
||||
> ⚠️ 第 6 步 runner token 每次重新注册都会变,旧 token 作废,必须在后台重新拿。
|
||||
|
||||
---
|
||||
|
||||
## 关于「又拍云同步」的容器化说明
|
||||
|
||||
原 1Panel 计划任务是 `bash /opt/upyun-sync/sync.sh`,每分钟跑一次,负责:
|
||||
从 COS 拉构建产物 → 解压 → `upx sync` 到又拍云 → purge → 刷多吉云。
|
||||
|
||||
容器化后逻辑不变,只是**用 `while sleep 60` 循环替代了 cron**(不再依赖 1Panel)。
|
||||
注意:`sync.sh` 里如果还引用 COS(`cos_sign.py` 签 COS 地址),说明 COS 还没砍;
|
||||
如果已改为「拉 Gitea artifact」,则 `cos_sign.py` 可以删掉。
|
||||
@@ -0,0 +1,157 @@
|
||||
# =============================================================================
|
||||
# Gitea 可移植部署包 —— 把所有「博客相关服务」打包成 docker-compose
|
||||
#
|
||||
# 目标:任何一台机器上,只要:
|
||||
# 1. git clone 本仓库(含 gitea-backup/ 目录)
|
||||
# 2. 准备 data/ 数据卷(迁移时从旧机器打包过来)
|
||||
# 3. 复制 .env.example 为 .env 并填好
|
||||
# 4. docker compose up -d
|
||||
# 就能拉起整套环境。
|
||||
#
|
||||
# 包含的服务:
|
||||
# - gitea 代码托管(境外已停用 GitHub Actions,构建全走这里)
|
||||
# - runner Gitea Actions 的执行器(act_runner,跑博客构建/部署)
|
||||
# - upyun-sync 又拍云同步(原 1Panel 计划任务,容器化后不再依赖面板)
|
||||
#
|
||||
# write-server(写作后台)源码仍在仓库根 write-server/,这里用相对路径引用,
|
||||
# 不搬源码。如需一起管理,取消下面 write-server 段的注释。
|
||||
# =============================================================================
|
||||
|
||||
name: gitea-backup
|
||||
|
||||
services:
|
||||
# ---------------------------------------------------------------------------
|
||||
# Gitea —— 代码托管 + CI 调度中心
|
||||
# 数据:SQLite 单文件(/data/gitea/gitea.db)+ app.ini,全部在挂载卷里
|
||||
# 迁移:把旧机器 /opt/gitea/data 整个 rsync 到本机 ./data/gitea 即可
|
||||
# ---------------------------------------------------------------------------
|
||||
gitea:
|
||||
image: gitea/gitea:1.28.0-rootless
|
||||
container_name: gitea
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- USER_UID=1000
|
||||
- USER_GID=1000
|
||||
- TZ=Asia/Shanghai
|
||||
# 数据库用内置 SQLite,无需额外容器
|
||||
- GITEA__database__DB_TYPE=sqlite3
|
||||
# 域名与基础 URL(必须与你备案域名一致)
|
||||
- GITEA__server__DOMAIN=${GITEA_DOMAIN}
|
||||
- GITEA__server__ROOT_URL=${GITEA_ROOT_URL}
|
||||
- GITEA__server__SSH_DOMAIN=${GITEA_SSH_DOMAIN}
|
||||
- GITEA__server__SSH_PORT=${GITEA_SSH_PORT}
|
||||
# 关闭注册,只有你一个人用
|
||||
- GITEA__service__DISABLE_REGISTRATION=true
|
||||
ports:
|
||||
- "${GITEA_HTTP_PORT}:3000"
|
||||
- "${GITEA_SSH_PORT}:2222"
|
||||
volumes:
|
||||
- ./data/gitea:/data
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:3000/api/v1/version"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 30s
|
||||
networks:
|
||||
- gitea-net
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# act_runner —— Gitea Actions 执行器(跑博客的构建 + 部署流水线)
|
||||
# 首次启动后需到 Gitea 后台「站点管理 → Actions → Runners」拿注册 token,
|
||||
# 然后 exec 进容器执行一次注册(详见 README「首次初始化」)
|
||||
# ---------------------------------------------------------------------------
|
||||
runner:
|
||||
image: gitea/act_runner:0.2.11
|
||||
container_name: gitea-runner
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- TZ=Asia/Shanghai
|
||||
- GITEA_INSTANCE_URL=${GITEA_ROOT_URL}
|
||||
# 注册 token:首次跑前手动填进 .env(见 README)
|
||||
- GITEA_RUNNER_REGISTRATION_TOKEN=${RUNNER_REGISTRATION_TOKEN}
|
||||
volumes:
|
||||
- ./data/runner:/data
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
depends_on:
|
||||
gitea:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- gitea-net
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# upyun-sync —— 又拍云同步(原 1Panel 计划任务「又拍云同步(国内中转)」)
|
||||
# 容器化后:不再依赖 1Panel,随 compose 一起迁移。
|
||||
# 工作目录 ./data/upyun-sync 里放 sync.sh / upx / cos_sign.py 等。
|
||||
# 注意:此服务用 host 网络(要访问宿主机已配好的证书/代理时更省事)。
|
||||
# ---------------------------------------------------------------------------
|
||||
upyun-sync:
|
||||
image: alpine:3.20
|
||||
container_name: upyun-sync
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- TZ=Asia/Shanghai
|
||||
# 又拍云凭据(从 .env 注入,容器内脚本读取)
|
||||
- UPYUN_SERVICE=${UPYUN_BUCKET}
|
||||
- UPYUN_OPERATOR=${UPYUN_OPERATOR}
|
||||
- UPYUN_PASSWORD=${UPYUN_PASSWORD}
|
||||
volumes:
|
||||
- ./data/upyun-sync:/opt/upyun-sync
|
||||
entrypoint: ["/bin/sh", "-c"]
|
||||
command:
|
||||
- |
|
||||
apk add --no-cache curl bash python3 py3-pip tar zstd openssl >/dev/null 2>&1 || true
|
||||
# 引导 upx(若 data 里没有)
|
||||
if [ ! -x /opt/upyun-sync/upx ]; then
|
||||
echo "引导 upx..."
|
||||
cd /tmp && curl -fsSL -o upx.tgz \
|
||||
"https://collection.b0.upaiyun.com/softwares/upx/upx_0.4.9_linux_amd64.tar.gz" \
|
||||
&& tar -xzf upx.tgz upx && mv upx /opt/upyun-sync/upx && chmod 755 /opt/upyun-sync/upx || \
|
||||
curl -fsSL -o upx.tgz \
|
||||
"https://github.com/upyun/upx/releases/download/v0.4.9/upx_0.4.9_linux_amd64.tar.gz" \
|
||||
&& tar -xzf upx.tgz upx && mv upx /opt/upyun-sync/upx && chmod 755 /opt/upyun-sync/upx
|
||||
fi
|
||||
# 每分钟跑一次 sync.sh(等价原 1Panel 的 * * * * * 计划任务)
|
||||
while true; do
|
||||
if [ -x /opt/upyun-sync/sync.sh ]; then
|
||||
bash /opt/upyun-sync/sync.sh || echo "[$(date -Is)] sync.sh 退出码 $?"
|
||||
else
|
||||
echo "[$(date -Is)] 缺少 sync.sh,跳过"
|
||||
fi
|
||||
sleep 60
|
||||
done
|
||||
networks:
|
||||
- gitea-net
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# write-server(可选,默认注释)—— 写作后台
|
||||
# 源码在仓库根 write-server/,这里用相对路径引用。
|
||||
# 若要把写作后台也纳入本部署包,取消下面整段注释,
|
||||
# 并确保 write-server/ 目录与 gitea-backup/ 同级。
|
||||
# ---------------------------------------------------------------------------
|
||||
# write-server:
|
||||
# build:
|
||||
# context: ../write-server
|
||||
# dockerfile: Dockerfile
|
||||
# container_name: write-server
|
||||
# restart: unless-stopped
|
||||
# ports:
|
||||
# - "8016:8016"
|
||||
# volumes:
|
||||
# - ../..:/blog # 博客根目录(与 write-server 原 compose 一致)
|
||||
# - ./data/write-server/recycle:/app/recycle
|
||||
# - ./data/write-server/logs:/app/logs
|
||||
# - ./data/write-server/backups:/app/backups
|
||||
# environment:
|
||||
# - NODE_ENV=production
|
||||
# - PORT=8016
|
||||
# - BLOG_ROOT=/blog
|
||||
# - TZ=Asia/Shanghai
|
||||
# networks:
|
||||
# - gitea-net
|
||||
|
||||
networks:
|
||||
gitea-net:
|
||||
driver: bridge
|
||||
@@ -0,0 +1,36 @@
|
||||
#!/bin/bash
|
||||
# =============================================================================
|
||||
# Gitea 部署包 —— 一键备份
|
||||
# 备份内容:
|
||||
# 1. gitea dump(仓库 + 用户 + 配置 + secrets 加密导出)
|
||||
# 2. 完整 data 卷(gitea.db / app.ini / runner 配置 / upyun-sync 目录)
|
||||
# 产物输出到 backups/ 目录
|
||||
# =============================================================================
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
ROOT_DIR="$(dirname "$SCRIPT_DIR")"
|
||||
BACKUP_DIR="$ROOT_DIR/backups"
|
||||
STAMP="$(date +%Y%m%d-%H%M%S)"
|
||||
|
||||
mkdir -p "$BACKUP_DIR"
|
||||
|
||||
echo "==> 1/2 导出 Gitea dump(含 secrets)..."
|
||||
docker compose -f "$ROOT_DIR/docker-compose.yml" exec -T gitea \
|
||||
gitea dump --config /data/gitea/conf/app.ini \
|
||||
--file /data/gitea-dump.zip \
|
||||
-R -S 2>/dev/null || {
|
||||
echo "⚠️ gitea dump 失败(容器可能未运行),跳过,仅备份 data 卷"
|
||||
}
|
||||
# 把 dump 产物从容器拷出来
|
||||
docker compose -f "$ROOT_DIR/docker-compose.yml" cp \
|
||||
gitea:/data/gitea-dump.zip "$BACKUP_DIR/gitea-dump-$STAMP.zip" 2>/dev/null || true
|
||||
|
||||
echo "==> 2/2 打包 data 卷..."
|
||||
tar -czf "$BACKUP_DIR/data-$STAMP.tar.gz" -C "$ROOT_DIR" data/
|
||||
|
||||
echo ""
|
||||
echo "✅ 备份完成:"
|
||||
ls -lh "$BACKUP_DIR" | tail -5
|
||||
echo ""
|
||||
echo "⚠️ 产物含密钥,请勿上传网盘/公开仓库。"
|
||||
@@ -0,0 +1,55 @@
|
||||
#!/bin/bash
|
||||
# =============================================================================
|
||||
# Gitea 部署包 —— 一键恢复
|
||||
# 用法:bash restore.sh <backups/data-<时间戳>.tar.gz>
|
||||
# 或 bash restore.sh <backups/gitea-dump-<时间戳>.zip>(仅恢复 dump)
|
||||
# =============================================================================
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
ROOT_DIR="$(dirname "$SCRIPT_DIR")"
|
||||
|
||||
if [ $# -lt 1 ]; then
|
||||
echo "用法:bash restore.sh <备份文件>"
|
||||
echo " - data-*.tar.gz 恢复完整 data 卷"
|
||||
echo " - gitea-dump-*.zip 仅恢复 gitea dump"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SRC="$1"
|
||||
|
||||
if [ ! -f "$SRC" ]; then
|
||||
echo "❌ 找不到备份文件:$SRC"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "==> 停止服务..."
|
||||
docker compose -f "$ROOT_DIR/docker-compose.yml" down 2>/dev/null || true
|
||||
|
||||
case "$SRC" in
|
||||
*data-*.tar.gz)
|
||||
echo "==> 恢复 data 卷..."
|
||||
tar -xzf "$SRC" -C "$ROOT_DIR"
|
||||
echo "✅ data 卷已恢复到 $ROOT_DIR/data/"
|
||||
;;
|
||||
*gitea-dump-*.zip)
|
||||
echo "==> 恢复 gitea dump..."
|
||||
docker compose -f "$ROOT_DIR/docker-compose.yml" up -d gitea
|
||||
sleep 5
|
||||
docker compose -f "$ROOT_DIR/docker-compose.yml" cp \
|
||||
"$SRC" gitea:/data/restore.zip
|
||||
docker compose -f "$ROOT_DIR/docker-compose.yml" exec -T gitea \
|
||||
gitea restore --config /data/gitea/conf/app.ini --file /data/restore.zip
|
||||
echo "✅ gitea dump 已恢复"
|
||||
;;
|
||||
*)
|
||||
echo "❌ 无法识别的备份文件类型:$SRC"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "==> 启动服务..."
|
||||
docker compose -f "$ROOT_DIR/docker-compose.yml" up -d
|
||||
|
||||
echo "✅ 恢复完成,检查状态:"
|
||||
docker compose -f "$ROOT_DIR/docker-compose.yml" ps
|
||||
Reference in new issue
Block a user