Files
WrBug 26dd3bb387 feat: 实现系统动态更新功能和 Release 创建脚本
主要变更:

1. 动态更新功能
   - 新增 Python 更新服务 (docker/update-service.py)
   - 添加系统更新前端页面 (frontend/src/pages/SystemUpdate.tsx)
   - 配置 Nginx 代理更新服务 API
   - 更新 Docker 启动脚本支持多进程管理
   - 修复权限验证接口 (AuthController.verify)

2. Release 创建脚本
   - 新增 create-release.sh 脚本支持快速创建 GitHub Release
   - 支持自动拼接 -beta 后缀(pre-release)
   - 支持无交互模式(--yes 参数)
   - 添加详细的使用文档

3. GitHub Actions 增强
   - 添加更新包构建和上传流程
   - 支持 Pre-release 检测和过滤

4. 文档完善
   - 添加动态更新技术方案文档
   - 添加 Docker 版本号确定流程文档
   - 添加 Release 脚本使用说明
2026-01-21 03:34:16 +08:00

7.8 KiB
Raw Permalink Blame History

Docker 版本号确定流程

概述

Docker 镜像的版本号从 GitHub Release Tag 获取,通过 GitHub Actions 自动传递到 Dockerfile,最终存储在容器内的 /app/version.json 文件中。

完整流程

1. GitHub Release Tag (v1.0.0)
   ↓
2. GitHub Actions 触发
   ↓
3. 从 Tag 提取版本号
   ↓
4. 作为 build-args 传递给 Dockerfile
   ↓
5. Dockerfile 写入 /app/version.json
   ↓
6. 容器运行时读取版本号

详细步骤

步骤 1: 创建 GitHub Release

通过 GitHub Releases 页面或 create-release.sh 脚本创建 Release

# 示例:创建 v1.0.1 版本
./create-release.sh -t v1.0.1 -T "Release v1.0.1" -d "更新内容"

结果:

  • 创建 Git tag: v1.0.1
  • 创建 GitHub Release: v1.0.1
  • 触发 GitHub Actions workflow

步骤 2: GitHub Actions 触发

GitHub Actions 监听 release: published 事件:

# .github/workflows/docker-build.yml
on:
  release:
    types:
      - published  # 当创建 release 时触发

事件数据:

  • github.event.release.tag_name: "v1.0.1"
  • github.event.release.prerelease: falsetrue

步骤 3: 提取版本号

GitHub Actions 从 Tag 中提取版本号:

# .github/workflows/docker-build.yml (步骤: Extract version)
TAG_NAME="${{ github.event.release.tag_name }}"  # "v1.0.1"
VERSION=${TAG_NAME#v}                             # "1.0.1" (移除 v 前缀)

提取结果:

  • VERSION: "1.0.1" (纯版本号,无 v 前缀)
  • TAG: "v1.0.1" (完整 tag,带 v 前缀)
  • IS_PRERELEASE: falsetrue

版本号格式验证:

  • 正确:v1.0.0, v2.10.102, v1.0.0-beta
  • 错误:v1.0, 1.0.0, v1.0.0.1

步骤 4: 传递构建参数

版本号作为 Docker build-args 传递给 Dockerfile

# .github/workflows/docker-build.yml
- name: Build and push Docker image
  uses: docker/build-push-action@v5
  with:
    build-args: |
      BUILD_IN_DOCKER=false
      VERSION=${{ steps.extract_version.outputs.VERSION }}      # "1.0.1"
      GIT_TAG=${{ steps.extract_version.outputs.TAG }}          # "v1.0.1"
      GITHUB_REPO_URL=https://github.com/WrBug/PolyHermes

步骤 5: Dockerfile 接收参数

Dockerfile 使用 ARG 接收构建参数:

# Dockerfile (第 92-94 行)
ARG VERSION=dev        # 默认值: dev
ARG GIT_TAG=dev        # 默认值: dev

# 写入 version.json
RUN echo "{\"version\":\"${VERSION}\",\"tag\":\"${GIT_TAG}\",\"buildTime\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"}" > /app/version.json

生成的文件内容 (/app/version.json):

{
  "version": "1.0.1",
  "tag": "v1.0.1",
  "buildTime": "2026-01-20T15:30:00Z"
}

步骤 6: 容器运行时读取

更新服务通过 /api/update/version 接口读取版本号:

# docker/update-service.py
def get_current_version():
    """获取当前版本"""
    if VERSION_FILE.exists():
        with open(VERSION_FILE) as f:
            data = json.load(f)
            return data.get('version', 'unknown')  # 返回: "1.0.1"

前端通过 API 获取并显示:

// frontend/src/pages/SystemUpdate.tsx
const response = await apiClient.get('/update/version')
const { version } = response.data.data  // "1.0.1"

不同场景下的版本号

场景 1: GitHub Actions 自动构建(正式发布)

