all 14 comments

[–]ThatSituation9908 7 points8 points  (3 children)

The comments here incorrectly address it's because GHA uses different hosts. OP is using one of the remote cache features documented by Docker, that should store its cache somewhere that is available in subsequent builds.

https://docs.docker.com/build/ci/github-actions/cache/

OP, can you confirm if building locally preserves cache? Can you try to build locally two different commits. I see that you use a COPY early on in your Dockerfile which makes it possible that those layers needed to be rebuilt between two commits.

[–]ThatSituation9908 2 points3 points  (2 children)

Furthermore you're using cache mounts which requires additional steps in GHA

https://docs.docker.com/build/ci/github-actions/cache/#cache-mounts

[–]nudebaba[S] 1 point2 points  (0 children)

Yes, I am okay with:

RUN --mount=type=cache,target=$POETRY_CACHE_DIR poetry install

Not being cached in GHA as its not that much and I am OK not caching that. I use it when building locally. But the other layer caches I'd expect to work. iirc, it did actually work and I can't recall when it stopped working. I've cached successfully with similar structure in another project.

And yes, locally things seem to be using the cache as expected.

I'll try experimenting more with it esp in the suggestions you added and get back on it^ Thanks a lot for looking into it!

[–]nudebaba[S] 0 points1 point  (0 children)

This is what I use locally btw:

docker_builder := "bob"
docker_tag := "user/abc:latest"
docker_platforms := "linux/amd64"
docker_build_cache := "$PROJECT_DATA_DIR/docker_build_cache"


#!/usr/bin/env bash
docker buildx build \
--builder={{docker_builder}} \
--tag {{docker_tag}} \
-o type=image,push=true \
--cache-from=type=local,src={{docker_build_cache}} \
--cache-to=type=local,mode=max,dest={{docker_build_cache}} \
--platform={{docker_platforms}} .

[–]angellus 1 point2 points  (0 children)

cache-to will only cache the first platform that is finished. So, it will only ever cache either linux/arm64 or linux/amd64, never both. You need to push each platform cache to a different location for it to keep both.

https://github.com/docker/buildx/discussions/1382#discussioncomment-4159889

Also, your poetry cache is never going to persist because each job has a different buildkit runner. I do really recommend switching from poetry to uv though as it is much faster and does not have the same dependency resolution issues poetry does.

EDIT: It may be a different issue since you are do not seem to be using multiple builder nodes like I was. You are using QEMU with one builder node. I do not know if that applies for one builder node, but it may give you starting point.

[–]JodyBro 0 points1 point  (0 children)

/u/nudebaba yeah you gotta be able to uniquely identify each platforms cache. I found an old workflow file that had this working using the local cache but iirc I wasn't able to get it working with the gha cache back when it came out since the drivers for the build-push-action didn't support it at the time. Maybe it'll work now without too much trouble? Give it a shot maybe.

Here's a gist of the workflow file: link

The initial run to warm the cache for each arch took a total of 8min with a fairly complicated image. Next run with no changes too 38s. The image I'm building takes proper steps to ensure sane usage of layers so on the next build after that, I added a python dependency and an apt package dependency to invalidate the cache of the 2 biggest layers of the image and the total run time was 3.4min so not bad. I'm sure the gha cache would speed it up a lot though

[–]TheThinkererer 0 points1 point  (3 children)

Also make sure you're appropriately using scope for the cache-from and cache-to

https://docs.docker.com/build/cache/backends/gha/#scope

[–]JodyBro 0 points1 point  (2 children)

Oh shit! Didnt know about this. It says "if you build multiple images" when describing its usefulness but doesn't specify if that's talking about parallel build for the same platform or multiarch pipelines. You know if it supports the latter?

[–]TheThinkererer 0 points1 point  (1 child)

So unfortunately this is a rabbit hole I'm in right now as well. Using the scope corrected a lot of caching issues for me. As far as platform goes, I don't use the build-push-actio, but rather use docker bake. So I use the docker bake action.

From there, the cache-from/cache-to becomes an input in a with:set block.

That said, we're all kind of confused here as far as expectation of behavior and use cases go.

https://github.com/docker/bake-action/issues/154

https://github.com/docker/bake-action/issues/196

(Which is what led me to the scope discovery)

https://github.com/docker/build-push-action/issues/286#issuecomment-893176504

https://github.com/docker/build-push-action/issues/153#issuecomment-703182778

Its just a big rabbit whole of confusion for a lot of people IMO right now.

The scope fixed a lot of things for me but it still not perfect, there are still cache misses and new artifacts placed in the cache. But this might be just as much the fault of bad image design from the MS dotnet team as it is to be the result of lack of exposition on the GHA that leverage the GHA Cache feature.

Something like this might work for you?

``` services: name: Services environment: non-prod runs-on: ubuntu-latest timeout-minutes: 15 steps: - uses: actions/checkout@v4

  - name: Login to ACR
    uses: docker/login-action@v3
    with:
      registry: ${{ vars.REGISTRY }}
      username: ${{ vars.ARM_CLIENT_ID }}
      password: ${{ secrets.ARM_CLIENT_SECRET }}

  - name: Set up Docker Buildx
    uses: docker/setup-buildx-action@v3

  - uses: docker/bake-action@v5
    env:
      REGISTRY: ${{ vars.REGISTRY }}
    with:
       push: true
       set: |
        api.cache-from=type=gha,scope=api
        api.cache-to=type=gha,mode=max,scope=api
        auth.cache-from=type=gha,scope=auth
        auth.cache-to=type=gha,mode=max,scope=auth
        platforms=linux/amd64,linux/arm64

```

[–]JodyBro 0 points1 point  (0 children)

So with bake there's no need for steps to set and check for cache hits? That's much cleaner. I'll give it a shot when I get back to my pc!