这是Google Developer Advocate Sandeep Dinesh 关于如何充分利用Kubernetes环境的七部分视频和博客系列的第一部分。 主要讲保持容器镜像尽可能小的理论和实用性。

dockerfileFROM node:onbuildEXPOSE 8080
通过使用较小的基础镜像(如Alpine),您可以显著减少容器的大小。Alpine Linux是一款体积小,轻量级的Linux发行版,在Docker用户中非常受欢迎,因为它与许多应用程序兼容,同时仍然保持小体积。
幸运的是,Node.js(以及其他流行语言)有一个官方的Alpine图像,可以满足您的一切需求。与默认的node镜像不同,node:alpine会删除许多文件和程序,只留下足以运行您的应用程序的部分。
基于Alpine Linux的Dockerfile创建起来有点复杂,因为你必须运行一些针对onbuild的命令。
dockerfileFROM node:alpineWORKDIR /appCOPY package.json /app/package.jsonRUN npm install --productionCOPY server.js /app/server.jsEXPOSE 8080CMD npm start
但是,这是值得的,因为产生的镜像只有65MB!
编译型语言的容器化

dockerfileFROM golang:onbuildEXPOSE 8080
下一步是使用更小的基础镜像,也就是golang:alpine镜像。 到目前为止,这与我们针对解释型语言所遵循的过程相同。
同样,使用Alpine基础镜像创建Dockerfile有点复杂,因为您必须运行一些执行onbuild镜像相关的命令。
dockerfileFROM golang:alpineWORKDIR /appADD . /appRUN cd /app && go build -o goappEXPOSE 8080ENTRYPOINT ./goapp
但同样,由此产生的镜像要小得多,大小只有256MB!
但是,我们可以使镜像更小:您不需要Go附带的任何编译器或其他构建和调试工具,因此您可以从最终容器中删除它们。
让我们使用多阶段构建来获取由golang:alpine容器创建的二进制文件并将其自行打包。
dockerfileFROM golang:alpine AS build-envWORKDIR /appADD . /appRUN cd /app && go build -o goappFROM alpineRUN apk update && \ apk add ca-certificates && \ update-ca-certificates && \ rm -rf /var/cache/apk/*WORKDIR /appCOPY --from=build-env /app/goapp /appEXPOSE 8080ENTRYPOINT ./goapp
你看看现在! 这个容器镜像只有12MB大小!
在构建此容器时,您可能会注意到Dockerfile会执行一些奇怪的操作,例如手动将HTTPS证书安装到容器中。这是因为基础的Alpine Linux几乎没有预安装任何东西。 因此,即使您需要手动安装任何依赖项,最终结果也还是超小容器镜像!
注意:如果您想节省更多空间,可以静态编译应用程序并使用scratch容器镜像。使用scratch作为基础容器镜像意味着您从头开始,根本没有基础层。 但是,我建议使用Alpine作为基础镜像而不是scratch,因为Alpine镜像中的仅仅增加少量额外MB的大小却可以使得使用标准工具和安装依赖项变得更加容易。
在哪构建和存储您的容器镜像?



对于每次构建,我都会删除缓存中的所有Docker镜像。
构建(Build):
Go Onbuild: 35 SecondsGo Multistage: 23 Seconds
对于较大的容器镜像,构建需要的时间大约是10秒左右。 虽然这个代价仅在初始构建时需要付出,但是如果您使用持续集成系统,则在每次构建时都要付出这个代价。
下一个测试是将容器镜像推送到远程镜像仓库。 对于此测试,我使用Google Container Registry来存储镜像。
推送(Push):
Go Onbuild: 15 SecondsGo Multistage: 14 Seconds
这很有趣! 为什么需要花费相同的时间来推送12MB镜像和700MB镜像? 事实证明,Google Container Registry在幕后使用了很多技巧,包括许多流行基础镜像的全局缓存。
最后,我想测试将镜像从远程镜像仓库库拉到本地计算机所需的时间。
拉取(Pull):
Go Onbuild: 26 SecondsGo Multistage: 6 Seconds
20秒的差距,这是使用两个不同容器镜像之间的最大差异。 您可以开始看到使用较小镜像的优势,尤其是在经常拉取镜像时。
您还可以使用Google Container Builder在云中构建容器镜像,这样可以自动将它们存储在Google Container Registry中。
构建(build)+ 推送(Push):
Go Onbuild: 25 SecondsGo Multistage: 20 Seconds
再次证明,使用较小的镜像有一点小优势,没有我想象的那么大。
在小型机器上构建镜像

Go Onbuild: 52 secondsGo Multistage: 6 seconds
推送(Push):
Go Onbuild: 54 secondsGo Multistage: 28 seconds
拉取(Pull):
Go Onbuild: 48 SecondsGo Multistage: 16 seconds
在这种情况下,使用较小的容器镜像确实非常有帮助!
在Kubernetes上拉取镜像


哇,这次两者之间有很大的不同! 较小容器镜像中只有三个“中级”漏洞,而较大容器镜像中有16个严重漏洞和300多个其他漏洞。
让我们深入了解更大容器镜像里面存在的问题。
您可以看到大多数存在的问题与我们的应用程序无关,甚至没有我们的应用程序! 因为多阶段构建使用的是更小的基础镜像,所以可以产生漏洞的东西更少。
结论
