概述
把缓存层推成 :cache 标签虽然可行,但会把构建内部产物放进用户可拉取的命名空间,也让镜像清理变得含糊。type=gha 后端把缓存存入 GitHub Actions 缓存服务,并按仓库隔离:BuildKit 通过 cache-from 导入、通过 cache-to 导出,镜像仓库只接收最终镜像。只需在构建步骤启用一次,后续运行即可受益,不需要额外基础设施。
步骤
- 构建时同时启用缓存导入与导出:
- uses: docker/setup-buildx-action@v3
- uses: docker/build-push-action@v6
with:
context: .
push: true
tags: ghcr.io/acme/api:${{ github.sha }}
cache-from: type=gha,scope=${{ github.ref_name }}
cache-to: type=gha,mode=max,scope=${{ github.ref_name }}
- 按分支隔离缓存作用域,避免特性分支覆盖主分支缓存:
cache-from: type=gha,scope=${{ github.ref_name }}
cache-to: type=gha,mode=max,scope=${{ github.ref_name }}
- 调整 Dockerfile 顺序,先复制锁文件再复制源码:
COPY package.json pnpm-lock.yaml ./
RUN corepack enable && pnpm install --frozen-lockfile
COPY . .
RUN pnpm build
- 用
.dockerignore排除密钥,确保任何缓存层都不会包含敏感文件:
.env
.env.*
*.pem
验证
第二次运行应出现大量 CACHED 标记,依赖安装层被复用,总时长明显下降。修改业务源码后,只有最后几层失效,安装层仍然命中。若缓存始终不命中,检查基础镜像是否使用了可变 tag,以及 apt-get update 是否与安装分离;这两者都会让第一层每次变化。
注意事项
- Actions 缓存按仓库隔离,并会在长期不活跃后被清理,只能当作加速手段,不能当作持久存储。
mode=max会缓存中间阶段,容易耗尽仓库缓存配额,大镜像建议改用mode=min。- 基础镜像应使用 digest 固定,tag 变化会导致缓存静默失效。
- 缓存命中不代表产物安全,最终镜像仍需经过漏洞扫描。
- 不要把
node_modules之类的大目录写入构建上下文,它会破坏缓存复用并拖慢上传。