前言

怎样才是构造Docker镜像的正确姿势?

相信大家在使用docker构建镜像时往往都会遇到这样的问题: 做的事情很简单,但是最终产出的镜像体积却要大得离谱,拖慢了服务部署的耗时,使镜像本身变得很不好用,同时这也背离了Docker存在的核心意义,那么也许这片文章能帮助到你。

构造方式的选择

docker为我们提供了三种构造方式

  • docker commit
  • docker build
  • docker import/load

commit可以让我们将已存在的容器提交生成一个全新的镜像,在容器中你可以做完所有的修改操作,这种方式好处在于这使镜像的构造变得极其简单方便,可以不用在意用料成本的情况下反反复复重试直到自己满意,但缺点就是这会导致你产出的镜像体积变得难以把控,且不利于维护,所以本人不推荐使用这种方式去构造镜像。

dockerfile是最常用的构造方式,它是一种脚本,你的每一句指令都会被docker build所解析执行,也正因为是脚本,所以你可以把它放在git上多人协作来共同维护更新,同时也保证了镜像的质量,更直观的表现就在于它可以让你最终产出的镜像体积达到最小,所以这也成了推荐使用它的原因。

import用于导入使用docker export所导出的容器,load用于导入使用docker save所导出镜像,它们最终都会成为镜像,但export/import操作会丢失该镜像的历史层。

Dockfile

在dockefile中,每一条指令都会使我们的镜像生成一个新的层,所有层的大小总和就是这个镜像的体积,当我们选择编写dockerfile来构建镜像的时候就必须得注意 RUN、COPY、ADD、EXPOSE 这些操作类的指令给镜像带来的修改成本,合理的使用它们,可以最大程度的优化镜像的体积。

举个栗子:

RUN wget https://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-5.7.17.zip
……………
RUN rm -rf mysql-5.7.17.zip

我们先wget了一个65m大小的mysql源码包,然后通过RUN rm -rf删除无用文件来尝试减小体积,但实际上镜像的大小并不会减小,只会给镜像再新增一个size为0的层,原因在我《DOCKER的工作原理与实际应用》文章中已提到。

解决办法:

RUN wget https://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-5.7.17.zip \
&& …………… \
&& rm -rf mysql-5.7.17.zip

很简单,只要将两个RUN操作合并成一个来执行就可以了,这样RUN新增的层就不会附带上源码包的体积。

后记

这些也都是我自己在构建镜像时踩过的坑,在解决问题的过程中得到的经验分享给大家,也希望能提供你们一些帮助~


一介布衣