This is the fifth day of my participation in the August Wen Challenge.More challenges in August

Writing in the front

Multi-phase builds are introduced in Docker Engine 17.05 to reduce build complexity and make it easier to shrink the image size. How to write a Dockerfile that implements a multistage build

About dockerfile basic preparation can refer to the previous docker container dockerfile detailed explanation


No multi-phase builds

We know that each instruction added to a Dockerfile creates a new layer in the image, and an efficient Dockerfile should clear all unwanted resources before proceeding to the next layer.

When not using a multi-phase build, we typically create two Dockerfiles, one for developing and compiling the application, and one for building a lean production image. In this way, the size of the production mirror can be greatly reduced.

Let’s take a look at it with a Go app. I’ll start by creating a Dockerfile, and the main purpose of building this image is to compile our application.

FROM golang:1.16 WORKDIR /go/ SRC COPY app.goCopy the code

Build the mirror

[root@localhost dockerfiles]# docker build -t builder_app:v1. Sending build context to docker daemon 3.072kB Step 1/4: FROM golang:1.16 --> 019C7b2e3cb8 Step 2/4: WORKDIR /go/ SRC --> Using cache --> 15362720e897 Step 3/4: COPY app.go ./ ---> Using cache ---> 8f14ac97a68a Step 4/4 : RUN go build -o myapp app.go ---> Running in 4368cc4617a7 Removing intermediate container 4368cc4617a7 ---> 631f67587803  Successfully built 631f67587803 Successfully tagged builder_app:v1Copy the code

This image contains our compiled application myApp. Now we can create a container to copy MyApp to the host for later use.

# docker create --name builder builder_app:v1
fafc1cf7ffa42e06d19430b807d24eafe0bf731fc45ff0ecf31ada5a6075f1d5
# docker cp builder:/go/src/myapp ./
Copy the code

Now that we have the application, the next step is to build a production image

FROM scratch
WORKDIR /server
COPY myapp ./
CMD ["./myapp"]
Copy the code

Since we don’t need other dependent environments at this point, we used Scratch as an empty image to not only reduce the container size, but also improve security.

Build the mirror

#docker build  --no-cache -t server_app:v1 .
Copy the code

Let’s look at the size of two mirrors for a build

# docker images 
REPOSITORY            TAG       IMAGE ID       CREATED          SIZE
server_app            v1        6ebc0833cad0   6 minutes ago    1.94MB
builder_app           v1        801f0b615004   23 minutes ago   921MB
Copy the code

Obviously we could have built a production image without using a multi-stage build, but we needed to maintain two Dockerfiles, leaving the app locally and incurs more storage overhead. These problems are better solved when using a multi-phase build.


Use a multi-phase build

Use multiple FROM directives in a Dockerfile, each FROM can use a different base image, and each directive will start a new phase of build. In a multi-phase build, we can copy resources from one phase to another, leaving only what we need in the final image.

We merge the two dockerfiles from the above instance as follows:

/ RUN go build app. Go -o myapp # phase 2 FROM scratch WORKDIR /server COPY  --from=0 /go/src/myapp ./ CMD ["./myapp"]Copy the code

Build the mirror

# docker build --no-cache  -t server_app:v2 .
Copy the code

View the built image

# docker images
REPOSITORY            TAG       IMAGE ID       CREATED              SIZE
server_app            v2        20225cb1ea6b   12 seconds ago       1.94MB
Copy the code

This allows us to build the same tiny target image in a simpler way without creating additional images. COPY –from=0 /go/ SRC /myapp./ Specify the source of our resource by –from=0, where 0 is the first stage.

Command construction phase

By default, the build phase has no name and can be referenced by integers 0 to N, where the first from starts at 0. We can also NAME the build phase by adding AS

in the FROM directive and then reference it by

in the COPY directive. Dockerfile (dockerfile);

Builder FROM Golang :1.16 as Builder WORKDIR /go/ SRC COPY app.go./ RUN go build app.go -o myapp # Stage 2 FROM scratch COPY --from=builder /go/ SRC /myapp./ CMD [".Copy the code
Build only one phase

When building an image, you don’t necessarily need to build the entire Dockerfile, we can specify a target phase to build with the –target parameter, such as our development phase we only build the Builder phase for testing.

#docker build --target builder -t builder_app:v2 .
Copy the code
Using external images

When using a multi-stage build, we are limited to copying stages that were previously created in the Dockerfile. You can also use the COPY –from directive to COPY from individual images, such as local image names, labels or tag ids available locally or on the Dockerhub. The Docker client will pull the required image locally if necessary.

COPY --from  httpd:latest /usr/local/apache2/conf/httpd.conf ./httpd.conf
Copy the code
Create a new phase from the previous phase

We can start a new phase by referring to the previous phase with the FROM directive

Builder FROM Golang :1.16 as Builder WORKDIR /go/ SRC COPY app.go./ RUN go build app.go -o myapp # Stage 2 FROM Builder  as builder_ex ADD dest.tar ./ ...Copy the code

Through the above we have an overall understanding of dockerfile multi-stage build.


NEXT

  • Dockerfile and Docker container security practices

I hope the essay is helpful to you. Please correct me if there is any mistake in the content.

You are free to reprint, modify, publish this article, without my consent. Iqsing.github. IO

\