
问题:CI 构建每次从零编译
用 GitHub Actions 跑 Docker 构建,明明什么都没改,却每次都从零开始。缓存命中率 0%,CI 时间从 2 分钟飙升到 12 分钟。
根因有两个,都很隐蔽:GITHUB_TOKEN 24h 过期导致 cache-from 认证静默失败,.dockerignore 漏写导致 BuildKit 上下文哈希每次变化。两个同时存在时,缓存完全失效。
坑1:GITHUB_TOKEN 24h 过期,cache-from 认证失败
GitHub Actions 的 GITHUB_TOKEN 有效期只有 24 小时。用 cache-from: type=registry,ref=ghcr.io/owner/image 引用私有镜像时,BuildKit 需要在构建时拉取缓存层。token 过期后 registry 认证失败,cache-from 静默失效——不报错,只是跳过缓存直接构建。
免费套餐的 GITHUB_TOKEN 过期时间是 24h(付费是 60 天,但 workflow 每次触发都会刷新)。夜里跑没问题,第二天早上再看又是全量编译。
- name: Check GITHUB_TOKEN and registry auth
run: |
# 验证 token 是否能访问 ghcr.io
echo "Token prefix: ${{ secrets.GITHUB_TOKEN:0:4 }}..."
TOKEN=$(curl -s -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \
https://ghcr.io/token/service=container_registry&scope=repository:${{ github.repository }}:pull)
if echo "$TOKEN" | jq -e '.token' > /dev/null 2>&1; then
echo "Registry auth: OK"
else
echo "Registry auth: FAILED - cache-from will silently skip"
fi
坑2:.dockerignore 漏写导致上下文哈希变化
BuildKit 的缓存 Key 包含"构建上下文"的哈希值。如果 .dockerignore 漏掉了大目录(.venv、node_modules、.git),每次上传的上下文大小差异巨大,BuildKit 认为上下文变了,缓存失效。
实测:一个 Next.js 项目漏掉 node_modules,上下文从 12MB 变成 420MB,构建时间从 1 分钟变成 11 分钟。
# 包含式写法:以 * 开头显式排除所有,再逐个恢复需要的目录
*
!src/
!package.json
!package-lock.json
!requirements.txt
!.dockerignore
# 排除大目录(显式列出)
.venv/
node_modules/
__pycache__/
.git/
.idea/
.vscode/
dist/
build/
完整修复方案
两个坑一起修:用 docker/login-action@v3 续命 token,用包含式 .dockerignore 稳定上下文哈希。
name: Build and Push Docker Image
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
# 修复坑1:登录续命 GITHUB_TOKEN
- name: Login to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# 修复坑2:确认 .dockerignore
- name: Verify dockerignore
run: |
echo "=== .dockerignore contents ==="
cat .dockerignore
echo "=== context size ==="
du -sh .
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ghcr.io/${{ github.repository }}:latest
cache-from: type=registry,ref=ghcr.io/${{ github.repository }}:latest
cache-to: type=registry,ref=ghcr.io/${{ github.repository }}:latest,mode=max
效果验证
修复前后对比:
# 修复前(两个坑同时存在)
context size: 420MB
cache hit rate: 0%
build time: 11m 32s
# 修复后
context size: 12MB
cache hit rate: 73%
build time: 1m 18s
login-action 让 cache-from 认证恢复,命中率从 0% 回到 70%+。dockerignore 优化后上下文从 420MB 降到 12MB,BuildKit 缓存 Key 稳定,后续构建跳过所有未更改的层。
现在你可以做什么
第一步:检查你的 .dockerignore 是否有包含式写法(以 * 开头),没有的话改成上面格式,重新推一次触发新构建。
第二步:在 workflow 里加 docker/login-action@v3,放在 build-push-action 之前,确保每次构建前 token 有效。
第三步:看 CI 日志里是否出现 Using cache 或 Cached (pull) 字样,出现则缓存生效。
第四步:记住 GITHUB_TOKEN 免费套餐 24h 过期、付费 60 天。如果 workflow 间隔超过这个时间,cache-from 会静默失效,需要在 workflow 里加定时触发保持 token 活跃。
更多交流点击入群






