• Docker从入门到精通——使用多阶段构建


    使用多阶段构建

      多阶段构建对于努力优化 Dockerfile 并使其易于阅读和维护的任何人都非常有用。

    一、在多阶段构建之前

      构建 images 最具挑战性的事情之一就是缩小 image 大小。Dockerfile 中的每条指令都会为映像添加一层,您需要记住在继续下一层之前清理您不需要的任何工件。要编写一个真正高效的 Dockerfile,您通常需要使用 shell 技巧和其他逻辑来保持层尽可能小,并确保每一层都具有前一层所需的工件,而没有其他任何东西。

      实际上,有一个 Dockerfile 用于开发(其中包含构建应用程序所需的所有内容)和一个精简的用于生产的 Dockerfile 是很常见的,它只包含您的应用程序以及运行它所需的内容。这被称为“建造者模式”。维护两个 Dockerfile 并不理想。

    这是一个遵循上述构建器模式Dockerfile.build的示例:Dockerfile

    Dockerfile.build

    # syntax=docker/dockerfile:1
    FROM golang:1.16
    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 .

    请注意,此示例还RUN使用 Bash&&运算符人为地将两个命令压缩在一起,以避免在图像中创建额外的层。这是容易失败且难以维护的。例如,很容易插入另一个命令而忘记使用该\字符继续该行。

    Dockerfile

    # syntax=docker/dockerfile:1
    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。这两个 image 都占用了您的系统空间,并且您 app 的本地磁盘上仍然有该工件。

      多阶段构建大大简化了这种情况!

    二、使用多阶段构建

      通过多阶段构建,您可以 FROM 在 Dockerfile 中使用多个语句。每条 FROM 指令都可以使用不同的基础,它们中的每一条都开始了构建的新阶段。您可以选择性地将工件从一个阶段复制到另一个阶段,从而在最终图像中留下您不想要的一切。为了展示它是如何工作的,让我们调整上一节中的 Dockerfile 以使用多阶段构建。

    Dockerfile

    # syntax=docker/dockerfile:1
    FROM golang:1.16
    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 alexellis2/href-counter:latest .

      最终结果是与以前相同的微小生产 image,但复杂性显着降低。您不需要创建任何中间 image,也不需要将任何工件提取到本地系统。

      它是如何工作的?第二条指令以 image 为基础FROM开始一个新的构建阶段。alpine:latest 该 COPY --from=0 行仅将构建的工件从前一个阶段复制到这个新阶段。Go SDK 和任何中间工件都被留下,不会保存在最终图像中。

    三、命名您的构建阶段

     默认情况下,这些阶段没有命名,您可以通过它们的整数来引用它们,第一FROM条指令从 0 开始。但是,您可以通过在指令中添加一个AS <NAME>来命名您的阶段。FROM此示例通过命名阶段并在COPY指令中使用名称来改进前一个示例。这意味着即使您的 Dockerfile 中的指令稍后重新排序,COPY也不会中断。

    
    
    # syntax=docker/dockerfile:1
    FROM golang:1.16 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您的应用程序填充测试数据的阶段,但使用使用真实数据的不同阶段构建生产

    五、使用外部图像作为“舞台” 

      使用多阶段构建时,您不仅限于从之前在 Dockerfile 中创建的阶段进行复制。您可以使用该COPY --from指令从单独的镜像中复制,可以使用本地镜像名称、本地或 Docker 注册表上可用的标签或标签 ID。如有必要,Docker 客户端会拉取映像并从那里复制工件。语法是:

    COPY --from=nginx:latest /etc/nginx/nginx.conf /nginx.conf
     使用前一个阶段作为新阶段

      FROM 使用指令时,您可以通过引用上一阶段停止的位置来继续。例如:

    # syntax=docker/dockerfile:1
    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

    六、版本兼容性

      Docker Engine 17.05 中引入了多阶段构建语法。

  • 相关阅读:
    环境部署(二):Linux下安装jenkins
    环境部署(一):Linux下安装JDK
    jenkins简单安装及配置(Windows环境)
    python相关资料链接
    性能测试相关资料链接
    管理篇:测试Leader应该做哪些事
    进阶篇:软件测试工程师的岗位职责
    基础篇:如何做一名专业的软件测试工程师
    python:面向对象编程之Zope.interface安装使用
    Django:Python3.6.2+Django2.0配置MySQL
  • 原文地址:https://www.cnblogs.com/zuoyang/p/16355788.html
Copyright © 2020-2023  润新知