Docker image caching is a double-edged sword. On one hand, leveraging cached image layers can significantly speed up Docker builds. However, these cached layers and intermediate images accumulate over time and take up considerable disk space. For production Docker hosts, bloated unused image caches can cause performance and stability issues.

This comprehensive, practical guide will demonstrate how to safely remove cached Docker layers to reclaim storage space. Read on to understand how Docker image caching works, when and why to prune caches, and expert techniques to optimize your Docker build and run process.

Docker Image Layer Caching: A Primer

Before jumping into solutions, it‘s important to level-set on some key Docker concepts relevant to image caching…

How Docker Image Building Works

When running docker build, Docker reads the Dockerfile instructions and executes them sequentially. Each completed instruction creates a new image layer that represents an incremental change over the last layer.

These layers are cached by default, so that the next time the image is rebuilt, Docker can reuse any existing layers instead of starting completely from scratch. This is much faster than re-running every instruction every time.

The final image is actually a stack of these read-only image layers plus a writable container layer on top. The full layer history can be inspected via docker history.

Docker image layer diagram

Docker leverages intermediate image caching to accelerate builds

The Downside: Accumulating Dead Weight

Image caching speedups come at a storage cost. Intermediate images, untagged layers and dangling caches build up on your Docker host:

> docker images

REPOSITORY   TAG       IMAGE ID       CREATED         SIZE
<none>       <none>    585c1f9857b3   5 days ago      1.2GB
<none>       <none>    9d937da7287e   6 days ago      1.1 GB
ubuntu       latest    9140108b62dc   3 weeks ago     72.9MB

These intermediary artifacts can quickly consume tens or hundreds of GB worth of disk space.

Furthermore, the docker daemon must index and traverse these unused layers when starting containers or building images. This slows down Docker operations and reduces stability for production deployments.

Aggressively removing cached Docker image layers should be part of any container maintenance routine.

Now let‘s explore best practices for safe, effective cache cleaning…

Method 1: Avoid Caches with --no-cache During Builds

Adding the --no-cache flag to docker build forces reconstruction of intermediate image layers instead of relying on cached versions:

docker build --no-cache -t myimage:v1 .

This approach prevents caches from accumulating in the first place.

However, always re-building images from scratch negates the main benefit of caching – faster builds. Let‘s quantify the performance impact…

Cache vs Uncached Build: Benchmark Comparison

Below benchmarks measure build times for a typical Node.js Dockerfile running npm install, with and without the cache enabled:

Build Time
Cached 22 seconds
Uncached 1 minute 15 seconds

Uncached docker builds take over 3X longer on average

Source: 2021 Docker Benchmarks, Docker Inc.

Clearly, your specific build workload, infrastructure and Docker host I/O performance heavily sway results. But in general, avoiding the cache significantly slows down image construction.

Verdict: Only force uncached builds selectively when removing troublesome layers, or in your final pre-production pipeline run.

Method 2: Prune Dangling Docker Build Cache

Instead of disabling the cache completely, a smarter approach is pruning only expired image layers that are no longer associated with a tagged image.

The docker builder prune command tidies up these dangling build caches:

> docker builder prune

Total reclaimed space: 12.5GB

Prune dangling resources whenever disk pressure is high, and periodically as general container host hygiene.

Verdict: This strikes a balance between maintaining fast cached builds and saving storage capacity.

Tip: For even more aggressive space reclamation, try Docker layer garbage collection.

Method 3: Remove Specific Images by ID

You can permanently delete images via docker rmi, specifying the exact Image ID or digest.

First inspect all images and look out for large intermediaries:

> docker images

REPOSITORY                        TAG                 IMAGE ID            CREATED             SIZE
our-app                           latest              58cc0f9ba163        13 days ago         1.44GB   
<none>                            <none>              bab382333545        2 weeks ago         1.32GB
ubuntu                            18.04               0ef2e08ed3fa        6 months ago        64.2MB

Then target big caches for removal:

> docker rmi bab382333545 

Deleted Images:
bab382333545: Untagged bab382333545: Done  

Be careful to not delete tagged images still powering production containers!

Verdict: Useful for purging specific large intermediaries. Risky without proper tag hygiene practices.

Recap: Best Practices for Handling Docker Cached Layers

Here are key tips to remember when managing Docker caches:

  • Enable cache during development builds for speed. Just be prepared to prune before deploying.
  • Delete unused anonymous images with no tags regularly via prune and garbage collection.
  • Enforce image tag hygiene e.g. our-app:release_1.5 and avoid dangling untagged images.
  • Monitor Docker disk utilization and prune when thresholds are exceeded (e.g. >80%)
  • Rebuild from scratch pre-production using --no-cache to control layer size.
  • Delete large anonymous layers via docker rmi <id> when needed.
  • Consider multi-stage builds to copy only essential final artifacts, avoiding bulky intermediaries.

Integrating these cache best practices will let you enjoy faster Docker builds without the storage headaches!

Similar Posts