当前位置: 首页 > 科技观察

Docker好实践:精简你的镜像的5种方法

时间:2023-03-14 00:17:06 科技观察

创建一个短生命周期的容器根据Dockerfile生成一个镜像,使用这个镜像生成的容器,我们想尽可能的缩短容器的生命周期.我在这里的理解是不要将容器用作虚拟机。这个容器可以停止或销毁,然后根据设置和配置的变化重新生成一个新的容器。了解构建上下文当您触发dockerbuild命令时,当前目录称为构建上下文。默认情况下,Dockerfile文件在该目录下,但可以通过-f参数指定Dockerfile的位置。无论Dockerfile在哪里,当前目录下的所有文件和目录都会作为构建上下文发送到docker守护进程。构建上下文示例创建一个目录并将cds放入其中。在hello文件中写入“hello”,创建Dockerfile,同时cathello文件。在当前上下文(.)中构建镜像:mkdirmyproject&&cdmyprojectecho"hello">helloecho-e"FROMbusyboxnCOPY/hello/nRUNcat/hello">Dockerfiledockerbuild-thelloapp:v1。将Dockerfile和hello文件移动到另一个目录。并构建另一个图像(不要使用以前的图像构建缓存)。使用-f指定Dockerfile并指定context目录:mkdir-pdockerfilescontextmvDockerfiledockerfiles&&mvhellocontextdockerbuild--no-cache-thelloapp:v2-fdockerfiles/Dockerfilecontext在构建过程中导入不必要的文件会导致更大的构建上下文,这会构建更大的镜像.这会增加构建镜像的时间、拉取和上传镜像的时间以及容器的大小。当你使用Dockerfile构建镜像时,你可以通过以下信息检查你的构建上下文的大小:SendingbuildcontexttoDockerdaemon187.8MBUse.dockerignoretoexcludefilesdon'tneedtobeaddedtothemirror有时我们需要来排除一些与我们构建镜像无关的无关文件,这时候我们可以通过写.dockerignore来实现不改变代码结构的目的。该文件的实现与.gitignore非常相似。关于如何创建.dockerignore,可以参考.dockerignore文件使用multi-stagebuild多阶段构建技术可以大大减少最终镜像的大小,而不是试图减少构建过程的层数和文件数。因为图像是在构建过程结束时生成的,所以我们可以通过利用构建缓存来最小化图像层。比如你构建一个镜像,这个镜像有很多层,可以按照镜像层的修改频率排序(也就是把更新不频繁的层作为底层,这样构建缓存就可以重用):安装工具以安装或更新依赖项构建应用程序示例Dockerfile用于Go应用程序:FROMgolang:1.11-alpineASbuild#Installtoolsrequiredforproject#Run`dockerbuild--no-cache.`toupdatedependenciesRUNapkadd--no-cachegitRUNgogetgithub.com/golang/dep/cmd/dep#ListprojectdependencieswithGopkg.tomlandGopkg.lock#Theselayersareonlyre-builtwhenGopkgfilesareupdatedCOPYGopkg.lockGopkg.toml/go/src/project/WORKDIR/go/src/project/#InstalllibrarydependenciesRUNdepensure-vendor-only#Copytheentireprojectandbuildit#ThislayerisrebuiltwhenafilechangesintheprojectdirectoryCOPY./go/src/project/RUN/gobuild-o/bin复制代码project#ThisresultsinasinglelayerimageFROMscratchCOPY--from=build/bin/project/bin/projectENTRYPOINT["/bin/project"]CMD["--help"]不要安装不必要的包为了降低镜像的复杂度和体积,我们应该避免安装一些我们不需要的包。例如,您不需要在数据库镜像中安装文本编辑器。应用程序解耦每个容器应该只包含一个应用程序实例。将多个应用程序解耦到多个容器中,可以方便应用程序的水平扩展和复用容器。例如,一个Web应用应该包含三个容器(Web容器、数据库容器、缓存容器),每个容器对应一张图片。限制每个容器一个进程是一个很好的经验法则,但这也不是一个硬性规定。容器中的进程不仅可以由init创建,有些程序可能会另外生成一些自己的进程。例如,Celery生成多个工作进程,而Apache为每个请求创建一个进程。每个场景不同,规则也不同。但是我们应该保证我们的容器功能尽可能的清晰和模块化。如果容器相互依赖(容器可能需要通信),可以使用Docker容器网络来确保容器间通信。减少镜像层数减少镜像层数对于镜像构建来说非常重要。在旧版本的docker中,我们需要特别注意。现在我们可以通过以下特性轻松限制镜像的层数:只有ONLY、COPY、ADD这三个命令增加层数,其他命令只创建一些临时镜像,不增加构建镜像的层数.使用多阶段构建只会将真正需要的工件(artifacts)复制到最终的镜像中。这允许您在构建期间使用工具和打印调试信息,而无需增加最终图像的大小。对多行参数进行排序只要有可能,最好按字母顺序对参数进行排序,这样可以避免重复安装包(特别是apt-get命令),也可以让开发人员更容易阅读和审查。下面是buildpack-depsimageimages的例子:RUNapt-getupdate&&apt-getinstall-ybzrcvsgitmercurialsubversion借助buildcache构建image时,docker会按照dockerfile中指令的顺序执行一次。当每条指令执行时,docker会去缓存中检查是否有现有的镜像可以重复使用,而不是创建一个新的镜像副本。如果不想使用构建缓存,可以使用dockerbuild参数选项--no-cache=true来禁用构建缓存。使用镜像缓存时,需要弄清楚缓存什么时候适合生效,什么时候失效。构建缓存的最基本规则如下:如果引用的父图像在构建缓存中,则下一个命令将与从父进程派生的所有子图像进行比较。如果有子图像使用相同的命令,则缓存命中,否则缓存失效。在大多数情况下,将Dockerfile中的指令与子映像进行比较就足够了。但有些说明需要进一步检查。对于ADD和COPY命令,检查文件的内容并为每个文件计算校验和。但是,校验和不考虑文件的最近修改和访问时间。在构建过程中,docker会对比已有的镜像。只要文件内容和元数据发生变化,缓存就会失效。除了ADD和COPY指令外,图像缓存不会检查容器中的文件来确定是否命中缓存。例如,在处理RUNapt-get-yupdate命令时,并没有检查容器中的更新文件是否命中缓存,这种情况下只检查命令字符串。