This action generates cache-from
and cache-to
inputs of docker/build-push-action for the effective cache strategy in the pull request based development flow.
docker/build-push-action supports the cache management using Buildx (BuildKit). It can import and export a cache by the following parameters:
cache-from: type=registry,ref=REGISTRY/REPOSITORY:TAG
cache-to: type=registry,ref=REGISTRY/REPOSITORY:TAG,mode=max
If a same tag is used in the pull request based development flow, it will cause a cache miss. For example,
- Initially, the cache points to main branch
- When a pull request B is opened,
- It imports the cache of main branch
- The cache hits
- It exports the cache of pull request B
- When a pull request C is opened,
- It imports the cache of pull request B
- The cache misses
- It exports the cache of pull request C
- When the pull request B is merged into main,
- It imports the cache of pull request C
- The cache misses
- It exports the cache of main branch
Therefore, it needs to prevent the cache pollution caused by a pull request.
Keep a cache tag tracking the corresponding branch.
When the main branch is pushed, it imports a cache from the main tag. It finally exports a cache to the main tag for the future build.
cache-from: type=registry,ref=REGISTRY/REPOSITORY:main
cache-to: type=registry,ref=REGISTRY/REPOSITORY:main,mode=max
When a pull request is created or updated, it only imports a cache from the main tag. It does not export a cache to the main tag to prevent the cache pollution.
cache-from: type=registry,ref=REGISTRY/REPOSITORY:main
cache-to:
If the base branch of the pull request is not main, it imports both base tag and main tag.
cache-from: |
type=registry,ref=REGISTRY/REPOSITORY:base
type=registry,ref=REGISTRY/REPOSITORY:main
cache-to:
Here is the diagram of this cache strategy.
This action generates the cache parameters by this strategy.
- uses: int128/docker-build-cache-config-action@v1
id: cache
with:
image: ghcr.io/${{ github.repository }}/cache
- uses: docker/build-push-action@v2
with:
cache-from: ${{ steps.cache.outputs.cache-from }}
cache-to: ${{ steps.cache.outputs.cache-to }}
Here is an example to manage a cache in GHCR (GitHub Container Registry).
- uses: docker/metadata-action@v3
id: metadata
with:
images: ghcr.io/${{ github.repository }}
- uses: int128/docker-build-cache-config-action@v1
id: cache
with:
image: ghcr.io/${{ github.repository }}/cache
- uses: docker/build-push-action@v2
id: build
with:
push: true
tags: ${{ steps.metadata.outputs.tags }}
labels: ${{ steps.metadata.outputs.labels }}
cache-from: ${{ steps.cache.outputs.cache-from }}
cache-to: ${{ steps.cache.outputs.cache-to }}
It will create the following image tags:
ghcr.io/${{ github.repository }}:main
ghcr.io/${{ github.repository }}:pr-1
ghcr.io/${{ github.repository }}/cache:main
You can set a tag suffix to store both image and cache into the same repository.
- uses: docker/metadata-action@v3
id: metadata
with:
images: ghcr.io/${{ github.repository }}
- uses: int128/docker-build-cache-config-action@v1
id: cache
with:
image: ghcr.io/${{ github.repository }}
flavor: suffix=-cache
- uses: docker/build-push-action@v2
id: build
with:
push: true
tags: ${{ steps.metadata.outputs.tags }}
labels: ${{ steps.metadata.outputs.labels }}
cache-from: ${{ steps.cache.outputs.cache-from }}
cache-to: ${{ steps.cache.outputs.cache-to }}
It will create the following image tags:
ghcr.io/${{ github.repository }}:main
ghcr.io/${{ github.repository }}:main-cache
ghcr.io/${{ github.repository }}:pr-1
Amazon ECR now supports the cache manifest (aws/containers-roadmap#876).
You can pass the extra attribute image-manifest=true
.
Here is an example to manage a cache in Amazon ECR.
jobs:
build:
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
outputs:
image-uri: ${{ steps.ecr.outputs.registry }}/${{ github.repository }}@${{ steps.build.outputs.digest }}
steps:
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::ACCOUNT:role/ROLE
- uses: aws-actions/amazon-ecr-login@v1
id: ecr
- uses: docker/metadata-action@v5
id: metadata
with:
images: ${{ steps.ecr.outputs.registry }}/${{ github.repository }}
- uses: int128/docker-build-cache-config-action@v1
id: cache
with:
image: ${{ steps.ecr.outputs.registry }}/${{ github.repository }}
suffix: -cache
extra-cache-to: image-manifest=true
- uses: docker/build-push-action@v5
id: build
with:
push: true
tags: ${{ steps.metadata.outputs.tags }}
labels: ${{ steps.metadata.outputs.labels }}
cache-from: ${{ steps.cache.outputs.cache-from }}
cache-to: ${{ steps.cache.outputs.cache-to }}
It will create the following image tags:
ACCOUNT.dkr.ecr.REGION.amazonaws.com/${{ github.repository }}:main
ACCOUNT.dkr.ecr.REGION.amazonaws.com/${{ github.repository }}:pr-1
ACCOUNT.dkr.ecr.REGION.amazonaws.com/${{ github.repository }}:main-cache
When a pull request is pushed, it can export a cache to a dedicated tag for the consecutive commits. It imports the cache from the dedicated tag when the pull request is pushed again.
cache-from: |
type=registry,ref=REGISTRY/REPOSITORY:pr-1
type=registry,ref=REGISTRY/REPOSITORY:main
cache-to: type=registry,ref=REGISTRY/REPOSITORY:pr-1,mode=max
Here is an example to enable the pull request cache feature.
- uses: docker/metadata-action@v3
id: metadata
with:
images: ghcr.io/${{ github.repository }}
- uses: int128/docker-build-cache-config-action@v1
id: cache
with:
image: ghcr.io/${{ github.repository }}/cache
pull-request-cache: true
- uses: docker/build-push-action@v2
id: build
with:
push: true
tags: ${{ steps.metadata.outputs.tags }}
labels: ${{ steps.metadata.outputs.labels }}
cache-from: ${{ steps.cache.outputs.cache-from }}
cache-to: ${{ steps.cache.outputs.cache-to }}
It will create the following image tags:
ghcr.io/${{ github.repository }}:main
ghcr.io/${{ github.repository }}:pr-1
ghcr.io/${{ github.repository }}/cache:main
ghcr.io/${{ github.repository }}/cache:pr-1
Note that it creates an image tag for every pull request. It is recommended to clean it when pull request is closed, or set a lifecycle policy into your container repository.
You can set a tag suffix to isolate caches for each architecture.
jobs:
build:
strategy:
fail-fast: false
matrix:
platform:
- linux/amd64
- linux/arm64
steps:
- uses: docker/metadata-action@v3
id: metadata
with:
images: ghcr.io/${{ github.repository }}
flavor: suffix=-${{ matrix.platform }}
- uses: int128/docker-build-cache-config-action@v1
id: cache
with:
image: ghcr.io/${{ github.repository }}/cache
flavor: suffix=-${{ matrix.platform }}
- uses: docker/build-push-action@v2
id: build
with:
push: true
tags: ${{ steps.metadata.outputs.tags }}
labels: ${{ steps.metadata.outputs.labels }}
cache-from: ${{ steps.cache.outputs.cache-from }}
cache-to: ${{ steps.cache.outputs.cache-to }}
platforms: ${{ matrix.platform }}
It will create the following image tags:
ghcr.io/${{ github.repository }}:main-linux-amd64
ghcr.io/${{ github.repository }}:main-linux-arm64
ghcr.io/${{ github.repository }}:pr-1-linux-amd64
ghcr.io/${{ github.repository }}:pr-1-linux-arm64
ghcr.io/${{ github.repository }}/cache:main-linux-amd64
ghcr.io/${{ github.repository }}/cache:main-linux-arm64
You can set a tag prefix to store caches of multiple images into a single repository.
- uses: docker/metadata-action@v3
id: metadata
with:
images: ghcr.io/${{ github.repository }}/microservice-name
- uses: int128/docker-build-cache-config-action@v1
id: cache
with:
image: ghcr.io/${{ github.repository }}/cache
flavor: prefix=microservice-name--
- uses: docker/build-push-action@v2
id: build
with:
push: true
tags: ${{ steps.metadata.outputs.tags }}
labels: ${{ steps.metadata.outputs.labels }}
cache-from: ${{ steps.cache.outputs.cache-from }}
cache-to: ${{ steps.cache.outputs.cache-to }}
It will create the following image tags:
ghcr.io/${{ github.repository }}/microservice-name:main
ghcr.io/${{ github.repository }}/microservice-name:pr-1
ghcr.io/${{ github.repository }}/cache:microservice-name--main
For a complex project, it needs to build multiple image tags from a branch. For example, it builds the following images when the main branch is pushed:
- Build an image tag
development
with the build-args of development environment - Build an image tag
staging
with the build-args of staging environment
In this case, it needs to separate the cache for each environment as follows:
- When the main branch is pushed,
- A job builds an image for the development environment.
It imports and exports a cache from/to
development
tag. - A job builds an image for the staging environment.
It imports and exports a cache from/to
staging
tag.
- A job builds an image for the development environment.
It imports and exports a cache from/to
- When a pull request is created or updated,
- A job builds an image for the pull request environment.
It imports a cache from
development
tag.
- A job builds an image for the pull request environment.
It imports a cache from
You can set a suffix to separate the caches for each environment.
jobs:
build:
strategy:
fail-fast: false
matrix:
environment:
- development
- staging
steps:
- uses: docker/metadata-action@v3
id: metadata
with:
images: ghcr.io/${{ github.repository }}
flavor: suffix=-${{ matrix.environment }}
- uses: int128/docker-build-cache-config-action@v1
id: cache
with:
image: ghcr.io/${{ github.repository }}/cache
cache-key: ${{ matrix.environment }}
cache-key-fallback: development
- uses: docker/build-push-action@v2
id: build
with:
push: true
tags: ${{ steps.metadata.outputs.tags }}
labels: ${{ steps.metadata.outputs.labels }}
cache-from: ${{ steps.cache.outputs.cache-from }}
cache-to: ${{ steps.cache.outputs.cache-to }}
It will create the following image tags:
ghcr.io/${{ github.repository }}:development
ghcr.io/${{ github.repository }}:staging
ghcr.io/${{ github.repository }}/cache:development
ghcr.io/${{ github.repository }}/cache:staging
Name | Default | Description |
---|---|---|
image |
(required) | Image repository to import/export cache |
flavor |
- | Flavor (multiline string) |
extra-cache-from |
- | Extra flag to cache-from |
extra-cache-to |
- | Extra flag to cache-to |
pull-request-cache |
- | Import and export a pull request cache |
cache-key |
- | Custom cache key |
cache-key-fallback |
- | Custom cache key to fallback |
flavor
is mostly compatible with docker/metadata-action
except this action supports only prefix
and suffix
.
extra-cache-to
is added to cache-to
parameter only when it needs to export cache.
Note that cache-key
and cache-key-fallback
are experimental.
The specification may change in the future.
Name | Description |
---|---|
cache-from |
Parameter for docker/build-push-action |
cache-to |
Parameter for docker/build-push-action |
This action exports a cache on the following events:
push
event to a branch- Export a cache to the tag corresponding to the pushed branch
pull_request
event- Export a cache to the tag corresponding to the pull request number (only if
pull-request-cache
is set)
- Export a cache to the tag corresponding to the pull request number (only if
issue_comment
event to a pull request- Export a cache to the tag corresponding to the pull request number (only if
pull-request-cache
is set)
- Export a cache to the tag corresponding to the pull request number (only if
- Other events
- Export nothing
It imports a cache on the following events:
push
event to a branch- Import a cache from the tag corresponding to the pushed branch
pull_request
event- Import a cache from the tag corresponding to the pull request number
- Import a cache from the tag corresponding to the base branch
- Import a cache from the tag corresponding to the default branch
issue_comment
event to a pull request- Import a cache from the tag corresponding to the pull request number
- Import a cache from the tag corresponding to the base branch
- Import a cache from the tag corresponding to the default branch
- Other events
- Import a cache from the tag corresponding to the default branch