美文网首页
六、基于多阶段构建减小镜像体积降低复杂度

六、基于多阶段构建减小镜像体积降低复杂度

作者: 悟尘80 | 来源:发表于2020-05-09 09:40 被阅读0次

    本文是《Docker必知必会系列》第六篇,原文发布于个人博客:悟尘纪

    上一篇:Docker必知必会系列(五):Docker 数据持久化存储与性能调优

    一、引言

    如何减小所构建镜像的体积最非常具有挑战性的事情。Docker 17.05版本以后,新增了Dockerfile多阶段构建。所谓多阶段构建,实际上是允许一个Dockerfile 中出现多个 FROM 指令。

    二、单 Dockerfile 构建镜像

    如果将所有的构建过程都包含在一个 Dockerfile 中,包括项目及其依赖库的编译、测试、打包等流程,这样会带来的一些问题:

    • 镜像层次多,镜像体积较大,部署时间变长
    • 源代码存在泄露的风险

    下面是一个简单示例:

    FROM golang:1.14-alpine
    RUN apk --no-cache add git ca-certificates
    WORKDIR /go/src/github.com/go/lixl.cn/helloworld/
    COPY app.go .
    RUN go get -d -v github.com/go-sql-driver/mysql \
      && CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app . \
      && cp /go/src/github.com/go/lixl.cn/helloworld/app /root
    WORKDIR /root/
    CMD ["./app"]
    

    构建镜像:docker build -t go/helloworld:1 -f Dockerfile1 .

    三、Builder 模式构建

    为了解决上面提到的问题,可以采用 Builder 模式:创建两个 Dockerfile,一个用于开发(包含构建应用程序所需的一切),另一个用于生产(仅包含您的应用程序以及运行该应用程序所需的内容),然后用编译脚本将其整合:

    • Dockerfile.build 文件:

      FROM golang:1.14-alpine
      RUN apk --no-cache add git ca-certificates
      WORKDIR /go/src/github.com/go/lixl.cn/helloworld/
      COPY app.go .
      RUN go get -d -v github.com/go-sql-driver/mysql \
          && CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app . 
      
    • Dockerfile2 文件:

      FROM alpine:latest
      RUN apk --no-cache add ca-certificates
      WORKDIR /root/
      COPY app .
      CMD ["./app"]
      
    • build.sh 文件:

      #!/bin/sh
      echo Building go/helloworld:build
      
      docker build -t go/helloworld:build . -f Dockerfile.build
      docker create --name extract go/helloworld:build
      docker cp extract:/go/src/github.com/go/lixl.cn/helloworld/app ./app
      docker rm -f extract
      
      echo Building go/helloworld:2
      docker build --no-cache -t go/helloworld:2 . -f Dockerfile2
      rm ./app
      

    构建镜像:chmod u+x build.sh && sh ./build.sh

    这种方式生成的镜像会很小,不过过程比较复杂,而且生成的多个镜像都会占用系统空间。

    四、多阶段构建方式

    为了解决这些问题,自 Docker v17.05 开始支持多阶段构建。每一条 FROM 指令都是一个构建阶段,多条 FROM 就是多阶段构建,虽然最后生成的镜像只能是最后一个阶段的结果,但是,能够将前置阶段中的文件拷贝到后边的阶段中,这就是多阶段构建的最大意义。示例如下:

    FROM golang:1.14-alpine as builder
    RUN apk --no-cache add git
    WORKDIR /go/src/github.com/go/lixl.cn/helloworld/
    RUN go get -d -v github.com/go-sql-driver/mysql
    COPY app.go .
    RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .
    
    FROM alpine:latest as prod
    RUN apk --no-cache add ca-certificates
    WORKDIR /root/
    COPY --from=0 /go/src/github.com/go/lixl.cn/helloworld/app .
    CMD ["./app"]
    

    第二FROM条指令以alpine:latest为基础开始新的构建阶段。COPY --from=0 行仅将先前阶段中构建的工件复制到新阶段(第一个FROM条指令的起始编号为 0),Go SDK 和任何中间工件都不会保存在最终镜像中。

    接下来,使用 docker build -t go/helloworld:3 . 构建镜像,然后对比三种方式生成的镜像大小。

    docker images
    REPOSITORY             TAG           IMAGE ID            CREATED             SIZE
    go/helloworld          3             5fb7cd98ef33        2 minutes ago       8.22MB
    go/helloworld          2             7c30b66f73f9        2 minutes ago       8.22MB
    go/helloworld          1             28fb4443a052        2 hours ago         401MB
    

    可以看出,单 Dockerfile 方式构建的镜像非常大。后两种方式构建的镜像大小一致,但多阶段构建大大降低了复杂性。

    使用多阶段构建:

    • 可以在 Dockerfile 中使用多个 FROM 语句,每个 FROM 指令可以使用不同的基础镜像。

    • 每个 FORM 都会开始新的构建阶段,可以有选择地将工件从一个阶段复制到另一个阶段。

    • 通过在 FROM 指令中添加 AS name 来可以命名阶段,然后使用 COPY --from=name 而非数字来引用。

    • 可以指定目标阶段来构建镜像(使用 --target name 指令),而不是必须构建整个 Dockerfile。

    • 可以直接引用外部的镜像,如:COPY --from=nginx:latest /etc/nginx/nginx.conf /nginx.conf

    • 可以在使用 FROM 指令时引用前一个阶段,从上一个阶段结束。例如:

      FROM alpine:latest as builder
      RUN apk --no-cache add build-base
      
      FROM builder as build1
      COPY source1.cpp source.cpp
      RUN g++ -o /binary source.cpp
      
      FROM builder as build2
      COPY source2.cpp source.cpp
      RUN g++ -o /binary source.cpp
      

    更详细的介绍,可以参考:https://docs.docker.com/develop/develop-images/multistage-build/

    相关文章

    相关文章

      网友评论

          本文标题:六、基于多阶段构建减小镜像体积降低复杂度

          本文链接:https://www.haomeiwen.com/subject/clyhnhtx.html