《详解容器镜像优化.docx》由会员分享,可在线阅读,更多相关《详解容器镜像优化.docx(9页珍藏版)》请在优知文库上搜索。
1、对于刚接触容器的人来说,很容易被自己制作的DoCker镜像大小所吓到,我只需要个几MB的可执行文件而已,为何镜像的大小会达到TGB以上?卜面将从两方面来进行货像大小优化,一种是通过多阶段构建处理一种是使用不同的基础镜像进行特定优化与精简.1减少镜像大小这部分着于介绍多阶段构建(multi-stagebuilds),因为这是慢像精简之路至关至要的一环.在这部分内容中,我会解秣静态链接和动态琏接的区别,它们对愤像带来的影响.以及如何避免那些不好的影响。我们还是从helloworid的程序开始,用C语营实现如下:hdkc7intmain()putsCHelk.world!);return0:然后为其
2、编写Dockerfile.如下:SROM9COFYheIIox.RUNgcc-CKdloKdloxCMDeHowl执行Dockerbuild-theldgcc.进行构建后,发现偏像大小超过了1GB.因为该镜像包含了整个gcc镜像的内容,但其实编译好的代码可执行文件只有8.4KB,这显然不科学.Enr1o11us11nutes09032mnuteogo在声明构建阶段时,可以不必使用关域词AS,最终阶段拷贝文件时可以直接使用序号表示之前的构建阶段(从零开始),也就是说,下面两行是等效的:COPY-from三mytjiIdstagchello.COPY-from三Ohello.如果Dockerfil
3、e内容不是很豆杂,构建阶段也不是很多,可以直接使用序号表示构建阶段。一旦Dockerfile变聂杂了,构建阶段增多了,最好还是通过关燧词AS为每个阶段命名,这样也便于后期维护.细心的你,可能会发现上面以ubuntu为基础镜像还是大了些,能不能选择一个更小的潦像呢?当然可以,我们可以采用busybox或alpine镜像来替代该ubuntu镜像.2精简策略这部分将会针对不同的基咄镜像进行精简,比如scratch,alpine,slim等,还可以从语言层面进行精简,会以golang语言为例进行分析.2.1 golang精筒Go语言程序编译时会将所有必须的依赖编译到二进制文件中,但也不能完全肯定它使用
4、的是静态链接,因为G。的某些包是依赖系统标准库的,例如使用到DNS解析的包。只要代码中导入了这些包,编译的二进制文件就需要调用到某些系统库,为了这个需求,Go实现了一种机制叫CgO,以允许Go调用C代码,这样编译好的二进制文件就可以调用系统库。也就是说,如果Go程序使用了net包,就会生成一个动态的二进制文件,如果想让镜像能够正常工作,必须将需要的库文件苴制到或像中,或者直接使用busybox:glibc镜像.当然,你也可以禁止ego,这样Go就不会使用系统库使用内置的实现来替代系统南例如使用内者的DNS解析器),这种情况下生成的二进制文件就是静态的。可以通过设置环境变量CGo_ENAB1.E
5、D=O来禁用ego,例如:ROMgolangPYwhatsmyipoENVCG0-ENAB1.ED-0RUNgobuildwhatsmyip.90FROMSaatChCOPYfrom三Ogowhatsmyip.CMDwhatsmyip由于编译生成的是岸态二进制文件,因此可以直接跑在scratch镜像中(下面会介绍)当然,也可以不用完全禁用ego,可以通过-tags参数指定需要使用的内建库,例如-tagsnetgo就表示使用内建的net包,不依赖系统库:$gobuild-tagsnetgoWhatSmyipe90这样指定之后,如果导入的其他包都没有用到系统库,那么编译得到的就是静态二进制文件.也
6、就是说,只要还有一个包用到了系统库,都会开启ego,最后得到的就是动态二进制文件.要想一劳永逸,还是设因环境变量CGe1.ENAB1.ED=O吧.2.2 使用scratch镜像SCratCh镜像很小,因为它基本上是空的,除了D。Cker给它额外添加的metadata(元数据:描述数据的数据)。它是一个虚拟镜像,不能被pu,也不能运行,因为它表示空!scratch镜像不可以直接从Docker官方拉取下来,但可以用以下命令构建这个scratch潦像:Starcv-files-fromdevnulldockerimport-Saateh$dockerimageIsREPOSITORYTAGIMAGE
7、IDCREATEDSIZEscratchlatest775bfce214293minutesagoOB从钱像大小可知,scratch镜像大小为0,scratch构建钱像时,可精简到只在scratch上面加一层代码生成的二进制可执行文件.可以用于构建busybox等超小镜像,可以说是真正的从零开始构建届于自己的碗像。在构建二进制可执行文件的时候,需要进行薛态编译链接,因为scratch中没有我们需要的动态镇接库.比如:CGO_ENAB1.ED=0GOOS=IinuxGOARCH=arm64gobuild-oempty-a-IdfIags-semptyImageProject/所以如果您追求镜像极
8、小的话,可以使用scratch潼像配合多阶段处理来构建业务镜像.其缺点是:缺少shell,缺少调试工具、缺少Iibc等基础库.2.3 使用scratch镜像AlPine是众多1.inUX发行版中的一员,和CentoS、UbuntuxArChlinUX之类一样,只是一个发行版的名字,号称小巧安全,有自己的包管理工具apk.与CentoS和Ubuntu不同,Alpine并没有像RedHat或Canonical之类的大公司为其提供维护支持,软件包的数量也比这些发行版少很多(如果只看开箱即用的默认软件仓库,Alpine只有100OO个软件包,而Ubuntu、Debian和Fedora的软件包数量均大于
9、50000.)容器娓起之前,AlPine还是个无名之辈,可能是因为大家并不是很关心操作系统本身的大小,毕竟大家只关心业务数据和文档,程序、库文件和系统本身的大小通常可以忽略不计.容器技术席卷整个软件产业之后,大家都注意到了一个问SS,那就是容器的穗像太大了,浪费磁盘空间,拉取镜像的时间也很长.于是,人们开始寻求适用于容器的更小的镜像.对于那些耳熟能详的发行版(例如Ubuntu、Debian.Fedora)来说,只能通过删除某些工品例如ifconfig和netstat网镜像体积控制在100M以下。而对于Alpine而言,什么都不用删除,镜像大小也就只有5M而已。AlPine镜像的另一个优势是包管
10、理工具的执行速度非常快,安装软件体验非常烦滑.诚然,在传统的虚拟机上不需要太关心软件包的安装速度,同一个包只需要装一次即可,无需不停生且安装,容器就不一样了,你可能会定期构建新镜像,也可能会在运行的容器中临时安装某些调试工具,如果软件包的安装速度很慢,会很快消磨掉我们的耐心.为了更直观,我们来做个简隼的对比测试,看看不同的发行版安装tcpdump需要多长时间,测试命令如下:$timedockerrunpxkaginstalltcpdump测试结果如下:BaseimageSizeTimetoinstalltcpdumpalpine.115.6MB1-2sarchlinux202106409MB7
11、-9sEtOS由237MB5-Gsdcbian:10114MB5-7SNdoraSI194MB35-60$ubuntu:!8.044MB6-8$既然apline镜像除了小之外,工具包的安装速度也快,那我们在挑选各种语言版本的基础镜像时,可以优先选择带alpine的tag的镜像,比如golang:alpine就提供了基于Alpine构建的Go工具链.FROMgolanglpinePYhellogo.RUNgobuildhellooFROMalpinePY-from=0gohcllo.CMD(hello-)生成的镜像大小为7.5M对于一个只打印hell。World的程序来说确实有点大了.但我们可以
12、换个角度:即使程序很红杂,生成的镜像也不会很大.包含了很多有用的调试工具.即使运行时缺少某些特殊的调试工具,也可以迅速安装.Go语言搞定了.C语言呢?并没有gcc:alpine这样的镜像啊。只能以Alpine镜像作为基础镜像,自己安装C编译器了,Dockerfile如下:FROMalpineRUNapkXdbuild-teeCOrrKello.C.RUNget-ohelloKHaCFROMalpineCOPYfrom三0hdlo.CMDhcow展后来对比一下不同构建方法得到的helloworld潦像大小:使用基础镜像golang构建:805MB多阶段构建,b3ld阶段使用基础镜像golang,run阶段使用基础镜像ubuntu:66.2MB多阶段构建,build阶段使用基咄镜像golang:alpine,run阶段使用基础镜像alpine:7.6MB多阶段构建,build阶段使用基咄镜像golang,run阶段使用基础镜像scratch:2MB最终镜像体积减少了99.75%,相当惊人了。2.4 slim镜像如果实在不想折腾,可以选择一个折衷的镜像xxx:SIim。slim镜像一般都基于Debian和glibc,删除了许多非必需的软件包,优化了体积.如果构建过程中需要编译器,那么slim镜像不适合.除此之外