With the release of version 17.05, Docker has also made an important update to the image building area, namely multi-stage build (multi-stage build), which is a real help to the long-term partners who have been troubled by the large image.
Multi-phase construction is not supported
Before version 17.05, we used to build Docker images in two ways:
- Writing all the build processes in the same Docker file, including the compilation, testing, packaging of the project and its dependency libraries, may bring some problems:
- Dockerfile is particularly bulky
- Mirror layers are particularly deep
- There is a risk of source leakage
- A slightly elegant way is to package the project and its dependency libraries compilation and testing outside before copying them into the build directory. Although this avoids the risks of the first way, we still need to write two sets of Dockerfile s or some scripts to integrate the two phases automatically.
Here, a simple example of JAVA project mirror construction is given to illustrate the two approaches. The project contains only one App.java class:
public class App { public static void main(String[] args) { System.out.println("Hello, multi-stage build..."); } }
- Take the simplest approach
FROM dojomadness/alpine-jdk8-maven:latest # add pom.xml and source code ADD ./pom.xml pom.xml ADD ./src src/ # package jar and remove source code and temporary class files RUN mvn clean package && cp -f target/msb-1.0.jar msb.jar && rm -rf pom.xml src/ target/ # run jar CMD ["java", "-jar", "msb.jar"]
This is where all the build processes are written in the same Dockerfile, but to minimize the mirror level, we merge multiple execution commands into one RUN At the same time, we need to clean up the source directory files and compiled temporary directory files to prevent source code leakage.
- In a slightly elegant way
Here we need to divide into two stages:
1) Compile and package Docker file.2.1
FROM maven:3.5.0-jdk-8-alpine # add pom.xml and source code ADD ./pom.xml pom.xml ADD ./src src/ # package jar RUN mvn clean package
2) Building mirror Docker file.2.2
From openjdk:8-jre-alpine # copy jar COPY ./msb.jar msb.jar # run jar CMD ["java", "-jar", "msb.jar"]
3) Integrating the two construction phases of build.sh
#!/bin/bash # First stage: complete build environment docker build -t msb:build -f Dockerfile.2.1 . # create temporary container docker create --name extract msb:build # extract jar docker cp extract:/target/msb-1.0.jar ./msb.jar # remove temporary container docker rm -f extract # Second stage: minimal runtime environment docker build --no-cache -t msb:build-2 -f Dockerfile.2.2 . # remove local jar rm -rf ./msb.jar
Here we have written two Dockerfiles and one Shell script to build the final image in two phases, but one predictable problem is that if multiple projects are related and dependent on each other, we need to maintain multiple Dockerfiles, or we need to write more complex build.sh scripts, resulting in high maintenance costs in the later period.
Support multi-stage construction
After the launch of Docker 17.05 multi-phase build, we can easily avoid the problems we encountered before, and only need to maintain a Docker file:
# First stage: complete build environment FROM maven:3.5.0-jdk-8-alpine AS builder # add pom.xml and source code ADD ./pom.xml pom.xml ADD ./src src/ # package jar RUN mvn clean package # Second stage: minimal runtime environment From openjdk:8-jre-alpine # copy jar from the first stage COPY --from=builder target/msb-1.0.jar msb.jar # run jar CMD ["java", "-jar", "msb.jar"]
Are you familiar with the Docker file above, which merges two Docker files in the second way into the same Docker file and automatically completes the process of building. sh for you during the construction process?
For multi-stage build ing, there are two key points:
-
At the preceding stage FROM An additional instruction is added after the instruction. AS Parameters can be named for this build phase, which can be easily referenced in the subsequent build phase. The format is as follows:
FROM image[:tag | @digest] AS stage
-
At a later stage COPY The -- from parameter is added after the instruction to indicate which previous build phase is referenced in the following format:
COPY --from=stage ...
Similarly, multi-stage construction can also easily build the desired container image through a Dockerfile for multiple interdependent projects without worrying about the risks of too large a mirror and source code leakage.