![70d8ae5d159630fe4926ef396a5f38be.png](https://img-blog.csdnimg.cn/img_convert/70d8ae5d159630fe4926ef396a5f38be.png)
毫无疑问,Docker 使部署多个应用程序变得非常容易。对于同一工具的不同版本、具有不同版本依赖关系的不同应用程序 ,Docker都能帮你搞定。但是,这种灵活性伴随着一些问题 - 如高磁盘使用率和大镜像时,在编写 Dockerfile时要使用一些技巧,以减少镜像大小并缩短生成时间。
Docker提供了一套遵循的标准实践,以使您的镜像尺寸较小-还简要介绍了多阶段构建。
多阶段构建 对于我们构建项目、二进制或可执行文件的用例特别有用。通常,构建二进制文件(例如 GCC、Maven等)需要大量依赖项,但一旦有可执行文件,就不需要这些依赖项来运行可执行文件。多阶段构建允许你在单独的环境中生成可执行文件,然后仅使用运行可执行文件所需的可执行文件和最小依赖项生成最终镜像。
例如,下面是一个在 Go 编写的简单应用程序。它的所有工作是输出"Hello World!!",
DockerfileFROM golangADD . /appWORKDIR /appRUN go build # This will create a binary file named appENTRYPOINT /app/app
- 生成并运行镜像
docker build -t goapp .~/g/helloworld ❯❯❯ docker run -it --rm goappHello World!!
- 现在让我们检查镜像大小
~/g/helloworld ❯❯❯ docker images | grep goappgoapp latest b4221e45dfa0 18 seconds ago 805MB
- 新 Dockerfile
# Build executable stageFROM golangADD . /appWORKDIR /appRUN go buildENTRYPOINT /app/app# Build final imageFROM alpine:latestRUN apk --no-cache add ca-certificatesWORKDIR /root/COPY --from=0 /app/app .CMD ["./app"]
- 重新生成和运行镜像
docker build -t goapp .~/g/helloworld ❯❯❯ docker run -it --rm goappHello World!!
- 让我们再次检查镜像
~/g/helloworld ❯❯❯ docker images | grep goappgoapp latest 100f92d756da 8 seconds ago 8.15MB~/g/helloworld ❯❯❯
我们可以看到镜像大小的大幅减少 -> 从805 MB到8.15 MB。这主要是因为Golang 镜像具有大量依赖关系,而我们的最终可执行文件甚至不需要这些依赖项来运行。
这里发生什么事了?
我们正在分两个阶段构建镜像。首先,我们使用 Golang 基本镜像,复制其内部的代码并构建我们的可执行文件。现在,在下一阶段,我们使用一个新的 alpine Linux 前构建的二进制文件到我们的新阶段。这里需要注意的要点是,每个阶段构建的镜像是完全独立的。
- 阶段 0
# Build executable stageFROM golangADD . /appWORKDIR /appRUN go buildENTRYPOINT /app/app
- 阶段 1
# Build final imageFROM alpine:latestRUN apk --no-cache add ca-certificatesWORKDIR /root/COPY --from=0 /app/app .CMD ["./app”]
请注意 COPY —from=0 /app/app这允许从上一个镜像中构建的镜像内部访问数据。
多阶段构建如何工作?
如果仔细查看流程,多阶段生成与实际 Docker 生成没有太大不同。唯一的主要区别是,您构建多个独立镜像(每个阶段 1 个),并且能够轻松地将 artifacts/files 从一个镜像复制到另一个镜像。多阶段构建现在提供的功能是较早通过脚本实现的。人们用于创建生成镜像 - 手动复制项目 - 然后将其复制到新镜像,无需其他依赖关系。在上面的示例中,我们在 Stage 0中构建一个镜像,然后在Stage 1中生成另一个镜像,我们将从旧镜像中复制文件 - 没有什么复杂的。
注意:我们将/app从一个镜像复制到另一个镜像 - 而不是一个容器到另一个容器。
这可以通过多种方式加快部署并节省成本
- 您可以构建高效的轻量级镜像 - 因此,在部署期间,您可以生成较少的数据,从而节省成本和时间。
- 您可以在任何阶段停止多阶段生成-因此您可以使用它来避免使用多阶段生成构建器模式。有一个用于开发、暂存和部署的Dockerfile。
以上只是一个小例子,多阶段构建也可用于改进以其他语言编写的应用程序的 Docker 镜像。