Docker image builds can utilize cached image layers to improve build speeds. However, sometimes a full, clean rebuild of the Docker image is required. This article covers how to perform a clean Docker image build without leveraging any cached image layers using the "--no-cache" flag.

Background on Docker Image Building

When running docker build, Docker checks for existing intermediate image layers it can reuse to optimize the build process. By default, if files in the Docker context change from previous builds, Docker will rebuild those layers, but reuse other cached layers to speed up builds.

For example, consider this Dockerfile:

FROM ubuntu:latest
RUN apt-get update
RUN apt-get install -y nginx
COPY index.html /var/www/html

The first time this Dockerfile is built, Docker will:

  1. Pull the ubuntu:latest base image
  2. Run apt-get update and commit that layer
  3. Install nginx and commit that layer
  4. Copy over index.html and commit that layer

On the next build, if only index.html changed, Docker would:

  1. Reuse existing ubuntu:latest layer from cache
  2. Reuse apt update layer from cache
  3. Reuse nginx install layer from cache
  4. Only rebuild the final layer copying index.html

By leveraging its layer cache intelligently like this, Docker can avoid unnecessary work and speed up builds.

However, sometimes you need to force Docker to rebuild the full image from scratch using --no-cache.

When to Use docker build --no-cache

There are a few common reasons you may want to utilize --no-cache for clean Docker builds:

  • Base image was updated: If your FROM base image was updated to a new version, you likely want to rebuild fully from latest base image version.

  • Dependency changes: If Dockerfile depends on files not copied into image that could have changed like package manager lock files or host mounted volumes, may need full rebuild.

  • Build consistency: Sometimes you want 100% clean/consistent builds, avoiding any potential issues with cache inconsistencies.

  • Security policies: In some corporate environments, security policies may require clean full rebuilds of images to avoid risks from relying on cache layers between builds.

Using --no-cache forces Docker to rebuild the full image in isolation without relying on any cached image layers from previous builds.

How docker build --no-cache Works

When Docker builds an image, it checks if it has existing images layers from previous builds it can reuse before executing each image layer step defined in the Dockerfile.

The --no-cache=true flag tells Docker to ignore any cached image layers and build each layer from scratch instead.

For example, consider this Dockerfile:

# Build stage
FROM golang AS build
...

# Final stage 
FROM alpine
COPY --from=build /app /app  

Normally on rebuilds Docker would reuse the golang and alpine base images from cache.

With --no-cache Docker will pull the latest versions of golang and alpine images ignoring cache, fully recreating the build, before copying artifacts over into the final image.

Using docker build --no-cache

To perform a Docker build without layer cache, simply add the --no-cache=true flag to your docker build command:

docker build --no-cache=true -t myimage .

You can also use the shorter -no-cache format:

docker build -no-cache -t myimage . 

That‘s all it takes to force a clean Docker image build!

Let‘s walk through an example to see this in practice.

Dockerfile Example

First, consider this simple Dockerfile that builds a Nginx web server:

# Base off latest ubuntu LTS 
FROM ubuntu:jammy

# Metadata
LABEL maintainer="sven@example.com"

# Update packages  
RUN apt-get update && apt-get install -y \
    nginx

# Configure nginx  
COPY nginx.conf /etc/nginx/

# Copy site data
COPY html /var/www/html

# Open port 80    
EXPOSE 80

# Start Nginx
CMD ["nginx", "-g", "daemon off;"]  

Next, build the initial Docker image:

$ docker build -t my-site:v1 .
[+] Building 8.2s (16/16) FINISHED
 => [internal] load build definition from Dockerfile                                                               0.1s
 => => resolving docker.io/library/ubuntu:jammy                                                                  0.1s
 => [auth] library/ubuntu:pull token for registry-1.docker.io                                                       0.0s
 => [internal] load .dockerignore                                                                                 0.0s
 => => transferring context: 35B                                                                                  0.0s 
 => [internal] load metadata for docker.io/library/ubuntu:jammy                                                    1.7s
 => [ 1/11] FROM docker.io/library/ubuntu:jammy@sha256:416d97810e5cc1ed2739aaeaf1e2c4c7debd16f58aff157   0.0s
 => CACHED [ 2/11] RUN apt-get update && apt-get install -y   nginx                                                0.0s
 => CACHED [ 3/11] COPY nginx.conf /etc/nginx/                                                                    0.0s    
 => CACHED [ 4/11] COPY html /var/www/html                                                                        0.0s
 => CACHED [ 5/11] EXPOSE 80                                                                                      0.0s
 => CACHED [ 6/11] CMD ["nginx" "-g" "daemon off;"]                                                               0.0s   
 => exporting to image                                                                                            1.4s   
 => => exporting layers                                                                                           1.4s   
 => => writing image sha256:8ad0d5cee6b7fed919561e9c52256595c9535f25862f3c69dab848c368fcd329                      0.0s   
 => => naming to docker.io/library/my-site:v1  

We can test it out with:

$ docker run -dp 80:80 my-site:v1  

And we‘ll see our site running at http://localhost.

Now let‘s make some changes and rebuild.

Rebuilding Without --no-cache

First, edit html/index.html locally and update some text.

Next, rebuild with docker build:

