一 Docker镜像优化层面
- 空间优化,也就是优化 Docker 镜像体积(也称呼为“镜像瘦身”)
- 优化 Docker 镜像构建速度,是优化构建的时间
二 Docker镜像优化方式
- 选择最精简的基础镜像
- 合理规划镜像的层数
- 清理镜像构建的中间产物
- 优化网络需求
- 构建缓存
- 使用多阶段构建镜像
- 编写 .dockerignore 文件
上述中: 空间优化(1、3、6)时间优化(4、5、7)
三 时间优化
时间层面的优化方式有网络优化、构建缓存、编写 .dockerignore 文件 3 种方式;
网络优化
优化网络主要是为了让镜像下载或者依赖的安装、代码下载在网络通道上更加通畅。常用的优化方式例如:调整构建机器网络质量、配置就近的加速仓库地址等等。
构建缓存
本地缓存
Docker 构建时下载基础镜像文件会进行缓存,所以构建缓存优化时,为了减少镜像的传输下载时间,建议使用固定的机器来专门进行镜像的构建。
镜像分层缓存
Docker 的一大特色就是镜像的存储分层,在 dockerfile 中的每一个指令会对应到镜像的每一层,并且默认启用缓存,所以构建时每一层是否会缓存取决于三个关键因素:
镜像父层没有发生变化
构建指令不变
添加文件校验和一致
只要一个构建指令满足这三个条件,这一层镜像构建就不会再执行,而是直接利用之前构建的结果。
编写 .dockerignore 文件
编写 .dockerignore 文件用于过滤构建过程中不必要的文件,或者创建单独的目录(如 .git 文件夹,markdown 文档等),从而减小目标镜像大小,加快构造速度。
四 空间优化
选择最精简的基础镜像
Docker 的仓库中存在同一个基础镜像的多个版本,为了优化 Docker 体积,我们通常会建议使用 Alpine 类型的版本,因为 Alpine 镜像和类似的其他镜像都经过了优化,其中仅包含最少、必须的软件包,所以它能够节省很多体积。
Alpine 类型的镜像被很多开发技术人员优先推荐。但是Alpine镜像也存在很多问题:
使用 Alpine 镜像程序容易报错
因为 Alpine 为了追求精简,很多依赖库都没有,需要一些依赖动态链接库的程序运行时就容易报错,比如 Go 的 cgo 调用。
域名解析行为跟 glibc 有差异
Alpine 镜像的底层库是 musl libc,域名解析行为跟标准 glibc 有差异,需要特殊作一些修复配置,并且有部分选项在 resolv.conf 中配置不支持。
运行 bash 脚本不兼容
因为没有内置 bash,所以运行 bash 的 shell 脚本会不兼容。
除此之外,使用 Alpine 镜像还会导致时区不一致、无法通过 lxcfs 提升容器资源可见性等问题。所以,你在真正使用之前需要评估好 Alpine 的弊端和风险,如果一定需要使用 Alpine 镜像,最好的方式是先使用 Alpine 镜像做基础镜像,在项目直接使用 Alpine 镜像之前进行一次初始化,然后再用初始化后的版本作为通用的基础镜像。
合理规划镜像的层数
除了精简的基础镜像,你还可以在编写 dockerfile 时,根据实际情况去合并一些指令,尽量减少镜像层级,以此来优化体积。
在 dockerfile 中每执行一条指令,就会提交一次修改,这次修改会保存成一个只读层挂载到联合文件系统,上面层的文件如果和下面层有冲突或不同,会覆盖隐藏底层的文件,所以每增加一层,镜像大小就会增加,但是在 Docker1.10 后有所改变,只有 RUN、COPY、ADD 指令会创建层,其他指令会创建临时的中间镜像,不会直接增加构建的镜像大小 。
使用多阶段构建镜像
将 dockerfile 的构建配置环境分为软件的编译环境和运行环境,这种方式就是多阶段构建思路。