镜像是 Docker 运维的基本单元。 优化镜像体积,能够:
提升安全性,因为可供攻击的目标更少;
减少故障恢复时间;
节省存储开销。
认清与理解 Docker 镜像的层次结构,是进行镜像优化的前提和基础。
docker 镜像的存储结构是分层次的。 无论底层的文件系统(可选可配置)是基于快照还是分块。
镜像构建的过程里,每步操作都产生一个只读的层:可重用,可复制,但是不可修改。 层次叠加,形成了包含历史(history)结构的镜像。 镜像启动后,产生了容器(container)。容器也是一个单独的层,可读写,但是不持久化,易丢失。
共享,以分层为基础。 以一个镜像为祖先,分别用多种方式做不同操作,各自生成新层,则形成多个新的镜像,祖先镜像则成为共享的部分。 继承自共同的祖先,实现了对共同内容的利用。
对单个镜像体积做优化,采取方式有两类思路:
打包尽可能少的内容入镜像
使用单行命令
工程实践中,还要考虑多镜像复用,尽量:
基础镜像需要满足的基本条件:
日志。Docker 的应用程序日志一般默认在标准输出,而系统进程仍然会往 /dev/log 写数据。需要有日志处理程序 syslog
后台任务如 cron
工具进程如 sshd(慎重选择)
这些需求,与在传统的服务器和虚拟机上做部署,是相似的。
如果仅仅基于这种相似性,就选择了使用 CentOS/Debian/Ubuntu 做为基础镜像,那么就有问题了。 首先,这些传统发行版的 Docker 镜像并不能符合基础需求; 其次,这些发行版的体积太大。
所有,仍然需要选择较小的发行版制作初始镜像。
市面上可选的有:
baseimage-amzn
Alpine
busybox
…
如果有多个业务需要运维,则在公共基础镜像基础上,构建私有的模版镜像。 共同的模版镜像,能够:
减少重复工作。解决边缘问题
减少开发时间。专注于上层应用
减少编译时间。
减少部署时间。基于镜像的层共享
模版镜像的目标是抽取业务的公共部分。
上线后,需要经常关注这些问题:
新业务使用到某个公共镜像,效果还不错,要不要推而广之?
解决这些问题,还需要经常复审镜像服用的效率。 简单的方案,可以对各类环境中的模版使用情况进行统计,尽量合并相似的镜像,将使用率较高的组件吸收进模版镜像。
常用考评指标:
编译效率
传输效率
存储效率
–flatten 是现在还是一个测试特性,可以减少镜像总体积,然而与复用的原则有冲突。 需要更加实际情况去做考虑。
这是因为应用程序需要一系列依赖。 如果使用最小的基础镜像,在制作应用镜像时,比如需要去安装依赖。 安装步骤可能会引入更多不必要的元素。 所以反而体积会超过已包含所需依赖的公共镜像。
centos -> app
alpine -> dependencies -> app # Too much dependencies