GHA中如何运行仅存于Docker本地构建缓存、未推送的镜像?
问题背景
- Dockerfile采用多阶段构建,定义了
builder和app两个阶段 - GitHub Actions工作流流程:先推送
builder阶段镜像到ghcr.io作为缓存,再构建app阶段镜像但不推送 - 运行已推送的
builder镜像正常,但运行未推送的app镜像时,报错:Unable to find image 'ghcr.io/geoheil/containerfun-app:latest' locally
- 当前临时方案是推送
app镜像到仓库再拉取运行,但期望直接使用本地构建缓存里的镜像
问题原因
多阶段构建时,如果构建app阶段的命令没有显式为镜像打上目标标签,Docker只会生成一个无标签的镜像(标记为<none>),不会自动关联你指定的仓库标签ghcr.io/geoheil/containerfun-app:latest。所以你用标签去运行时,Docker找不到对应的镜像。
另外,GitHub Actions的步骤虽共享同一环境,但如果构建步骤未正确保留镜像标签,后续运行步骤也无法通过标签定位到本地构建的镜像。
解决方案
方案1:构建时直接打标签
在构建app阶段的命令中添加--tag参数指定目标标签,构建完成后本地就会有带标签的镜像,直接运行即可:
docker build --tag ghcr.io/geoheil/containerfun-app:latest --target app .
在GHA工作流中,把构建步骤改成上述命令,后续运行步骤直接用该标签执行docker run ghcr.io/geoheil/containerfun-app:latest。
方案2:通过镜像ID运行
如果已完成构建但没打标签,可以先列出本地镜像找到app阶段对应的镜像ID,再用ID运行:
- 列出镜像:
docker images
找到app阶段对应的无标签镜像(通常是最后构建的那个,可通过创建时间判断)
2. 用ID运行:
docker run <镜像ID>
在GHA中,可直接用命令捕获镜像ID:
IMAGE_ID=$(docker build --target app -q .) docker run $IMAGE_ID
-q参数会只输出镜像ID,方便后续变量引用。
方案3:优化GHA工作流缓存
如果想复用builder阶段的缓存同时保留app阶段的本地镜像,可改用GHA的Docker缓存动作,无需推送builder镜像到仓库,同时确保app镜像被正确标记:
jobs: build-and-run: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Cache Docker layers uses: actions/cache@v3 with: path: /tmp/.buildx-cache key: ${{ runner.os }}-buildx-${{ github.sha }} restore-keys: | ${{ runner.os }}-buildx- - name: Build app image locally run: docker build --tag ghcr.io/geoheil/containerfun-app:latest --target app . --cache-from type=local,src=/tmp/.buildx-cache --cache-to type=local,dest=/tmp/.buildx-cache,mode=max - name: Run app image run: docker run ghcr.io/geoheil/containerfun-app:latest
该方案用Buildx和本地缓存复用builder阶段的构建结果,直接给app镜像打标签,无需推送任何镜像到仓库就能运行。
内容的提问来源于stack exchange,提问作者Georg Heiler

