本文内容来自我参与维护的 《Docker 从入门到实践》 项目。
之前的做法
在 Docker 17.05 版本之前,我们构建 Docker 镜像时,通常会采用两种方式:
全部放入一个 Dockerfile
一种方式是将所有的构建过程编包含在一个 Dockerfile
中,包括项目及其依赖库的编译、测试、打包等流程,这里可能会带来的一些问题:
Dockerfile
特别长,可维护性降低镜像层次多,镜像体积较大,部署时间变长
源代码存在泄露的风险
例如
编写 app.go
文件,该程序输出 Hello World!
1 | package main |
编写 Dockerfile.one
文件
1 | FROM golang:1.9-alpine |
构建镜像
1 | $ docker build -t go/helloworld:1 -f Dockerfile.one . |
分散到多个 Dockerfile
另一种方式,就是我们事先在一个 Dockerfile
将项目及其依赖库编译测试打包好后,再将其拷贝到运行环境中,这种方式需要我们编写两个 Dockerfile
和一些编译脚本才能将其两个阶段自动整合起来,这种方式虽然可以很好地规避第一种方式存在的风险,但明显部署过程较复杂。
例如
编写 Dockerfile.build
文件
1 | FROM golang:1.9-alpine |
编写 Dockerfile.copy
文件
1 | FROM alpine:latest |
新建 build.sh
1 |
|
现在运行脚本即可构建镜像
1 | $ chmod +x build.sh |
对比两种方式生成的镜像大小
1 | $ docker image ls |
使用多阶段构建
为解决以上问题,Docker v17.05 开始支持多阶段构建 (multistage builds
)。使用多阶段构建我们就可以很容易解决前面提到的问题,并且只需要编写一个 Dockerfile
:
例如
编写 Dockerfile
文件
1 | FROM golang:1.9-alpine |
构建镜像
1 | $ docker build -t go/helloworld:3 . |
对比三个镜像大小
1 | $ docker image ls |
很明显使用多阶段构建的镜像体积小,同时也完美解决了上边提到的问题。