Multi-stage builds

The principles we've discussed so far are all about how to make builds fast and how to make the final image smaller while keeping the maintainability of the Dockerfile. Instead of striving to optimize a Dockerfile, writing one to build the artifacts we need and then moving them to another image with runtime dependencies only makes it much easier to sort the different logic out. In the building stage, we can forget about minimizing the layers so that the build cache can be reused efficiently; when it comes to the release image, we can follow the previously recommended techniques to make our image clean and small. Before Docker CE 17.05, we had to write two Dockerfiles to implement this build pattern. Now, Docker has built-in support to define different stages in a single Dockerfile.

Take a golang build as an example: this requires lots of dependencies and a compiler, but the artifact can merely be a single binary. Let's look at the following example:

FROM golang:1.11 AS builder
ARG GOOS=linux
ARG GOARCH=amd64
ARG CGO_ENABLED=0
WORKDIR /go/src/app
COPY main.go .
RUN go get .

RUN go build -a -tags netgo -ldflags '-w -s -extldflags "-static"'

FROM scratch
COPY --from=builder /go/src/app/app .
ENTRYPOINT ["/app"]
CMD ["--help"]

The delimiter for the different stages is the FROM directive, and we can name the stages with the AS keyword after the image name. At the builder stage, Docker starts a golang base image, and then builds the target binary as usual. Afterwards, during the second build, it copies the binary from the builder container with --from=[stage name|image name] to a scratch imageā€”a reserved name for an entirely empty image. As there's only one binary file and one layer in the resultant image, its size is dramatically smaller than the builder one. 

The number of stages isn't limited to two, and the source of the COPY directive can either be a previously defined stage or a built image. The ARG directive works against FROM, which is also the only exception that can be written before a FROM directive, as they belong to different stages. In order to use it, the ARG directive to be consumed in FROM should be declared before FROM, as shown here:

ARG TAGS=latest
FROM ubuntu:$TAGS
...
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset