zoukankan      html  css  js  c++  java
  • 使用 Docker 开发

    多阶段构建是一个新特性,需要 Docker 17.05 或更高版本的守护进程和客户端。对于那些努力优化 Dockerfiles 并使其易于阅读和维护的人来说,多阶段构建非常有用。

    在多阶段构建之前

    构建镜像时最具挑战性的事情之一就是缩小镜像大小。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 .
    

    请注意,此示例还使用 Bash 操作符 && 将两个 RUN 命令人为压缩在一起,以避免在镜像中创建额外的层。这很容易发生故障,也很难维护。例如,很容易插入另一个命令而忘记使用 字符继续行。

    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 脚本,它需要构建第一个镜像,从中创建一个容器来复制工件,然后构建第二个镜像。这两个镜像在您的系统上占用空间,并且您的本地磁盘上仍然有 app 工件。

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

    使用多阶段构建

    对于多阶段构建,可以在 Dockerfile 中使用多个 FROM 语句。每个 FROM 指令都可以使用不同的基镜像,并且它们都开始了构建的新阶段。您可以选择性地将工件从一个阶段复制到另一个阶段,舍弃在最终镜像中您不想要的所有内容。为了说明这是如何工作的,让我们使用多阶段构建调整前一节中的 Dockerfile。

    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 alexellis2/href-counter:latest .
    

    最终的结果是与前面相同的微小生产镜像,并且显著降低了复杂性。您不需要创建任何中间镜像,也不需要将任何工件提取到本地系统中。

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

    为构建阶段命名

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

    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)阶段,在这个阶段你的应用会被测试数据填充,但是在构建产品时,使用一个使用真实数据的不同阶段。

    docker-multi-stage-medium

    使用外部镜像作为“阶段”

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

    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
    

    作者 : Docker 官网
    译者 : 技术译民
    出品 : 技术译站
    链接 : 英文原文

  • 相关阅读:
    访问网站出现EOF
    ExecutorService中submit()和execute()的区别
    JAVA设计模式之工厂模式
    使用cssQuery选择器语法来查找元素
    【转载 待读】卷积神经网络
    Python random模块(获取随机数)常用方法和使用例子
    Python 字符串操作方法大全
    Microsoft Visual C++ 9.0 is required Unable to find vcvarsall.bat 解决办法
    如何在Windows 10安装和使用Linux的Bash shell
    python之内置函数
  • 原文地址:https://www.cnblogs.com/ittranslator/p/13235891.html
Copyright © 2011-2022 走看看