header source
my icon
esplo.net
ぷるぷるした直方体
Cover Image for Docker Multistage Build Use Cases

Docker Multistage Build Use Cases

about8mins to read

The Multistage Build feature has made it possible to write extremely concise Dockerfiles.
I was so impressed that I decided to summarize the delightful points for each use case.

Note that it's been a while since I wrote this memo, so this article has become quite outdated. The Multistage Build feature has been available since the 2017/05 release, so it's been almost a year...….
Additionally, there's an article about Multistage Build on the official GCP blog, which includes measurements and is a very interesting read. Please refer to it beforehand, as it explains the first use case in detail.

https://cloudplatform.googleblog.com/2018/04/Kubernetes-best-practices-how-and-why-to-build-small-container-images.html

Use Case 1: Reducing Image Size

This is an indispensable merit when it comes to Multistage Build. By copying the build results (and necessary libraries), you can exclude programs and unnecessary layers required only for building from the image.

This benefit is common to many containers, but it's particularly powerful for Go language programs. This is because Go programs can run with just a single binary copy, making it possible to create extremely lightweight images.
You can now create images of several MB in size, which was previously impossible.

before

FROM alpine:latest as builder
...
// build as command

CMD command

Several hundred MB〜

after

FROM ... as builder
...
// build as command

FROM ...
COPY --from=build command command
CMD command

Several MB〜

Use Case 2: Excluding Programs Used Only in Development Environments

There are programs that are valuable in development environments, such as hot reload tools and debuggers, but are not needed in release environments.
Without Multistage Build, you would need to prepare two Dockerfiles (Dockerfile.dev and Dockerfile.prod, etc.). Since the build preparation is the same for both files, you would need to modify both, which would decrease maintainability.

By using Multistage Build, you can exclude programs used only in development environments from the image with a single Dockerfile. The modifications for using docker-compose are also minimal.

Personally, I think this is the most convenient way to use Multistage Build.

before

Dockerfile.dev

FROM ...
// build preparation
// build
// hot reload tool installation
CMD hot-reload command

Dockerfile.prod

FROM ...
// build preparation
// build
CMD command

after

FROM ... as builder
// build preparation
// build
// hot reload tool installation
CMD hot-reload command

FROM ...
COPY --from=build command command
CMD command

Use Case 3: Refactoring

This is a byproduct of the above two use cases, but it makes the dependencies between each stage clear.
For example, consider building two programs and using their results to run a program (such as building plugins or creating local certificates). Previously, to reduce image size, you would build everything in a single layer of the Dockerfile and finally execute it.
With Multistage Build, you can separate the dependencies into each stage, making the Dockerfile more understandable.

before

FROM ...
RUN apk pre-cmd1 pre-cmd2 cmd3 ... && \
    build cmd1 ... && \
    cd ... && \
    build cmd2 ... && \
    ...

CMD cmd1 cmd2

after

FROM ... as cmd1
RUN apk pre-cmd1 ... && \
    build cmd1 ...

FROM ... as cmd2
RUN apk pre-cmd2 ... && \
    build cmd2 ...

FROM ...
COPY --from=build cmd1 cmd1
COPY --from=build cmd2 cmd2

CMD cmd1 cmd2

Conclusion

Multistage Build is a very convenient feature that can simplify complex Dockerfiles. Let's aim to create lightweight and easy-to-understand Dockerfiles by effectively utilizing this feature.

Share