• Home
  • LLMs
  • Python
  • Docker
  • Kubernetes
  • Java
  • Maven
  • All
  • About
Docker | Multi-Stage Builds
  1. Multi-Stage Builds

  1. Multi-stage builds
    Multi-stage builds feature allow you to add multiple FROM instructions in the Dockerfile. The FROM instructions are basicaly the same as the regular single FROM instructions that we have used previously.

    Each FROM instruction define a build stage that has its base image and a set of instructions to build images layers. A FROM instruction should have a name which can be used by other FROM instructions as a reference. The FROM instruction that references another one, will be able to copy artifacts created within that staging build.

    A staging build can be considered as a temporary build that we can use in the next staging builds to copy only the artifacts that we need and discards everything else. The goal is to have an optimized final stage (in term of disk space) that in theory will be the one that we will use for the image we want to create.

    Let's use this Dokerfile (not a very useful one but it's simple enough to demonstrate the multi-stage builds feature):
    $ vi Dockerfile
    #stage 0
    FROM alpine:latest AS stage0
    
    RUN apk add --no-cache curl tar
    
    RUN curl -fSL -o /tmp/apache-zookeeper-3.6.1-bin.tar.gz https://archive.apache.org/dist/zookeeper/zookeeper-3.6.1/apache-zookeeper-3.6.1-bin.tar.gz
    
    RUN tar -xzf /tmp/apache-zookeeper-3.6.1-bin.tar.gz -C /tmp/
    
    #final stage
    FROM alpine:latest
    
    COPY --from=stage0 /tmp/apache-zookeeper-3.6.1-bin /opt/
    Let's build the Dockerfile:
    $ DOCKER_BUILDKIT=0 docker build -t zookeeper-multi-stage:3.6.1 .
    Sending build context to Docker daemon  2.048kB
    
    Step 1/6 : FROM alpine:latest AS stage0
    latest: Pulling from library/alpine
    df20fa9351a1: Pull complete
    Digest: sha256:185518070891758909c9f839cf4ca393ee977ac378609f700f60a771a2dfe321
    Status: Downloaded newer image for alpine:latest
     ---> a24bb4013296
    
    Step 2/6 : RUN apk add --no-cache curl tar
     ---> Running in 97a752789c85
    fetch http://dl-cdn.alpinelinux.org/alpine/v3.12/main/x86_64/APKINDEX.tar.gz
    fetch http://dl-cdn.alpinelinux.org/alpine/v3.12/community/x86_64/APKINDEX.tar.gz
    (1/6) Installing ca-certificates (20191127-r4)
    (2/6) Installing nghttp2-libs (1.41.0-r0)
    (3/6) Installing libcurl (7.69.1-r0)
    (4/6) Installing curl (7.69.1-r0)
    (5/6) Installing libacl (2.2.53-r0)
    (6/6) Installing tar (1.32-r1)
    Executing busybox-1.31.1-r16.trigger
    Executing ca-certificates-20191127-r4.trigger
    OK: 8 MiB in 20 packages
    Removing intermediate container 97a752789c85
     ---> 5d10ef835956
    
    Step 3/6 : RUN curl -fSL -o /tmp/apache-zookeeper-3.6.1-bin.tar.gz https://archive.apache.org/dist/zookeeper/zookeeper-3.6.1/apache-zookeeper-3.6.1-bin.tar.gz
     ---> Running in 636240e89a86
      % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                     Dload  Upload   Total   Spent    Left  Speed
    100 11.8M  100 11.8M    0     0  7515k      0  0:00:01  0:00:01 --:--:-- 7510k
    Removing intermediate container 636240e89a86
     ---> 5341fb2f8fe0
    
    Step 4/6 : RUN tar -xzf /tmp/apache-zookeeper-3.6.1-bin.tar.gz -C /tmp/
     ---> Running in 27a216de9588
    Removing intermediate container 27a216de9588
     ---> 5425d0ccdc19
    
    Step 5/6 : FROM alpine:latest
     ---> a24bb4013296
    
    Step 6/6 : COPY --from=stage0 /tmp/apache-zookeeper-3.6.1-bin /opt/
     ---> c54f88c3c573
    
    Successfully built c54f88c3c573
    Successfully tagged zookeeper-multi-stage:3.6.1
    Let's have a look at the image history:
    $ docker image history zookeeper-multi-stage:3.6.1 --no-trunc
    IMAGE                                                                     CREATED              CREATED BY                                                                                              SIZE                COMMENT
    sha256:c54f88c3c573930fb26ea047d5953a842a702bb39289618f3f3cfc013edf337d   About a minute ago   /bin/sh -c #(nop) COPY dir:420ba2bd6abb5a0706062b95eb13c8e9c1cb7a7d9c19f1e88eab87c425d65877 in /opt/    35.3MB
    sha256:a24bb4013296f61e89ba57005a7b3e52274d8edd3ae2077d04395f806b63d83e   2 months ago         /bin/sh -c #(nop)  CMD ["/bin/sh"]                                                                      0B
    <missing>                                                                 2 months ago         /bin/sh -c #(nop) ADD file:c92c248239f8c7b9b3c067650954815f391b7bcb09023f984972c082ace2a8d0 in /        5.57MB
    As you can see, the image does contain only the layers of the base image (alpine) and the layer of the COPY instruction.

    Notes:
    • Assigning a name to a stage build is recommended but not mandatory. Instead of using the name of the stage build you can reference it by its number. The first FROM instruction in the Dockerfile has the number 0 and the following will be numbered 1,2,3, and so on. To reference the first build stage, you do: COPY --from=0 ...
      #stage 0
      FROM alpine:latest
      
      RUN apk add --no-cache curl tar
      
      RUN curl -fSL -o /tmp/apache-zookeeper-3.6.1-bin.tar.gz https://archive.apache.org/dist/zookeeper/zookeeper-3.6.1/apache-zookeeper-3.6.1-bin.tar.gz
      
      RUN tar -xzf /tmp/apache-zookeeper-3.6.1-bin.tar.gz -C /tmp/
      
      #final stage
      FROM alpine:latest
      
      COPY --from=0 /tmp/apache-zookeeper-3.6.1-bin /opt/
    • It's also possible to copy artifacts from external images (kind of using the image as a stage):
      COPY --from=zookeeper:3.6.1 /apache-zookeeper-3.6.1-bin /opt/zookeper
    • You can also use a stage build as a base image for the FROM instruction (FROM stage0 AS stage1):
      #stage 0
      FROM alpine:latest AS stage0
      
      RUN apk add --no-cache curl tar
      
      #stage 1
      FROM stage0 AS stage1
      
      RUN curl -fSL -o /tmp/apache-zookeeper-3.6.1-bin.tar.gz https://archive.apache.org/dist/zookeeper/zookeeper-3.6.1/apache-zookeeper-3.6.1-bin.tar.gz
      
      RUN tar -xzf /tmp/apache-zookeeper-3.6.1-bin.tar.gz -C /tmp/
      
      #final stage
      FROM alpine:latest
      
      COPY --from=stage1 /tmp/apache-zookeeper-3.6.1-bin /opt/
© 2025  mtitek