Github Actions中Docker GHA缓存失效问题排查求助
这种情况确实挺让人挠头的——明明COPY go.sum都命中缓存了,紧随其后的RUN go mod download却没跟上,下面给你几个实用的调试思路,一步步排查问题:
先确认缓存键的生成逻辑
Docker BuildKit的缓存是基于前序步骤的哈希值来匹配的,虽然COPY步骤显示CACHED,但得先排查几个关键点:- 在构建步骤前加个echo命令,输出
${{ matrix.ecr_repo }}的值,确认每次构建的缓存scope是不是完全一致——如果matrix参数有变化,缓存scope变了,自然读不到之前的缓存。 - 检查
go.mod和go.sum的隐性差异:比如换行符(Windows vs Linux)、末尾空格、注释变化这些肉眼难察觉的改动,都会导致文件哈希变化。可以在Dockerfile里临时加一行RUN cat go.mod go.sum | sha256sum,然后对比两次构建的哈希值,看是不是文件真的没变化。
- 在构建步骤前加个echo命令,输出
开启BuildKit的详细日志
默认的构建日志不会显示缓存决策的细节,你可以在docker/build-push-action步骤里加两个环境变量,让BuildKit输出更详细的调试信息:- name: Build & Push uses: docker/build-push-action@v2 env: BUILDKIT_DEBUG: 1 BUILDKIT_PROGRESS: plain with: cache-from: type=gha,scope=${{ matrix.ecr_repo }} cache-to: type=gha,mode=max,scope=${{ matrix.ecr_repo }} push: true tags: "${{ env.tags }}"这样日志里会明确显示每个步骤的缓存键计算过程,以及为什么没命中缓存——比如是前序步骤的哈希不匹配,还是对应的缓存条目根本不存在。
验证GHA缓存的读写状态
去GitHub Actions的构建任务页面,看看有没有"Cache"标签(部分仓库会显示),或者直接看docker/setup-buildx-action和docker/build-push-action的日志,找类似Loaded cache from gha scope: xxx或者Pushed cache to gha scope: xxx的信息,确认缓存确实被正确读取和写入了。如果怀疑是旧缓存干扰,可以去仓库的Settings -> Actions -> Cache里手动清理对应scope的缓存,然后重新构建试试。排查Dockerfile上下文和构建参数
- 检查构建时有没有传入不同的build-arg:比如如果有
GO_VERSION这类参数,哪怕COPY步骤命中了,RUN go mod download也可能因为build-arg变化而重新执行。 - 确认
.dockerignore配置是否正确:如果构建上下文里包含了一些无关文件(比如本地的临时文件、日志),会导致整个上下文的哈希变化,进而影响后续步骤的缓存。可以用docker build --no-cache --print-context命令在本地查看构建上下文的内容,对比两次构建的差异。
- 检查构建时有没有传入不同的build-arg:比如如果有
本地复现测试
把代码拉到本地,开启Docker BuildKit(设置环境变量DOCKER_BUILDKIT=1),执行几次构建,看本地会不会出现同样的问题:- 如果本地构建时
RUN go mod download能正常命中缓存,那问题大概率出在GitHub Actions的GHA缓存配置或者CI环境上; - 如果本地也出现同样的问题,那就是Dockerfile或者代码本身的问题,比如
go.mod/go.sum有隐性变化,或者Dockerfile的写法有问题。
- 如果本地构建时
检查依赖的隐性变化
虽然go.mod和go.sum看起来没变化,但可以试试在RUN go mod download后面加一行RUN go mod verify,检查依赖包的完整性;或者用go list -m all输出所有依赖的版本,对比两次构建的结果,看是不是有间接依赖的版本变化(不过这种情况概率很低,因为go mod download是严格按照go.sum来的)。
内容的提问来源于stack exchange,提问作者maxisme

