Skip to content

Caching and multistage

Goal

This project is about the cache and multistage builds. You will:

  • use cache-busting to your advantage
  • create and build a multistage build

Tools

  • Try to complete the tasks below with the help of the slides and the cheatsheet.
  • If you have any problems, you will find a fold-out block for each task describing the solution.

Preparation

Make sure that you are still in the folder my-first-image from the previous hands-on.

Task 1 - Layers and caching

1.1: Building with cache

  • Build the image again and observe the output.
  • The cache is used for all layers. Nothing is rebuilt.
Solution (click on the arrow if you get stuck)
  • Execute again
    docker build -t demo01 .
    
  • The output contains CACHED for each layer, e.g:
     => CACHED [5/7] COPY requirements.txt .
    

1.2: Cache-busting in app.py

  • Change the string "Web App with Python Flask!" in app.py.
  • Build the image again.
  • Look at the output. The cache could no longer be used in every step.
Solution (click on the arrow if you get stuck)
  • Change the return value in line 7 in app.py to:
        return 'Hello World from Docker demo'
    
  • Execute docker build -t demo01 . again.
  • The output now no longer contains CACHED in step 7, e.g:
     => [7/7] COPY app.py .
    
  • The layer had to be rebuilt.

1.3: Cache-busting through new system dependencies

  • In addition to the existing system dependencies python3 and python3-pip, add another package nano.
  • Build the image again.
  • The build will now take longer again, as the system dependencies have to be reinstalled and the cache could no longer be used.
Solution (click on the arrow if you get stuck)
  • Change the Dockerfile to:
        [...]
        RUN apt-get update && apt-get install -y \
            python3 \
            python3-pip \
            nano \
        && rm -rf /var/lib/apt/lists/*
        [...]
    
  • Run again
    docker build -t demo01 .
    
  • The layers had to be built again.

Task 2 - Multistage build

2.1: Create requirements.dev.txt

Create a file requirements.dev.txt in the folder my-first-image with the following content:

pylint
pytest

2.2: Extend Dockerfile to multistage build

Based on the previous, minimal image, we now want to install further install further development dependencies. These could be used in a CI/CD pipeline to unit/integration tests and code linting. However, the dependencies should not be included in the previous, minimal image.

  • Give the previous stage the name runtime.
Solution (click on the arrow if you get stuck)
  • Change the Dockerfile to:
        FROM ubuntu:20.04 as runtime
    
        RUN apt-get update && apt-get install -y \
        [...]
    
  • Create a second stage dev_environment which, based on the first stage, adds further dependencies from the requirement.dev.txt. Please note here, that the user must first be set to root and then to app-runner-user again, as only the root user has the rights for the installations.
Solution (click on the arrow if you get stuck)
  • Change the Dockerfile to:
        [...]
        CMD ["python3", "app.py"]
    
        ## Second stage
        FROM runtime as dev_environment
    
        USER root
        COPY requirements.dev.txt .
        RUN python3 -m pip install -r requirements.dev.txt
    
        USER app-runner-user
    

2.3: Building a multistage build

Now build both stages.

Solution (click on the arrow if you get stuck)
  • If you want to build all stages, you can do this as before with the following command:
    docker build -t demo01_dev .
    

Now build only the first stage.

Solution (click on the arrow if you get stuck)
  • Build the first stage with the name runtime, as follows:
    docker build -t demo01 --target runtime .
    

You have now successfully worked with the cache and multistage builds. By the inclusion of the cache in the creation process of a Dockerfile, the build time can be minimized considerably. Multistage builds are ideal to minimize the image size.