在过去的几天里,我需要几次在一些微小的变化后上传一个1Gb的图像,我不禁想知道为什么没有一个部署路径内置到Docker和相关技术(如k8s)中,以推动 * 只是应用程序文件 *(Dockerfile,Docker-compose.yml和应用程序相关代码),并有它建立了基础设施 * 从 *(现场)Docker主机?
换句话说,为什么我每次修改应用程序代码时都要上传整个linux机器?
Docker的全部要点不就是配置描述了一个纯粹确定性的基础设施输出吗?我甚至不明白为什么需要上传整个容器映像,除非他们在Dockerfile之外手动对其进行更改,然后希望上传修改后的映像。但这至少看起来是一个糟糕的做法...
我错过了什么,还是这只是系统的一个特点?
1条答案
按热度按时间2q5ifsrm1#
问得好。
简短回答:
因为存储比处理能力便宜,所以构建"实时"映像可能很复杂、耗时,而且可能不可预测。
例如,在您的Kubernetes集群上,您只需要提取图像的"缓存"层,您知道它可以正常工作,您只需在几秒钟内运行它,而不是编译二进制文件和下载内容(如您在Dockerfile中指定的那样)。
关于构建映像:
您不必在本地构建这些映像,您可以使用CI/CD runner并从管道中运行
docker build
和docker 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 GCP和AWS CodeBuild)