Multi-stage builds are a new feature requiring Docker 17.05 or higher on the daemon and client. It's useful in building complex/multi step image while keeping them easy to read and maintain.
Keeping the image size down is one of the challenging task while building image. Each instruction in Dockerfile adds a layer to the image. Also, you need to remember to clean up any dependency/artifactory you don't need later. Earlier you might have used shell scripts to keep layers light as much as possible. Using shell scripts, tricks to write a really efficient Dockerfile is a painful task.
In simple terms: you can use end result (for ex: binary/executable file) of one stage into another stage without worrying about dependencies used to build that binary/executable file.
With Multi-stage builds, you can have multiple FROM
statement in a single Dockerfile. Each FROM
statement contributes to one stage.
First stage starts from number 0
.
FROM mhart/alpine-node:10 #stage 0
....
...
FROM alpine:3.7 #stage 1
Here order of stage matters as the first stage will always be 0
. Another way is to give name to the stage
by using AS
.
In that case you don't have to worry about order.
FROM mhart/alpine-node:10 AS nodebuilder
....
...
FROM alpine:3.7 AS builder
Platform | Number of Instance | Reading Time |
---|---|---|
Play with Docker | 1 | 5 min |
For demonstration, Let us consider a nodejs project and build a binary out of it. When you execute this binary, it will call a NASA api which returns some interesting facts about today's date.
Currently we have two images which I pulled from dockerhub:
alpine (~4Mb)
- Lightest version of linux osalpine-node (~70Mb)
- alpine + Node/Npm and other dependency.
-
Dockerfile
:- On stage 0 (alias:
builder
), we have aalpine-node
OS which hasnode
andnpm
built in it. Its size is~70Mb
. This stage will create binary (named asnasa
: Line 6) in the currentWORKDIR
i.eapp/
. - On stage 1, we have
alpine
OS. After that, we install some necessary dependencies. InLine 14
, we copiednasa
binary from previous stage (builder
) to current stage. So, we just copied binary and leaving all heavyalpine-node
OS and other dependencies likenpm
(node package manager) etc as binary already have required dependecies (like nodejs) built in it.
- On stage 0 (alias:
-
app/
: It's just a simple node application. It does ahttps
call and fetches data using nasa api. It hasindex.js
andpackage.json
. I have usedpkg
to build the node binary.
multistage:1.0.0 (56b102754f6d
) is the final required image which we built. Its size is ~45Mb
. Almost 1/4th of the intermediate image(13bac50ebc1a
) built on stage 0. And almost half of alpine-node
image.
So, this was a simple example to showcase multi-stage builds feature. For images having multi step (like 10-15 FROM statement), you will find this feature very useful.
When using multi-stage builds, you are not limited to copying from stages you created earlier in your Dockerfile. You can use the COPY --from
instruction to copy from a separate image, either using the local image name, a tag available locally or on a Docker registry, or a tag ID. The Docker client pulls the image if necessary and copies the artifact from there. The syntax is:
COPY --from=sampleapp:latest home/user/app/config.json app/config.json