Creating the optimal CI/CD workflow is not always a simple task. In fact, writing effective and efficient configuration code is the biggest hurdle that many developers face in their DevOps journey.

You don’t need to be an expert to set up a fast, reliable testing and deployment infrastructure. With a few straightforward techniques, you can optimize your config.yml file and unleash the full potential of your CI/CD pipelines.

In this series, we’re sharing some of the top recommendations that our solutions engineers make during one-on-one config reviews with customers. In this article, our focus is on Docker layer caching (DLC), a powerful technique for saving Docker layers between jobs and speeding up your workflows.

In this post, we’ll explain what Docker layer caching is, why it matters, and how you can add a Docker build cache to your pipelines.

What is Docker layer caching?

Docker is the containerization technology used on the CircleCI platform. In both the Docker executor and the machine execution environment, you can run Docker build commands to containerize your applications for testing and deployment. With Docker layer caching, you can save individual layers of the Docker images you build so that they can be reused in subsequent pipeline runs.

Docker layer caching can save your team time during the build process by skipping some or all of the image build steps.

Docker images are built from Dockerfiles, and each command in the Dockerfile creates a new layer in the image. When you build a Docker image with docker build or docker compose, DLC saves the individual layers to a volume attached to the machine or remote Docker instance running the job. The next time you run the image build job, CircleCI will retrieve any unchanged layers from the cache.

If your Dockerfile stays the same between pipeline runs, the entire image will be retrieved from the cache. If you introduce a change to the Dockerfile between runs, CircleCI will retrieve all the layers up to the change, then build the rest of the image based on the new Dockerfile. The less your Dockerfile changes between runs, the faster your image will build.

When should you use Docker layer caching?

Docker containers have changed the landscape of software development. Using Docker, teams can build, test, and deploy applications collaboratively, securely, and consistently by packaging binaries and dependencies into a portable unit of software. This process eliminates the potential for environment conflicts or the “it worked on my machine” issue. Many teams have adopted containerization as a way to implement cloud-native development practices and shift their software architecture toward a more distributed approach.

If your application relies on containers, you may find yourself building the same image on every run of your CI/CD pipeline, which can be a serious drain on your build minutes. By enabling Docker layer caching, you can achieve a significant reduction in build times by reusing cached image layers rather than building them from scratch each time.

Note that DLC will only reduce the time it takes to build your own Docker images with docker build, docker compose, or similar docker commands in a remote Docker environment. It does not affect the time it takes to spin up the primary Docker container. If you are running your pipelines in a Docker container but not building new images as part of your workflow, DLC won’t provide that reduction in build times.

How to add Docker layer caching to your pipelines

You can use Docker layer caching to speed up Docker image builds in both the Docker and the machine execution environments. In the Docker execution environment, any Docker images that you create are built in a secondary container called the remote Docker environment.

The remote Docker environment:

  • Adds security to the build process
  • Gives you access to many Docker commands
  • Lets you SSH into your builds for debugging

You can spin up the remote Docker environment with the setup-remote-docker key, then add Docker layer caching to the build job by setting docker_layer_caching to true:

version: 2
jobs:
  build:
    docker:
      # DLC does nothing here, its caching depends on commonality of the image layers.
      - image: cimg/base:2023.04

    steps:
      - checkout
      - setup_remote_docker:
          docker_layer_caching: true
      # DLC will explicitly cache layers here and try to avoid rebuilding.
      - run: docker build .

This example config.yml file sets docker as the execution environment for the build job and sets up a remote Docker environment with docker_layer_caching set to true. CircleCI will cache the layers of the Docker image you build with the docker build command so that the next time you run this job, any unchanged layers won’t be rebuilt.

The machine execution environment does not require a remote Docker environment to run docker or docker-compose commands, so you can include the docker_layer_caching: true key directly below your machine executor key:

version: 2
jobs:
  build_elixir:
    machine:
      image: ubuntu-2004:202104-01
      docker_layer_caching: true
    steps:
      - checkout
      - run:
          name: build Elixir image
          command: docker build -t circleci/elixir:example .

In this example, you set the ubuntu-2004:202104-01 Linux image as your machine executor type, then set docker_layer_caching: true to enable Docker layer caching for this environment. When you build the Elixir image with the docker build command, CircleCI will cache the individual layers to be reused in future runs.

Once you have enabled DLC for your project, any layers that are saved will be available for three days between job runs. Any cached layers that are not reused after three days will be deleted.

For more information on how to implement Docker layer caching in your projects, as well as some potential use cases and limitations, visit the DLC documentation.

Conclusion

Docker layer caching is an important tool for speeding up your Docker builds on CircleCI. If your team builds containerized applications, you can save valuable development time by reusing unchanged Docker layers in your projects. This not only makes your team more efficient and saves your organization money, but it also helps you deliver value to your users faster, a key differentiator in today’s software development landscape.

DLC is only one of many different optimizations you can make to your config. Other cache-based optimizations include persisting data in workspaces and caching dependencies for faster builds. For more information on dependency caching, check out Config best practices: dependency caching. Stay tuned for other deep dives into available config optimizations in future installments of this series.

To get started using the most powerful CI/CD platform to build, test, and deploy your applications faster and with more confidence, sign up for a free plan today.

Start Building for Free