As a follow-up, I would like to share solutions and some explanation around Docker Buildx and the Docker Layer Cache (DLC) feature on CircleCI.
Re: DLC on CircleCI
When you build a Docker image, its layers are saved within the Docker root directory.
The Docker root directory is typically /var/lib/docker
for most setups.
However, builds on CircleCI (or any CI) are ephemeral.
The next build is likely on a different virtual machine (VM) and so we need a way to “pass” around the stored layers between builds.
Hence, layer caching on CircleCI works by storing and retrieving these layers in an external volume instead.
These volumes are attached to the remote machine running the Docker daemon.
The idea is that these volumes will likely include all, if not some of the layers as they get passed around.
More information: https://circleci.com/docs/docker-layer-caching#how-dlc-works
Re: How does this impact Docker Buildx
With Docker Buildx, developers can choose where the cached layers should be stored and retrieved.
There are many options, but this includes the local cache (folder), or a registry cache (i.e., saving the layers in a Docker repo on a registry like Docker Hub).
See the following options for the docker buildx build
command:
Note that you do not need the DLC feature in order to pass around the cache storage between builds.
Example: Cache from local folder
jobs:
build-push-local-docker:
docker:
- image: cimg/base:stable
resource_class: medium
environment:
- DOCKER_REGISTRY: docker.io
- DOCKER_USER: <user_or_org>
- DOCKER_LOGIN: <login_user>
steps:
- checkout
- setup_remote_docker:
version: 20.10.14
- run:
name: Check Docker settings (for buildx)
command: |
docker version
docker buildx version
docker context inspect
- run:
name: Setup docker buildx
command: |
docker context create circleci
docker buildx create --use circleci
docker buildx ls
docker context inspect circleci
- run:
name: Login to registry
command: |
# login credentials should be provided via context or project environment variables.
echo $DOCKER_PASSWORD | docker login $DOCKER_REGISTRY --username $DOCKER_LOGIN --password-stdin
- restore_cache:
keys:
- hello-buildx-docker-{{ arch }}-{{ .Branch }}-
- hello-buildx-docker-{{ arch }}-
- run:
name: Docker buildx with local cache
command: |
docker buildx build --progress=plain \
--tag="${DOCKER_REGISTRY}/${DOCKER_USER}/hello-buildx:${CIRCLE_SHA1}" \
--cache-to=type=local,mode=max,dest=/tmp/dockercache \
--cache-from=type=local,src=/tmp/dockercache \
--output=type=docker \
.
docker image ls
- save_cache:
key: hello-buildx-docker-{{ arch }}-{{ .Branch }}-{{ checksum "/tmp/dockercache/index.json" }}
paths:
- /tmp/dockercache
- run:
name: Publish image
command: |
docker image tag "${DOCKER_REGISTRY}/${DOCKER_USER}/hello-buildx:${CIRCLE_SHA1}" "${DOCKER_REGISTRY}/${DOCKER_USER}/hello-buildx:local-docker"
docker image push "${DOCKER_REGISTRY}/${DOCKER_USER}/hello-buildx:local-docker"
- run:
name: Prune cache
command: |
docker buildx prune
This solution uses the local
cache option for --cache-from
and --cache-to
.
With the local
cache strategy, we can take advantage of CircleCI’s restore_cache
and save_cache
steps to load and save the cached layers between builds!
Hope this helps!
I have a sample repo showcasing the registry and local cache strategies: