New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Multi-stage build doesn't reuse previously made local cache from Github Cache Action #286
Comments
I also create an alternative use case, just to check if I use the action correctly. BehaviourSame idea. I want to reuse the local build cache. However this time I build all the stages in one action. Then build again separate stage (base, prod, and test) in the hope of doing a local retag to be used for docker testing and at the same time reuse existing cache. Steps to reproduce this issue
Expected behaviourSecond workflow run would reuse all cache from previous build. Each build stage would reuse these caches. Actual behaviourInterestingly for me. The step for building all stages reuse all the cache for all stage. Configuration
name: build-latest
on:
push:
jobs:
build-image:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Get build cache
uses: actions/cache@v2
with:
path: /tmp/.buildx-cache
key: buildx-${{ hashFiles('Dockerfile') }}
restore-keys: |
buildx-
- name: Build all stages
id: docker_build_all
uses: docker/build-push-action@v2
with:
context: .
file: Dockerfile
push: false
load: false
cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,mode=max,dest=/tmp/.buildx-cache
- name: Build base image
id: docker_build_base
uses: docker/build-push-action@v2
with:
context: .
file: Dockerfile
push: false
load: false
cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,mode=max,dest=/tmp/.buildx-cache
target: base
- name: Build prod image
id: docker_build_prod
uses: docker/build-push-action@v2
with:
context: .
file: Dockerfile
push: false
load: false
cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,mode=max,dest=/tmp/.buildx-cache
target: prod
- name: Build image for testing
id: docker_build_testing_image
uses: docker/build-push-action@v2
with:
context: .
file: Dockerfile
push: false
load: false
cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,mode=max,dest=/tmp/.buildx-cache
target: test
Logs |
I'm fine if the accepted use case is to actually build all stages to reuse the cache. |
I encountered the same problem even without cache-from and cache-to. I think it relates to |
@lucernae Any news on this? I'm in the same boat. |
I'm experiencing the same problem here https://github.com/epics-containers/epics-modules/blob/main/.github/workflows/buiild.yml |
@jfabre I don't know man. I just decided that it's beyond my power and knowledge. |
@lucernae Sorry for the delay. There might be some cache invalidation with actions/cache (GC) but I think you're hitting the following behavior where BuildKit will only build stages that are needed for the final target for your So smth like this might be better in your case: name: build-latest
on:
push:
jobs:
build-image:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Get build cache all
uses: actions/cache@v2
with:
path: /tmp/.buildx-all-cache
key: buildx-all-${{ hashFiles('Dockerfile') }}
restore-keys: |
buildx-all-
- name: Get build cache base
uses: actions/cache@v2
with:
path: /tmp/.buildx-base-cache
key: buildx-base-${{ hashFiles('Dockerfile') }}
restore-keys: |
buildx-base-
- name: Get build cache prod
uses: actions/cache@v2
with:
path: /tmp/.buildx-prod-cache
key: buildx-prod-${{ hashFiles('Dockerfile') }}
restore-keys: |
buildx-prod-
- name: Get build cache test
uses: actions/cache@v2
with:
path: /tmp/.buildx-test-cache
key: buildx-test-${{ hashFiles('Dockerfile') }}
restore-keys: |
buildx-test-
- name: Build all stages
id: docker_build_all
uses: docker/build-push-action@v2
with:
context: .
file: Dockerfile
push: false
load: false
cache-from: |
type=local,src=/tmp/.buildx-all-cache
cache-to: |
type=local,mode=max,dest=/tmp/.buildx-all-cache-new
- name: Build base image
id: docker_build_base
uses: docker/build-push-action@v2
with:
context: .
file: Dockerfile
push: false
load: false
cache-from: |
type=local,src=/tmp/.buildx-all-cache
type=local,src=/tmp/.buildx-base-cache
cache-to: |
type=local,mode=max,dest=/tmp/.buildx-base-cache-new
target: base
- name: Build prod image
id: docker_build_prod
uses: docker/build-push-action@v2
with:
context: .
file: Dockerfile
push: false
load: false
cache-from: |
type=local,src=/tmp/.buildx-all-cache
type=local,src=/tmp/.buildx-base-cache
type=local,src=/tmp/.buildx-prod-cache
cache-to: |
type=local,mode=max,dest=/tmp/.buildx-prod-cache-new
target: prod
- name: Build image for testing
id: docker_build_testing_image
uses: docker/build-push-action@v2
with:
context: .
file: Dockerfile
push: false
load: false
cache-from: |
type=local,src=/tmp/.buildx-all-cache
type=local,src=/tmp/.buildx-base-cache
type=local,src=/tmp/.buildx-prod-cache
type=local,src=/tmp/.buildx-test-cache
cache-to: |
type=local,mode=max,dest=/tmp/.buildx-prod-cache-new
target: test
-
# Temp fix
# https://github.com/docker/build-push-action/issues/252
# https://github.com/moby/buildkit/issues/1896
name: Move cache
run: |
rm -rf /tmp/.buildx-all-cache /tmp/.buildx-base-cache /tmp/.buildx-prod-cache /tmp/.buildx-test-cache
mv /tmp/.buildx-all-cache-new /tmp/.buildx-all-cache
mv /tmp/.buildx-base-cache-new /tmp/.buildx-base-cache
mv /tmp/.buildx-prod-cache-new /tmp/.buildx-prod-cache
mv /tmp/.buildx-test-cache-new /tmp/.buildx-test-cache You can also try with the new GitHub Action cache backend: name: build-latest
on:
push:
jobs:
build-image:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Build base image
id: docker_build_base
uses: docker/build-push-action@v2
with:
context: .
file: Dockerfile
push: false
load: false
cache-from: |
type=gha,scope=base
cache-to: |
type=gha,scope=base,mode=max
target: base
- name: Build prod image
id: docker_build_prod
uses: docker/build-push-action@v2
with:
context: .
file: Dockerfile
push: false
load: false
cache-from: |
type=gha,scope=prod
type=gha,scope=base
cache-to: |
type=gha,scope=prod,mode=max
target: prod
- name: Build image for testing
id: docker_build_testing_image
uses: docker/build-push-action@v2
with:
context: .
file: Dockerfile
push: false
load: false
cache-from: |
type=gha,scope=test
type=gha,scope=prod
type=gha,scope=base
cache-to: |
type=gha,scope=test,mode=max
target: test |
Thank you @crazy-max ! In my From the example you provide above, my use case fit the second yaml file using the new GH cache backend, so I will try that first. It's also nice because it's less verbose. |
Ah yes indeed I didn't look at the right Dockerfile...
Yes that's correct
Yes try it. I will also repro your use case and keep you in touch. |
@jfabre Ok was able to reproduce your initial use case and from what I see cache is invalidated because you're using the same cache folder for different targets which overrides the cache index (pretty much the same thing as #153 (comment)). One of the solutions in my comment above should fix your issue. |
Thanks @crazy-max and sorry to necro the thread a little bit. The GH cache backend works nicely. For others having the same issue, the key solution is to provide a different cache-to location for each different target. If you want to reuse any target, include the possible caches in cache-from (can be multiple lines). The problem is caused by cache invalidation if multiple target uses the same cache-to location. I've made an example action that build all the stages and then reuse it in the same run:
Again, thanks for the quick response. |
Effectively it means multi-stage builds are broken (it requires external configuration so it makes it useless, similar to running X Is there any roadmap to fixing this cache issue? type=local, type=gha and type=registry,ref=ghcr.io are all broken as they do not cache properly previous stage in GitHub Actions. |
we're struggling with this too. I can't get over how hard it is to do something as mundane as building a docker image in the most efficient way using github actions. This shouldn't be this hard. |
Troubleshooting
Before sumbitting a bug report please read the Troubleshooting doc.
Behaviour
I am using Multi-stage Dockerfile.
There are 3 stages,
base
,prod
andtest
.I'm also using Github cache action.
In the workflow, I build the target base, then prod, then test.
This is because I want to run the test first then store local cache.
When the tests finished, I want to build base and prod image with
push: true
to the registry, reusing the previous cache.I tried to control the caching. I put .dockerignore in such a way it ignores everything else except the Dockerfile. This is combined with cache key using
build-${{ hashFiles('Dockerfile') }}
in order for it to ensure a cache hit.I'm hoping that with this usage, whenever I change unittests, or github workflow files, the builder will reuse existing cache because obviously the image itself should not change.
However, what happens is:
Even without changing any files and rerun the workflow. This always happens.
Steps to reproduce this issue
Expected behaviour
Second workflow run should build all local images using the cache entirely, because no files are changed.
Workflow run after new commit should use cache entirely if build input doesn't change (files included in the docker context).
Actual behaviour
Base stage uses cache, but prod stage doesn't use prod cache, however it still uses base stage cache.
Test stage uses prod cache, but doesn't use test stage cache.
Configuration
Logs
logs_17.zip
The text was updated successfully, but these errors were encountered: