kubernetes 为什么Docker容器依赖于上传(大)图像而不是从规范文件构建?

j7dteeu8  于 2023-02-03  发布在  Kubernetes
关注(0)|答案(1)|浏览(100)

在过去的几天里,我需要几次在一些微小的变化后上传一个1Gb的图像,我不禁想知道为什么没有一个部署路径内置到Docker和相关技术(如k8s)中,以推动 * 只是应用程序文件 *(Dockerfile,Docker-compose.yml和应用程序相关代码),并有它建立了基础设施 * 从 *(现场)Docker主机?
换句话说,为什么我每次修改应用程序代码时都要上传整个linux机器?
Docker的全部要点不就是配置描述了一个纯粹确定性的基础设施输出吗?我甚至不明白为什么需要上传整个容器映像,除非他们在Dockerfile之外手动对其进行更改,然后希望上传修改后的映像。但这至少看起来是一个糟糕的做法...
我错过了什么,还是这只是系统的一个特点?

2q5ifsrm

2q5ifsrm1#

问得好。
简短回答:
因为存储比处理能力便宜,所以构建"实时"映像可能很复杂、耗时,而且可能不可预测。
例如,在您的Kubernetes集群上,您只需要提取图像的"缓存"层,您知道它可以正常工作,您只需在几秒钟内运行它,而不是编译二进制文件和下载内容(如您在Dockerfile中指定的那样)。
关于构建映像:
您不必在本地构建这些映像,您可以使用CI/CD runner并从管道中运行docker builddocker push,当您将代码推送到git仓库时,管道会运行这些映像。
而且,如果图像太大,你应该寻找减少其大小的方法,使用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
这是基于阿尔卑斯山:https://github.com/alpinelinux/docker-alpine
在实际启动应用程序之前,您不希望应用程序在运行时执行这些文件(及其脚本)中指定的所有操作,因为这可能是不可预测的、耗时的,并且比它应该的更复杂(例如,您需要防火墙例外,用于从集群到互联网的出口流量,以下载一些您不知道是否可用的依赖项)。
你可以根据你测试过的基础映像发布一个映像,然后把它发送到注册中心,k8s会把它当作一个黑盒来运行,这可能是可预测的和确定的。
然后关于你的观点,它是多么烦人,推动巨大的码头图片每一次:
您可以通过遵循一些最佳实践并精心设计您的Dockerfile来减少该大小,例如:

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

最后但并非最不重要:
您不必从计算机推送映像,可以使用CI/CD runner(例如build-push Github action),或者使用云提供商的"Cloud Build"产品(例如Cloud Build for GCPAWS CodeBuild

相关问题