From 5e5e2813eaef3a5abc504abf71d622a14b7a2276 Mon Sep 17 00:00:00 2001 From: WrBug Date: Sun, 7 Dec 2025 17:13:56 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=20Docker=20=E9=95=9C?= =?UTF-8?q?=E5=83=8F=E5=88=A0=E9=99=A4=E6=97=B6=E7=9A=84=20401=20=E8=AE=A4?= =?UTF-8?q?=E8=AF=81=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 改用 JWT Token 认证方式(推荐用于 Access Token) - 添加 Basic Auth 降级方案(适用于密码) - 改进 Token 提取逻辑,支持多种格式 - 添加详细的错误提示(401、403 等) - 更新文档,说明如何配置 Docker Hub Access Token 权限 --- .github/workflows/docker-build.yml | 48 ++++++++++++++++++++++-- docs/VERSION_MANAGEMENT.md | 60 ++++++++++++++++++++++++++---- 2 files changed, 96 insertions(+), 12 deletions(-) diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml index 54ba879..187cc11 100644 --- a/.github/workflows/docker-build.yml +++ b/.github/workflows/docker-build.yml @@ -91,10 +91,36 @@ jobs: echo "正在删除 Docker 镜像: ${IMAGE_NAME}:${TAG_NAME}" - # 使用 Docker Hub API v2 删除镜像标签 - RESPONSE=$(curl -s -w "\n%{http_code}" -X DELETE \ - -u "${DOCKER_USERNAME}:${DOCKER_PASSWORD}" \ - "https://hub.docker.com/v2/repositories/${IMAGE_NAME}/tags/${TAG_NAME}/") + # 方法 1: 尝试使用 JWT Token 认证(推荐,适用于 Access Token) + # 获取 JWT Token + echo "正在获取 Docker Hub JWT Token..." + TOKEN_RESPONSE=$(curl -s -X POST \ + -H "Content-Type: application/json" \ + -d "{\"username\": \"${DOCKER_USERNAME}\", \"password\": \"${DOCKER_PASSWORD}\"}" \ + "https://hub.docker.com/v2/users/login/") + + # 提取 Token(支持多种格式) + TOKEN=$(echo "$TOKEN_RESPONSE" | grep -oE '"token":"[^"]*"' | head -1 | cut -d'"' -f4) + + if [ -z "$TOKEN" ]; then + # 尝试另一种提取方式 + TOKEN=$(echo "$TOKEN_RESPONSE" | python3 -c "import sys, json; print(json.load(sys.stdin).get('token', ''))" 2>/dev/null || echo "") + fi + + if [ -n "$TOKEN" ] && [ "$TOKEN" != "null" ]; then + echo "✅ 成功获取 JWT Token,使用 JWT Token 认证" + # 使用 JWT Token 删除镜像标签 + RESPONSE=$(curl -s -w "\n%{http_code}" -X DELETE \ + -H "Authorization: JWT ${TOKEN}" \ + "https://hub.docker.com/v2/repositories/${IMAGE_NAME}/tags/${TAG_NAME}/") + else + echo "⚠️ JWT Token 获取失败,尝试使用 Basic Auth" + echo " 如果继续失败,请检查 DOCKER_USERNAME 和 DOCKER_PASSWORD 是否正确" + # 方法 2: 使用 Basic Auth(适用于密码) + RESPONSE=$(curl -s -w "\n%{http_code}" -X DELETE \ + -u "${DOCKER_USERNAME}:${DOCKER_PASSWORD}" \ + "https://hub.docker.com/v2/repositories/${IMAGE_NAME}/tags/${TAG_NAME}/") + fi HTTP_CODE=$(echo "$RESPONSE" | tail -n1) BODY=$(echo "$RESPONSE" | head -n-1) @@ -103,6 +129,20 @@ jobs: echo "✅ 成功删除 Docker 镜像标签: ${IMAGE_NAME}:${TAG_NAME}" elif [ "$HTTP_CODE" = "404" ]; then echo "⚠️ 镜像标签不存在: ${IMAGE_NAME}:${TAG_NAME},可能已被删除或不存在" + elif [ "$HTTP_CODE" = "401" ]; then + echo "❌ 认证失败 (HTTP 401): 未授权" + echo " 请检查以下内容:" + echo " 1. DOCKER_USERNAME 和 DOCKER_PASSWORD 是否正确" + echo " 2. 如果使用 Access Token,确保有删除镜像的权限" + echo " 3. 访问令牌是否过期" + echo " 响应详情: $BODY" + exit 1 + elif [ "$HTTP_CODE" = "403" ]; then + echo "❌ 权限不足 (HTTP 403): 没有删除镜像的权限" + echo " 请确保 Docker Hub 访问令牌具有以下权限:" + echo " - Delete repository tags" + echo " 响应详情: $BODY" + exit 1 else echo "❌ 删除失败 (HTTP $HTTP_CODE): $BODY" exit 1 diff --git a/docs/VERSION_MANAGEMENT.md b/docs/VERSION_MANAGEMENT.md index 97c62f5..976a1b4 100644 --- a/docs/VERSION_MANAGEMENT.md +++ b/docs/VERSION_MANAGEMENT.md @@ -20,12 +20,29 @@ 在 GitHub 仓库设置中添加以下 Secrets: - `DOCKER_USERNAME`: Docker Hub 用户名(例如:`wrbug`) -- `DOCKER_PASSWORD`: Docker Hub 密码或访问令牌 +- `DOCKER_PASSWORD`: Docker Hub 访问令牌(推荐)或密码 **设置步骤**: -1. 访问 GitHub 仓库 → Settings → Secrets and variables → Actions -2. 点击 "New repository secret" -3. 添加 `DOCKER_USERNAME` 和 `DOCKER_PASSWORD` + +1. **创建 Docker Hub Access Token**(推荐): + - 访问:https://hub.docker.com/settings/security + - 点击 "New Access Token" + - 填写描述(如:`GitHub Actions PolyHermes`) + - **重要**:勾选以下权限: + - ✅ `Read & Write`(用于推送镜像) + - ✅ `Delete repository tags`(用于删除镜像) + - 点击 "Generate" + - **立即复制令牌**(只显示一次) + +2. **在 GitHub 中添加 Secrets**: + - 访问 GitHub 仓库 → Settings → Secrets and variables → Actions + - 点击 "New repository secret" + - 添加 `DOCKER_USERNAME`:你的 Docker Hub 用户名 + - 添加 `DOCKER_PASSWORD`:刚才创建的 Access Token(不是密码) + +**注意**: +- ⚠️ 如果使用密码而不是 Access Token,删除镜像功能可能无法正常工作 +- ✅ 推荐使用 Access Token,并确保有 `Delete repository tags` 权限 ### 2. 创建 Release(必须通过 GitHub Releases 页面) @@ -151,11 +168,38 @@ VITE_APP_GITHUB_REPO_URL=https://github.com/WrBug/PolyHermes ### Q5: 删除 release 后 Docker 镜像没有被删除? **A:** 检查以下几点: -1. 确认版本号格式为 `v数字.数字.数字`(例如:`v1.0.0`) +1. 确认版本号格式为 `v数字.数字.数字` 或 `v数字.数字.数字-后缀`(例如:`v1.0.0`, `v1.0.0-beta`) 2. 确认 Docker Hub 凭证(`DOCKER_USERNAME` 和 `DOCKER_PASSWORD`)正确配置 -3. 确认 Docker Hub 访问令牌有删除镜像的权限 -4. 查看 GitHub Actions 日志,确认删除操作是否执行 -5. 如果镜像标签不存在,会显示警告但不会失败(这是正常的) +3. **确认 Docker Hub 访问令牌有删除镜像的权限**: + - 如果使用 Access Token,需要确保有 `Delete repository tags` 权限 + - 访问 Docker Hub → Account Settings → Security → Access Tokens + - 创建或编辑访问令牌,确保勾选 `Delete repository tags` 权限 +4. 如果遇到 401 错误,可能是: + - 访问令牌过期,需要重新生成 + - 访问令牌权限不足,需要添加删除权限 + - 用户名或密码/令牌错误 +5. 查看 GitHub Actions 日志,确认删除操作是否执行 +6. 如果镜像标签不存在,会显示警告但不会失败(这是正常的) + +### Q7: 删除镜像时遇到 401 未授权错误? + +**A:** 这通常是因为认证失败,请检查: + +1. **如果使用 Access Token**: + - 确保访问令牌未过期 + - 确保访问令牌有 `Delete repository tags` 权限 + - 在 Docker Hub → Account Settings → Security → Access Tokens 中检查权限 + +2. **如果使用密码**: + - 确保用户名和密码正确 + - 如果启用了 2FA,需要使用 Access Token 而不是密码 + +3. **创建新的 Access Token**: + - 访问:https://hub.docker.com/settings/security + - 点击 "New Access Token" + - 填写描述(如:`GitHub Actions Delete Images`) + - **重要**:勾选 `Delete repository tags` 权限 + - 复制生成的令牌,更新 GitHub Secrets 中的 `DOCKER_PASSWORD` ### Q6: 版本号格式要求是什么?