【问题标题】:Why do docker containers rely on uploading (large) images rather than building from the spec files?为什么 docker 容器依赖于上传(大)图像而不是从规范文件构建?
【发布时间】:2023-02-01 08:54:34
【问题描述】:

在过去的几天里,在经过一些微小的改变后,我需要多次上传 1Gb 的图像,我不禁想知道为什么没有内置到 docker 和相关技术(例如 k8s)中的部署路径来推送只是应用程序文件(Dockerfile、docker-compose.yml 和应用程序相关代码)并构建基础设施从内部(现场)码头工人主机?

换句话说,为什么每次更改我的应用程序代码时都必须上传整个 linux 机器?

配置描述纯粹确定性基础设施输出的 Docker 的重点不是吗?我什至不明白为什么需要上传整个容器镜像,除非他们在 Dockerfile 之外手动对其进行更改,然后希望上传修改后的镜像。但这至少似乎是不好的做法......

我错过了什么或者这只是系统的一个特点?

【问题讨论】:

  • 如果使用得当,Docker 会按照您想要的方式运行。这是其图像层如何工作的一个特点。当你重建一个镜像时,只有应用程序相关的东西应该改变,而基本操作系统镜像保持不变。推送时,仅提交更改的图像层。如果您在每次重建时都有 1GB 的上传,这很可能是图像构建方式的问题。 dockerfile 中的每个步骤都会创建一个图像层,这对于控制重建时构建和上传的内容很重要。
  • Docker 不一定是确定性的。一个常见的例子是在构建时获取一个远程文件,它可能指向一个组件的“最新”版本。

标签: docker kubernetes containers amazon-eks


【解决方案1】:

好问题。

简短回答:

由于存储比处理能力便宜,因此“实时”构建图像可能很复杂、耗时,而且可能无法预测。

例如,在你的 Kubernetes 集群上,你只想拉取你知道它有效的图像的“缓存”层,然后你只需运行它......在几秒钟内而不是编译二进制文件和下载东西(正如你在你的 Dockerfile)。

关于构建图像:

您不必在本地构建这些图像,您可以使用 CI/CD 运行器并从将代码推送到 git 存储库时运行的管道中运行 docker builddocker push

而且,如果图像太大,你应该研究通过使用multi-stage building、使用更轻/最小的基础图像、使用更少的层来减小其大小的方法(例如多个RUN apt install可以分组为一个apt install命令列出多个包),并使用 .dockerignore 不将不必要的文件发送到您的图像。最后阅读更多关于 caching in docker builds 的信息,因为它可能会减少您在进行更改时可能推送的层的大小。


长答案:

将 Dockerfile 视为源代码,将 Image 视为最终的二进制文件。我知道这是一个经典的例子。

但是只要考虑一下每次要使用它时构建/编译二进制文件需要多长时间(通过运行它,或者将它作为库导入到不同的软件中)。然后考虑下载该软件的依赖项或每次运行它们时在不同机器上编译它们的不确定性。

你可以拿 Node.js 的 Dockerfile 为例: https://github.com/nodejs/docker-node/blob/main/16/alpine3.16/Dockerfile

这是基于 Alpine 的:https://github.com/alpinelinux/docker-alpine

您不希望您的应用程序在实际启动您的应用程序之前在运行时执行这些文件(及其脚本)中指定的所有操作,因为它可能不可预测、耗时并且比应有的更复杂(例如,您从集群到互联网的出口流量需要防火墙例外,以下载一些您不知道它们是否可用的依赖项)。

相反,您可以根据您测试并构建要运行的代码的基础映像来发布映像。该图像将被构建并发送到注册表,然后 k8s 将把它作为一个黑盒子运行,这可能是可预测和确定的。

然后关于你每次推送巨大的 docker 图像是多么烦人的观点:

您可以通过遵循一些最佳实践并精心设计 Dockerfile 来减小该大小,例如:

  • 减少层数,例如,只要有可能就向命令传递多个参数,而不是多次重新运行它们。
  • 使用多阶段构建,因此您只会推送最终图像,而不是编译和配置应用程序所需构建的阶段。
  • 避免将数据注入图像,您可以稍后在运行时将其传递给容器。
  • 对图层进行排序,这样您在进行更改时就不必重新构建未触及的图层。
  • 不要包含不必要的文件,使用.dockerignore

最后但并非最不重要:

你不必从你的机器上推送图像,你可以使用 CI/CD 运行器(例如build-push Github action),或者你可以使用你的云提供商的“云构建”产品(比如Cloud Build for GCPAWS CodeBuild )

【讨论】:

    猜你喜欢
    • 2021-06-23
    • 2019-10-24
    • 1970-01-01
    • 1970-01-01
    • 2022-01-18
    • 1970-01-01
    • 2021-02-24
    • 1970-01-01
    • 2016-08-16
    相关资源
    最近更新 更多