输入:

  • Release Tag: v1.0.1
  • Release Type: Published (正式版本)

流程:

  1. GitHub Actions 提取: VERSION="1.0.1", GIT_TAG="v1.0.1"
  2. 传递给 Dockerfile
  3. 生成 /app/version.json: {"version": "1.0.1", "tag": "v1.0.1", ...}

Docker 镜像标签:

  • wrbug/polyhermes:v1.0.1
  • wrbug/polyhermes:latest (因为不是 pre-release)

场景 2: Pre-release(测试版本)

输入:

  • Release Tag: v1.0.1-beta
  • Release Type: Pre-release

流程:

  1. GitHub Actions 提取: VERSION="1.0.1-beta", GIT_TAG="v1.0.1-beta"
  2. 传递给 Dockerfile
  3. 生成 /app/version.json: {"version": "1.0.1-beta", "tag": "v1.0.1-beta", ...}

Docker 镜像标签:

  • wrbug/polyhermes:v1.0.1-beta
  • wrbug/polyhermes:latest (pre-release 不推送到 latest)

场景 3: 本地构建(开发环境)

命令行:

docker build -t polyhermes:local .

流程:

  1. 没有传递 VERSIONGIT_TAG 参数
  2. Dockerfile 使用默认值: VERSION=dev, GIT_TAG=dev
  3. 生成 /app/version.json: {"version": "dev", "tag": "dev", ...}

显式指定版本号:

docker build \
  --build-arg VERSION=1.0.1 \
  --build-arg GIT_TAG=v1.0.1 \
  -t polyhermes:local .

场景 4: 本地 Docker Compose

docker-compose.yml:

services:
  app:
    build:
      context: .
      args:
        VERSION: 1.0.1
        GIT_TAG: v1.0.1

版本号存储位置

容器内路径

/app/version.json

文件格式

{
  "version": "1.0.1",           // 纯版本号(无 v 前缀)
  "tag": "v1.0.1",              // 完整 tag(带 v 前缀)
  "buildTime": "2026-01-20T15:30:00Z"  // 构建时间(UTC
}

访问方式

1. 通过 API:

curl http://localhost/api/update/version

2. 进入容器查看:

docker exec -it <container_id> cat /app/version.json

3. 前端显示:

  • 系统设置 → 系统更新页面
  • 显示当前版本: v1.0.1

版本号的作用

1. 显示当前版本

前端和系统更新页面显示当前运行的版本号。

2. 检查更新

更新服务通过比较当前版本和 GitHub 最新版本判断是否有更新:

# docker/update-service.py
current_version = get_current_version()  # "1.0.1"
latest_version = fetch_latest_release()  # "1.0.2"

if compare_versions(latest_version, current_version) > 0:
    # 有新版本,提示更新

3. 版本追踪

记录 Docker 镜像的构建版本,便于追踪和回滚。

关键文件

文件 作用 版本号来源
.github/workflows/docker-build.yml GitHub Actions 工作流 github.event.release.tag_name
Dockerfile Docker 构建配置 构建参数 VERSION, GIT_TAG
/app/version.json 版本号存储文件 Dockerfile 生成
docker/update-service.py 更新服务 读取 /app/version.json

常见问题

Q1: 为什么版本号是 dev

A: 本地构建时没有传递版本号参数,使用了默认值。

解决:

docker build \
  --build-arg VERSION=1.0.1 \
  --build-arg GIT_TAG=v1.0.1 \
  -t polyhermes:local .

Q2: 如何查看当前容器的版本号?

A:

# 方法1: API 接口
curl http://localhost/api/update/version

# 方法2: 进入容器
docker exec -it <container_id> cat /app/version.json

# 方法3: 前端页面
系统设置 → 系统更新 → 查看"当前版本"

Q3: 版本号格式错误怎么办?

A: GitHub Actions 会验证版本号格式:

  • 正确:v1.0.0, v1.0.0-beta
  • 错误:v1.0, 1.0.0

如果格式错误,构建会失败并提示错误信息。

Q4: Pre-release 和正式版本的版本号有什么区别?

A:

  • 格式: 都可以使用相同的格式(v1.0.1-beta vs v1.0.1
  • 存储: 都存储在 /app/version.json
  • Docker 标签: Pre-release 不会推送到 latest 标签
  • 通知: Pre-release 不会发送 Telegram 通知

总结

Docker 版本号的确定流程:

  1. 来源: GitHub Release Tag
  2. 提取: GitHub Actions 从 tag 中提取版本号
  3. 传递: 通过 Docker build-args 传递
  4. 存储: 写入容器内的 /app/version.json
  5. 使用: 用于显示、检查更新、版本追踪

关键点:

  • 版本号来自 GitHub Release Tag
  • 格式必须符合:v数字.数字.数字[-后缀]
  • 默认值为 dev(本地构建时)
  • 支持 Pre-release 标记