Let’s face it: 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. But 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 go into depth on some common recommendations that our solutions engineers make during one-on-one config reviews with enterprise-level customers. Today, we are focused on Docker layer caching (DLC), a powerful technique for saving Docker layers between jobs and speeding up your workflows.

Only available until recently on the Performance and Scale plans, DLC is now included on the new CircleCI Free plan as well as on installations of CircleCI server. In this post, we’ll talk about what Docker layer caching is, why it matters, and how you can add it 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 significant time during the build process by bypassing 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 fundamentally changed the landscape of software development, allowing teams to build, test, and deploy applications collaboratively, securely, and consistently by packaging binaries and dependencies into a portable unit of software that eliminates the potential for environment conflicts or the “it worked on my machine” conundrum. 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 you run your builds.

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, then you will not see any reduction in build times by implementing DLC.

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, which adds additional security to the build process and gives you access to a variety of Docker commands as well as the ability to SSH into your builds for debugging purposes. 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/node:17.3.0
        auth:
        username: mydockerhub-user
          password: $DOCKERHUB_PASSWORD
    steps:
      - checkout
      - setup_remote_docker:
          docker_layer_caching: true
      # DLC will explicitly cache layers here and try to avoid rebuilding.
      - run: docker build .

In this example config.yml file, you set docker as the execution environment for the build job and set 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, you can avoid rebuilding any unchanged layers.

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. You can create up to 50 DLC volumes per project. 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 part of speeding up your Docker builds on CircleCI and is now included in the CircleCI Free plan. If your team builds containerized applications, you can save valuable development time by reusing unchanged Docker layers within 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, see 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. If you are interested in an expert-level review of your CircleCI configuration, you can get a personalized, one-on-one evaluation from a dedicated support engineer by signing up for a premium support plan.