从docker17.05版本开始,dockerfile中允许使用多个FROM指令(multistage)。这是docker17.05版本的release note:https://docs.docker.com/engine/release-notes/17.05/

这个特性有什么实际的应用场景?最近需要做一个docker镜像,就用到了该特性。简单来说就是可以使编译环境和发布环境分离

使用多FROM指令可以完成多阶段编译。每一条 FROM 指令都是一个构建阶段,多条 FROM 就是多阶段构建,虽然最后生成的镜像只能是最后一个阶段的结果,但是,能够将前置阶段中产生的文件拷贝到后边的阶段中,这就是多阶段构建的最大意义。

比如下面这种场景:

我们要构建一个c++应用程序的镜像,这个c++程序依赖了很多第三方库,那么我们的构建过程大概如下:

# c++语言环境基础镜像
FROM centos:7.0.3

#安装编译工具,gcc g++ gdb cmake ==

#安装第三方库

# 将源码拷贝到镜像中
COPY project /build/

# 指定工作目录
WORKDIR /build

# 使用make编译代码,生成可执行程序


# 指定容器运行时入口程序 server
ENTRYPOINT ["/build/server"]

这样会导致我们编译出来的镜像非常庞大,而我们最终要用的只是一个可执行程序以及它运行时依赖的动态库,不需要编译工具以及编译时依赖的第三方库的源代码。有了多FROM指令后,我们就可以这样实现这个过程:在基础镜像上安装编译工具->下载第三方库源代码->编译安装第三方库->编译自己的模块代码->将编译好的可执行文件拷贝到新的镜像中->将运行时依赖的动态库拷贝到新镜像中->修改新镜像中的环境变量,使之指向运行时依赖库的位置。dockerfile修改如下:

# c++语言环境基础镜像
FROM centos:7.0.3 AS build_base

#安装编译工具,gcc g++ gdb cmake ==

#安装第三方库

# 将源码拷贝到镜像中
COPY project /build/

# 指定工作目录
WORKDIR /build

# 编译镜像时,运行 make生成可执行程序


# 指定容器运行时入口程序 server
ENTRYPOINT ["/build/server"]

#这里重新启动一个镜像,将编译好的可执行文件和运行依赖库拷贝过来就可以了
FROM centos:7.0.3
COPY --from build_base ***.so .
COPY --from build_base /build/server .
#修改环境变量,使之指向动态库的目录
ENV LD_LIBRARY_PATH=./

我们最终用到的镜像就是最后一个FROM后生成的镜像,前边的FROM只是起到了一个辅助产生编译环境的作用。这也是多FROM特性比较常用的一个场景。

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