$ docker build -t my-site:v2 . 
[+] Building 1.8s (9/9) FINISHED
 => [internal] load build definition from Dockerfile                                                               0.1s 
 => => transferring dockerfile: 37B                                                                               0.0s
 => [internal] load .dockerignore                                                                                 0.0s 
 => => transferring context: 35B                                                                                  0.0s
 => [internal] load metadata for docker.io/library/ubuntu:jammy                                                    1.7s
 => [ 1/6] FROM docker.io/library/ubuntu:jammy@sha256:416d97810e5cc1ed2739aaeaf1e2c4c7debd16f58aff157a3d0c5d   0.0s
 => CACHED [ 2/6] RUN apt-get update && apt-get install -y   nginx                                                 0.0s
 => CACHED [ 3/6] COPY nginx.conf /etc/nginx/                                                                     0.0s
 => CACHED [ 4/6] EXPOSE 80                                                                                       0.0s
 => CACHED [ 5/6] CMD ["nginx" "-g" "daemon off;"]                                                                0.0s
 => [ 6/6] COPY html /var/www/html                                                                                0.7s
 => exporting to image                                                                                            0.1s
 => => exporting layers                                                                                           0.1s
 => => writing image sha256:5e17f3d3200e9dff63af92adaa43c989e2339e225d0a9b2d984e19d9233bc9ce                      0.0s
 => => naming to docker.io/library/my-site:v2

Note how Docker reused existing cache image layers for the initial Dockerfile instructions, only rebuilding the final layer copying our updated html.

This leverages cache to optimize build performance, but doesn‘t give us a fully clean build.

Rebuilding with --no-cache

Now, let‘s rebuild using --no-cache for a full, clean build:

$ docker build --no-cache -t my-site:v3 .  
[+] Building 2m0s (16/16) FINISHED
 => [internal] load build definition from Dockerfile                                                               0.1s
 => => transferring dockerfile: 37B                                                                               0.0s  
 => [internal] load .dockerignore                                                                                 0.0s
 => => transferring context: 35B                                                                                  0.0s
 => [internal] load metadata for docker.io/library/ubuntu:jammy                                                    1.6s
 => [auth] library/ubuntu:pull token for registry-1.docker.io                                                       0.0s
 => [ 1/11] FROM docker.io/library/ubuntu:jammy@sha256:416d97810e5cc1ed2739aaeaf1e2c4c7debd16f58aff157a3d0c5d   0.0s
 => [internal] load build context                                                                                  0.1s
 => => transferring context: 5.49kB                                                                               0.1s
 => CACHED [ 2/11] RUN apt-get update && apt-get install -y   nginx                                                0.0s
 => CACHED [ 3/11] COPY nginx.conf /etc/nginx/                                                                    0.0s
 => CACHED [ 4/11] EXPOSE 80                                                                                      0.0s  
 => CACHED [ 5/11] CMD ["nginx" "-g" "daemon off;"]                                                               0.0s
 => [ 6/11] COPY html /var/www/html                                                                               1.3s 
 => exporting to image                                                                                            0.2s 
 => => exporting layers                                                                                           0.2s
 => => writing image sha256:41262d86610e8331bfbab672bc0310d7bd0aca5258c7f9c6deafa4c603249eb9                      0.0s  
 => => naming to docker.io/library/my-site:v3 

Now on rebuild, Docker did not leverage any cache image layers from prior builds.

It pulled a brand new ubuntu base image, and rebuilt the full Docker image from scratch.

So using --no-cache gave us a fully clean, consistent Docker image build after we updated our source code.

This can be useful in many situations when you need 100% clean Docker builds.

Caching Specific Build Stages

When using multi-stage Docker builds, you can also selectively control layer caching.

For example:

# Build stage
FROM maven AS build 
COPY . /src
RUN mvn package -f /src  

# Package stage
FROM tomcat
COPY --from=build /src/target/app.war /webapps  

To force a clean rebuild of just the build stage, do:

docker build --no-cache=true --target build -t app .

This will recreate the maven builder stage from scratch, while still utilizing cache for the packaging stage.

So with multi-stage builds, you have granular control over layer caching per stage.

Other Cache Configuration Options

In addition to --no-cache, Docker also offers some other cache tuning options:

  • --cache-from – Prefetch images for cache sources
  • --no-cache=false – Only rebuild changed layers, but use cache (default behavior)
  • --pull – Always attempt to pull newer base images
  • --cache-to – Save resulting image for future cache source

For example, to use a specific cached image as the cache source:

docker build --cache-from myimage:cachebase -t mybuild . 

This leverages advanced cached images for more repeatable builds.

So while --no-cache disables all caching, you can also fine-tune cache behavior if needed.

Conclusion

While Docker caching often improves image build speeds, utilizing --no-cache forces clean full rebuilds.

Key reasons to disable Docker cache with --no-cache:

  • Base images updated
  • Dependency changes
  • Consistent/clean builds needed
  • Corporate security requirements

Simply add --no-cache or -no-cache to your docker build and Docker will rebuild the full image from scratch.

This guide covered common use cases, implementation, and examples using --no-cache for clean cached Docker image building.

Disabling caching provides complete control over the integrity and consistency of your Docker images.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *