Gradle Jib在GitHub Workflow中无法认证GHCR,本地为何也随即失败?
问题分析与解决
现象描述
本地可通过Gradle Jib构建并推送容器镜像至GitHub容器注册表(GHCR),但GitHub Workflow执行相同操作时失败;更特殊的是,Workflow失败后,本地再用同一个令牌执行构建也会报相同错误,必须重新生成GitHub个人访问令牌才能恢复正常。
复现步骤
build.gradle配置如下:
plugins { id 'java' id 'idea' id 'org.springframework.boot' version '3.0.1' id 'com.google.cloud.tools.jib' version '3.3.1' id 'io.spring.dependency-management' version '1.1.0' } java { sourceCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17 } compileJava.options.encoding = "UTF-8" compileTestJava.options.encoding = "UTF-8" configurations { published compileOnly { extendsFrom annotationProcessor } } dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor' testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation('org.assertj:assertj-core') testImplementation('org.junit.jupiter:junit-jupiter-api') testRuntimeOnly('org.junit.jupiter:junit-jupiter-engine') } tasks.withType(Test) { useJUnitPlatform() } task prepareKotlinBuildScriptModel { } springBoot { buildInfo() } bootJar { enabled = false } jar { enabled = true } def baseImage = 'ghcr.io/tobias-neubert/eclipse-temurin:17.0.2_8-jre' jib { from { image = baseImage auth { username = "tobias-neubert" password = "${System.getenv("GITHUB_PASSWORD")}" } } to { image = 'ghcr.io/tobias-neubert/motd-service' auth { username = "tobias-neubert" password = "${System.getenv("GITHUB_PASSWORD")}" } } container { mainClass = 'com.neubert.scaffold.motdservice.MotdServiceApplication' ports = ['8080'] } }
- 在GitHub创建新的个人访问令牌(PAT)。
- 本地执行命令:
GITHUB_PASSWORD=<personal-access-token> ./gradlew :motd-service:jib
- 本地执行命令:
- 镜像成功推送至GHCR,重复本地构建也能成功。
- GitHub Workflow配置如下:
name: Build and push motd-service on: push: branches: - actions jobs: build: runs-on: ubuntu-latest steps: - name: Checkout Code uses: actions/checkout@v3 - name: Set up Java uses: actions/setup-java@v2 with: java-version: 17 distribution: temurin - name: Setup Gradle uses: gradle/gradle-build-action@v2 - name: Make gradlew executable run: chmod +x ./gradlew - name: Build the motd image run: | GITHUB_PASSWORD=<personal-access-token> ./gradlew :motd-service:jib
- Workflow执行失败,报错:
Execution failed for task ':motd-service:jib'. > com.google.cloud.tools.jib.plugins.common.BuildStepsExecutionException: Build image failed, perhaps you should make sure you have permissions for ghcr.io/tobias-neubert/eclipse-temurin and set correct credentials.
- 再次本地执行相同构建命令,也出现上述错误。
问题根源
- 令牌泄露被自动吊销:Workflow中直接硬编码个人访问令牌,提交到仓库后,GitHub会检测到日志或代码中的令牌并自动吊销——这就是Workflow失败后本地也无法使用同一令牌的核心原因。
- 不必要的基础镜像认证:如果
ghcr.io/tobias-neubert/eclipse-temurin是公共镜像,拉取时无需认证,硬加认证反而可能触发权限校验错误。 - 令牌权限不足:创建个人访问令牌时,未授予足够的权限(如
write:packages、read:packages),导致推送/拉取镜像操作失败。
解决方案
1. 修复Workflow的令牌使用方式
绝对禁止在Workflow中硬编码令牌,改用GitHub Secrets存储:
- 进入仓库的
Settings→Secrets and variables→Actions,点击New repository secret,创建名为GITHUB_PASSWORD的Secret,值为你的个人访问令牌。 - 修改Workflow的构建步骤:
- name: Build the motd image run: | GITHUB_PASSWORD=${{ secrets.GITHUB_PASSWORD }} ./gradlew :motd-service:jib
2. 移除基础镜像的不必要认证
如果基础镜像ghcr.io/tobias-neubert/eclipse-temurin是公开的,删除jib.from.auth配置:
jib { from { image = baseImage // 删除auth块 } // to部分的auth保留 }
3. 确保令牌权限足够
创建个人访问令牌时,勾选以下权限:
write:packages(推送镜像)read:packages(拉取镜像)repo(若为私有仓库)
4. 推荐使用GitHub Actions内置的GITHUB_TOKEN
无需手动创建个人令牌,GitHub Actions提供临时的GITHUB_TOKEN,默认拥有当前仓库的packages操作权限:
- 修改Workflow的构建步骤:
- name: Build the motd image env: GITHUB_PASSWORD: ${{ secrets.GITHUB_TOKEN }} GITHUB_USERNAME: github-actions[bot] run: ./gradlew :motd-service:jib
- 同步修改
build.gradle的auth配置,兼容两种令牌场景:
jib { from { image = baseImage } to { image = 'ghcr.io/tobias-neubert/motd-service' auth { username = System.getenv("GITHUB_USERNAME") ?: "tobias-neubert" password = System.getenv("GITHUB_PASSWORD") } } // container部分不变 }
内容的提问来源于stack exchange,提问作者Tobias Neubert
相关产品推荐
相关产品推荐

