Use Multi-Stage Builds to Improve Continuous Delivery Pipeline
Learn how to use Docker multi-stage builds
Table of Contents
A basic rule for building a container image is “the smaller is better”.
But it’s not an easy job for the compiled language (e.g. go, java) due to large build environment and dependencies. In the post “Building Minimal Docker Image for Go Applications”, we need to produce a go binary first and put it into scratch
image. And it’s quite complicated and heavy for developers to create such continuous delivery pipeline.
To solve this problem, Docker 17.05+ releases a new feature called Multi-stage builds
. With this feature we can combine multiple dockerfiles into one and let base image to copy artifacts and outputs from the intermediate image. In this way, we can keep pipeline easy to read and maintain.
Dockerfile example of multi-stage builds
FROM alpine AS base
RUN apk add --no-cache curl wget
FROM golang:1.9.2 AS go-builder
WORKDIR /go
COPY *.go /go/
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o main .
FROM base
COPY --from=go-builder /go/main /main
CMD ["/main"]
Here is a diagram to explain what happened during the builds.
FROM alpine AS base
RUN apk add --no-cache curl wget
- Name stage 0 as
base
by addingas <NAME>
. - Use
alpine
as parent image to create an intermediate image, and install required packages (curl, wget).
FROM golang:1.9.2 AS go-builder
WORKDIR /go
COPY *.go /go/
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o main .
- Name stage 1 as
go-builder
. - Compile packages and dependencies.
FROM base
COPY --from=go-builder /go/main /main
CMD ["/main"]
- Use intermediate image as parent image in stage 0 (stage build).
- Use
COPY
command copy artifacts generated in stage 1 (stage go-builder).COPY --from=1
COPY --from=<intermediate_image_name>
FROM <base_image> as <stage_name>
- Always name stage for readability.
- No need to modify existing
COPY
commands if more stages add in future.
COPY --from=<stage_name>
- Use stage name instead of number of stage for readability and maintenance.
Build image
$ docker build -t multi_stage_minimal_go_docker_img .
You should see log outputs like following
Sending build context to Docker daemon 3.072kB
Step 1/9 : FROM alpine AS base
---> 3fd9065eaf02
Step 2/9 : RUN apk add --no-cache curl wget
---> Running in c1c75ffbfef4
fetch http://dl-cdn.alpinelinux.org/alpine/v3.7/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.7/community/x86_64/APKINDEX.tar.gz
(1/5) Installing ca-certificates (20171114-r0)
(2/5) Installing libssh2 (1.8.0-r2)
(3/5) Installing libcurl (7.59.0-r0)
(4/5) Installing curl (7.59.0-r0)
(5/5) Installing wget (1.19.2-r1)
Executing busybox-1.27.2-r7.trigger
Executing ca-certificates-20171114-r0.trigger
OK: 6 MiB in 16 packages
Removing intermediate container c1c75ffbfef4
---> 6061a54c31c9
Step 3/9 : FROM golang:1.9.2 AS go-builder
---> 138bd936fa29
Step 4/9 : WORKDIR /go
Removing intermediate container e7a1f8df0451
---> 8f440d314727
Step 5/9 : COPY *.go /go/
---> 95f1803ce6b3
Step 6/9 : RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o main .
---> Running in 72cba3033d5c
Removing intermediate container 72cba3033d5c
---> 9a8875b6eec1
Step 7/9 : FROM base
---> 6061a54c31c9
Step 8/9 : COPY --from=go-builder /go/main /main
---> 99e564fa87b8
Step 9/9 : CMD ["/main"]
---> Running in 7751604e5d0c
Removing intermediate container 7751604e5d0c
---> 50aa7d144269
Successfully built 50aa7d144269
Successfully tagged multi_stage_minimal_go_docker_img:latest
That’s it! Now, we can produce a small docker image without too much effort!
- https://blog.alexellis.io/mutli-stage-docker-builds/
- https://docs.docker.com/develop/develop-images/multistage-build/
See Also
- Adopting Container and Kubernetes in Production
- Fission and Istio Integration
- Kubernetes - Two Steps Installation
- Building Minimal Docker Image for Go Applications
- Rolling Updates with Kubernetes Deployments
To reproduce, republish or re-use the content,
please attach with link: https://tachingchen.com/
Twitter
Google+
Facebook
Reddit
LinkedIn
StumbleUpon
Pinterest
Email