# 第一阶段——编译(炒)
FROM openjdk:8u171-jdk-alpine3.8 as builder # 自带编译工具ADD . /app
WORKDIR /app
RUN ... 省略编译和清理工作...
# 现在,JAR 已经出炉。JDK 不再需要,所以不能留在镜像中。
# 所以我们开启第二阶段——运行(上桌),并扔掉第一阶段的所有文件(包括编译工具)
FROM openjdk:8u181-jre-alpine3.8 as environment # 只带运行时
# 目前,编译工具等上一阶段的东西已经被我们抛下。目前的镜像中只有运行时,我们需要把上一阶段(炒)的结果拿来,其它不要。
COPY --from=0 /final.jar .
# 好了,现在镜像只有必要的运行时和 JAR 了。
ENTRYPOINT java -jar /final.jar
如上就是多阶段构建的介绍。
使用多阶段构建
多阶段构建的核心命令是 FROM。FORM 对于身经百战的你来说已经不用多讲了。在多阶段构建中,每次 FROM 都会开启一个新的 Stage(阶段),可以看作一个新的 Image(不够准确、来源请求),与其它阶段隔离(甚至包括环境变量)。只有最后的 FROM 才会被纳入 Image 中。
我们来做一个最 simple 的多阶段构建例子:
# Stage 1
FROM alpine:3.8
WORKDIR /demo
RUN echo "Hello, stage 1" > /demo/hi-1.txt# Stage 2
FROM alpine:3.8
WORKDIR /demo
RUN echo "Hello, stage 2" > /demo/hi-2.txt
可以自己构建一下这个 Dockerfile,然后 docker save <tag> > docker.tar 看看其中的内容。不出意外应该只有 /demo/hi-2.txt 和 Alpine。
在这个 Dockerfile 中,我们创建了两个阶段。第一个阶段创建 hi-1.txt,第二个阶段创建 hi-2.txt,且第二个阶段会被加入最终 Image,其它不会。
复制文件——阶段间的桥梁
如果阶段间完全隔离,那么多阶段就没有意义——上一个阶段的结果会被完全抛弃,并进入全新的下一阶段。
我们可以通过 COPY 命令来获取其它阶段的文件。在多阶段中使用 COPY 和普通应用完全一致,仅需要添加 –form ` 即可。那么,我们修正上一个例子,使最终镜像包含两个阶段的产物:
# Stage 1
FROM alpine:3.8
WORKDIR /demo
RUN echo "Hello, stage 1" > /demo/hi-1.txt# Stage 2
FROM alpine:3.8
WORKDIR /demo
COPY --from=0 /demo/hi-1.txt /demo
RUN echo "Hello, stage 2" > /demo/hi-2.txt
重新构建并保存(Save),你会发现多了一层 Layer,其中包含 hi-1.txt。
阶段命名——快速识别
对于只有七秒记忆的我们来说,每次使用 stage index 并不是一件很妙的事情。这时候,可以通过阶段命名的方式给它们赋予名字,以方便识别。










