技术: 深耕 Docker 生态圈(五){自己构建的镜像为何这么大}

解决前面留下的问题,为什么自己构建的镜像比没有commit之前的大得多?

你要是回答一句 “因为你给镜像里扔了很多东西” 那我就没话可说了。

现在的想法是,有没有什么办法可以缩小镜像的尺寸?,除了 docker save -o 这种导出办法。

虽然我已经知道 commit 其实是在多层文件系统上另外增加了一层文件系统,即按照镜像的构建的方式。

但是为啥会大这么多?

如果仔细观察,会注意到,这里标识的所占用空间和在 Docker Hub 上看到的镜像大小不同。比如,ubuntu:16.04 镜像大小,在这里是 127 MB,但是在 Docker Hub 显示的却是 50 MB。这是因为 Docker Hub 中显示的体积是压缩后的体积。在镜像下载和上传过程中镜像是保持着压缩状态的,因此 Docker Hub 所显示的大小是网络传输中更关心的流量大小。而 docker image ls 显示的是镜像下载到本地后,展开的大小,准确说,是展开后的各层所占空间的总和,因为镜像到本地后,查看空间的时候,更关心的是本地磁盘空间占用的大小。

也就是说,原来的镜像看到的是压缩状态的,而 docker images 或者 docker image ls 看到的是本地展开后各层所占的磁盘空间总和。

另外一个需要注意的问题是,docker image ls 列表中的镜像体积总和并非是所有镜像实际硬盘消耗。由于 Docker 镜像是多层存储结构,并且可以继承、复用,因此不同镜像可能会因为使用相同的基础镜像,从而拥有共同的层。由于 Docker 使用 Union FS,相同的层只需要保存一份即可,因此实际镜像硬盘占用空间很可能要比这个列表镜像大小的总和要小的多。

你可以通过 docker system df 来便捷的查看镜像、容器、数据卷所占用的空间。

这个例子不太明显,当有多个镜像且是经过同一个镜像构建比如commit的话,就能看出来实际占用比查看到占用小:

可以用 docker history 命令查看是否是多了一层。 (docker history ubuntu:file)

其实最后也就一句话: 看到的占用的大并非实际真的占有那么多。(btw: 慎用 commit)

为什么自己构建的镜像比没有commit之前的大得多?

其实也和 docker commit 有关。

貌似只是修改了一个文件或者添加了一个库,其实还有很多文件被改动或添加了。这还仅仅是最简单的操作,如果是安装软件包、编译构建,那会有大量的无关内容被添加进来,如果不小心清理了话,将会导致镜像极为臃肿。(镜像原来的层不会动,只会再加一层;层层如影随行;所以最好不要 commit)


问题是如何缩小镜像大小?

  • 采用压缩,甚至导出为压缩文件
  • 了解实际构建过程,自己控制 Dockerfile 过程(减少指令语句)。(比如用脚本控制,优化流程)
  • 在 Docker 17.05 以上版本中,你可以使用 多阶段构建 来减少所构建镜像的大小

更加深入的实践和经验,后续补充一下。
个人觉得 多阶段构建 应该已经能很好的满足要求了;除非你的容器构建没有遵循《Dockerfile最佳实践》里推荐的几个建议。


Merlin

文章目录
|