Docker镜像多阶段构建


前言

  在我们日常构建镜像中,镜像构建会依赖上一次镜像构建生产的内容。比如在构建一个JAVA语言镜像,需要先在一个Dockerfile中编译生成JAR包,然后再另外一个Dockerfile把编译好的JAR放到镜像中。这样就相当于增大了CI/CD的复杂度。
  Docker多阶段构建是17.05以后引入的新特性,旨在解决编译和构建复杂的问题。减小镜像大小。因此要使用多阶段构建特性必须使用高于或等于17.05的Docker。


一、多阶段构建出现之前

  构建镜像最具挑战性的一点是使镜像大小尽可能的小。Dockerfile中的每条指令都为图像添加了一个图层,为了编写高效的Dockerfile,传统上需要使用shell技巧和其他逻辑来保持层尽可能小,并确保每个层都具有前一层所需的工件而不是其他任何东西。
  在实际工作中,往往有一个Dockerfile用于开发(包含构建应用程序所需的所有内容),还有一个Dockerfile用于生产环境的精简版,它只包含应用程序以及运行它所需的内容。这被称为“建造者模式”。但维护两个Dockerfiles并不是理想的状态。

这是一个Dockerfile.build和Dockerfile的例子,它遵循上面的模式:

Dockerfile.build:
	FROM golang:1.7.3
	WORKDIR /go/src/github.com/alexellis/href-counter/
	COPY app.go .
	RUN go get -d -v golang.org/x/net/html \
	&& CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .

Dockerfile:
	FROM alpine:latest  
	RUN apk --no-cache add ca-certificates
	WORKDIR /root/
	COPY app .
	CMD ["./app"]

build.sh:
	#!/bin/sh
	echo Building alexellis2/href-counter:build
	docker build --build-arg https_proxy=$https_proxy --build-arg http_proxy=$http_proxy \  
	-t alexellis2/href-counter:build . -f Dockerfile.build
	docker container create --name extract alexellis2/href-counter:build  
	docker container cp extract:/go/src/github.com/alexellis/href-counter/app ./app  
	docker container rm -f extract
	echo Building alexellis2/href-counter:latest
	docker build --no-cache -t alexellis2/href-counter:latest .
	rm ./app

当运行build.sh脚本时,它需要构建第一个image,从中创建容器以复制工件,然后构建第二个image。

二、多阶段构建

1. 简介

  对于多阶段构建,可以在Dockerfile中使用多个FROM语句。每个FROM指令可以使用不同的基础,并且每个指令都开始一个新的构建。您可以选择性地将工件从一个阶段复制到另一个阶段,从而在最终image中只留下您想要的内容。

2.多阶段构建使用

示例

Dockerfile:
	FROM golang:1.7.3
	WORKDIR /go/src/github.com/alexellis/href-counter/
	RUN go get -d -v golang.org/x/net/html  
	COPY app.go .
	RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .
	FROM alpine:latest  
	RUN apk --no-cache add ca-certificates
	WORKDIR /root/
	COPY --from=0 /go/src/github.com/alexellis/href-counter/app .
	CMD ["./app"]  

  所以只需要单个Dockerfile即可实现上述相关内容。运行
docker build构建镜像
   $ docker build -t app:latest .

  相对于两次构建,降低相关复杂性。也无需创建中间image,也不需要将任何artifacts提取到本地系统。是通过第二个FROM指令以alpine:latest image为基础开始一个新的构建阶段。COPY –from = 0行仅将前一阶段的构建文件复制到此新阶段。Go SDK和任何中间层都被遗忘,而不是保存在最终image中。

三、多阶段构建命名

  默认情况下,阶段未命名,我们可以通过整数来引用它们,从第0个FROM指令开始。同时也可以通过向FROM指令添加as name来命名相关阶段。
示例

FROM golang:1.7.3 as builder
WORKDIR /go/src/github.com/alexellis/href-counter/
RUN go get -d -v golang.org/x/net/html  
COPY app.go    .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .
FROM alpine:latest  
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /go/src/github.com/alexellis/href-counter/app .
CMD ["./app"] 

四、其他

停在某个构建阶段
  构建镜像时,不一定需要构建整个Dockerfile每个阶段,可以指定目标构建阶段。以上述Dockerfile为例,在builder的阶段停止:
  $ docker build --target builder -t alexellis2/href-counter:latest .

适用场景
  比如调试特定的构建阶段,在debug阶段,启用所有调试或工具,而在production阶段尽量精简,在testing阶段,通过测试数据进行测试应用程序,在production阶段则使用生产数据。

使用外部镜像作为stage
  使用多阶段构建时,不仅可以从Dockerfile中创建的镜像中进行复制。还可以使用COPY –from指令从单独的image中复制,使用本地image名称,本地或Docker注册表中可用的标记或标记ID。
如有必要,Docker会提取image并从那里开始复制。
语法:
  COPY --from=nginx:latest /etc/nginx/nginx.conf /nginx.conf

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值