cicdJuly 5, 20265 min read

Docker Build Cache Optimization - Reduce Build Times by 80% | DevOps Duoo

Learn how to cut Docker build times by up to 80% using layer caching, multi-stage builds, and BuildKit cache. Includes production-tested Dockerfile examples.

Understanding Docker Layer Caching

Docker layer caching is a mechanism that allows Docker to reuse existing layers during the build process. This can significantly reduce build times, since Docker does not need to rebuild layers that have not changed.

When you run a docker build command, Docker creates a new image by executing the instructions in your Dockerfile. Each instruction creates a new layer, and Docker stores these layers in its cache. If you run the same docker build command again, Docker checks its cache for existing layers and reuses them if the instruction and its context have not changed.

Example Dockerfile

Here is a basic Dockerfile that demonstrates layer caching:

FROM python:3.11-slim

WORKDIR /app

COPY requirements.txt .

RUN pip install --no-cache-dir -r requirements.txt

COPY . .

EXPOSE 8000

CMD ["python", "app.py"]

In this example, Docker creates a new layer for each instruction. If you only change your application code, Docker reuses the cached layer for the pip install step because requirements.txt has not changed — saving significant time on repeated builds.

Optimizing Dockerfiles for Better Cache Utilization

To maximize cache reuse in your Dockerfiles, follow these best practices:

  • Place instructions that change infrequently (e.g., installing system dependencies) at the top of the Dockerfile.
  • Place instructions that change frequently (e.g., copying application source code) near the bottom.
  • Use multi-stage builds to separate the build and runtime environments.

Multi-Stage Builds Example

Multi-stage builds are one of the most effective Dockerfile optimizations available. They let you use a larger build image to compile your application and then copy only the final artifacts into a lean runtime image:

FROM python:3.11-slim AS build

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .
RUN python setup.py build

FROM python:3.11-slim

WORKDIR /app

COPY --from=build /app/build .

EXPOSE 8000

CMD ["python", "app.py"]

The build stage installs all dependencies and compiles the application, while the runtime stage contains only the output artifacts. This results in a smaller, more secure final image and faster subsequent builds.

Using BuildKit Cache

BuildKit is Docker's modern build backend. It provides improved performance, parallelism, and advanced caching capabilities. BuildKit is enabled by default in Docker Desktop and in Docker Engine 23.0+.

Enabling BuildKit

If you are on an older Docker version, you can enable BuildKit explicitly:

DOCKER_BUILDKIT=1 docker build -t myimage .

echo '{"features":{"buildkit":true}}' | sudo tee /etc/docker/daemon.json
sudo systemctl restart docker

Using the --cache-from Flag

Once BuildKit is enabled, you can use the --cache-from flag to pull a previously built image as a cache source — useful in CI/CD pipelines where the build cache does not persist between runs:

docker pull myimage:latest || true

docker build --cache-from myimage:latest -t myimage:latest .

This technique can dramatically reduce build times in CI environments by reusing layers from the last successful build.

Common Mistakes

When optimizing your Docker build process, watch out for these common mistakes:

  • Copying all files before installing dependencies: This invalidates the dependency cache on every code change. Always copy your dependency manifest (e.g., requirements.txt, package.json) before copying source files.
  • Not using multi-stage builds: Combining build and runtime environments results in bloated images and longer build times.
  • Not enabling BuildKit: Docker's legacy builder is significantly slower and less cache-efficient than BuildKit.
  • Using COPY . . too early: Broad COPY instructions early in the Dockerfile cause almost every layer to be invalidated on any file change.

Troubleshooting

If you are experiencing slow Docker builds, here are some steps to diagnose the issue:

  • Run docker build --progress=plain . to see exactly which steps are being cached and which are being rebuilt.
  • Use docker system df to check the size of your build cache and use docker builder prune to clear stale entries.
  • Add --no-cache to confirm whether the issue is cache-related: docker build --no-cache -t myimage .

Key Takeaways

  • Order your Dockerfile instructions from least to most frequently changed to maximize cache reuse.
  • Use multi-stage builds to keep your final images small and your build process efficient.
  • Enable BuildKit and use --cache-from to maintain a warm cache in CI/CD pipelines.
  • Use --progress=plain to diagnose cache hit/miss behavior.
  • Regularly audit and clean your Docker build cache with docker builder prune.

Share this article

← Back to Blog

Related Articles