Streamlined compression and optimized Docker image hundreds of MB

Reprint: http://www.dockerinfo.net/3328.html

20161027203227

introduce

Some time ago, Netease Honeycomb launched the Honeycomb Logo T-shirt, which was made with Docker image. The most amazing thing is that its final image size is only 585 bytes.

$ docker images | grep hub.c.163.com/public/logo

REPOSITORY                          TAG     IMAGE ID           CREATED      SIZE

hub.c.163.com/public/logo  latest  6fbdd13cd20411 days ago  585 B  

A lot of techniques for reducing mirroring are used, especially for the optimization and simplification of C programs. But we usually develop more than C language, and even some images are not packaged by ourselves (such as downloading public images), so is there some general way to simplify Docker images? The answer is yes, and even some mirrors can be reduced by 98%. The benefits of reducing the image size are self-evident. It not only saves storage space, but also saves bandwidth and speeds up transmission. Well, then please follow me to learn how to simplify the Docker image step by step.

Layers

Before starting to make a mirror, first understand the principle of mirroring, and the most important concept is the mirror layer (Layers). The mirror layer relies on a series of underlying technologies, such as filesystems, copy-on-write, union mounts, etc. Fortunately, you can learn these technologies in many places, The technical details will not be repeated here.

 

20161027203243

 

In general, you need to keep this in mind:

In a Dockerfile, each instruction creates an image layer, which in turn increases the overall image size.

for example:

FROM busybox

RUN mkdir /tmp/foo

RUN dd if=/dev/zero of=/tmp/foo/bar bs=1048576 count=100

RUN rm /tmp/foo/bar

The above Dockerfile does the following things:

  • Based on an official base image busybox (only more than 1M)
  • Create a folder (/tmp/foo) and a file (bar)
  • 100M size is allocated for the file
  • delete this large file

In fact, it didn't do anything in the end, let's build it into an image to see (build can refer to the first issue):

docker build -t busybox:test .

再让我们来对比下原生的 busybox 镜像大小和我们生成的镜像大小:

$ docker images | grep

busyboxbusybox    test     896c63dbdb96    2 seconds ago    106 MB

busybox    latest   2b8fd9751c4c    9 weeks ago      1.093 MB

出乎意料的是,却生成了 106 MB 的镜像。

多出了 100 M,这是为何?这点和 git 类似(都用到了Copy-On-Write技术),我用 git 做了如下两次提交(添加了又删除),请问 A_VERY_LARGE_FILE 还在 git 仓库中吗?

$ git add  A_VERY_LARGE_FILE

$ git commit

$ git rm  A_VERY_LARGE_FILE

$ git commit

答案是: 在的 ,并且会占用仓库的大小。Git 会保存每一次提交的文件版本,而 Dockerfile 中每一条指令都可能增加整体镜像的大小,即使它最终什么事情都没做。

精简步骤

了解了镜像层知识,有助于我们接下来制作精简镜像。这里开始,以最常用的开源缓存软件 Redis 为例,从一步步试验,来介绍如何制作更精简的 Docker 镜像

步骤 1:初始化构建 Redis 镜像

直接上 Dockerfile :

FROM ubuntu:trusty

ENV VER     3.0.0

ENV TARBALL http://download.redis.io/releases/redis-$VER.tar.gz

# ==> Install curl and helper tools...

RUN apt-get update

RUN apt-get install -y  curl make gcc

# ==> Download, compile, and install...

RUN curl -L $TARBALL | tar zxv

WORKDIR  redis-$VER

RUN make

RUN make install

#...

# ==> Clean up...

WORKDIR /

RUN apt-get remove -y --auto-remove curl make gcc

RUN apt-get clean

RUN rm -rf /var/lib/apt/lists/*  /redis-$VER

#...

CMD ["redis-server"]

结合注释,读起来并不困难,用到的都是常规的几个命令,简要介绍如下:

  • FROM:顶头写,指定一个基础镜像,此处基于 ubuntu:trusty
  • ENV:设置环境变量,这里设置了 VER 和 TARBALL 两个环境变量
  • RUN:最常用的 Dockerfile 指令,用于运行各种命令,这里调用了 8 次 RUN 指令
  • WORKDIR:指定工作目录,相当于指令 cd
  • CMD:指定镜像默认执行的命令,此处默认执行 redis-server 命令来启动 redis

执行构建:

$ docker build  -t redis:lab-1  .

注:国内网络,更新下载可能会较慢

查看大小:

 

20161027203303

 

动辄就有 300多 M 的大小,不能忍,下面我们开始一步步优化。

步骤 2: 优化基础镜像

方法:选用更小的基础镜像。

常用的 Linux 系统镜像一般有 ubuntu、centos、debian,其中debian 更轻量,而且够用,对比如下:

REPOSITORY     TAG        IMAGE ID           VIRTUAL SIZE

---------------           ------          ------------                ------------

centos              7               214a4932132a     215.7 MB

centos              6               f6808a3e4d9e      202.6 MB

ubuntu              trusty       d0955f21bf24      188.3 MB

ubuntu              precise    9c5e4be642b7     131.9 MB

debian              jessie       65688f7c61c4      122.8 MB

debian              wheezy    1265e16d0c28      84.96 MB

替换 debian:jessie 作为我们的基础镜像。

优化 Dockerfile:

FROM debian:jessie

#...

执行构建:

$ docker build  -t redis:lab-2  .

查看大小:

 

20161027203254

 

减少了42M,稍有成效,但并不明显。细心的同学应该发现,只有 122 MB 的 debian 基础镜像,构建后增加到了 305 MB,看来这里面肯定有优化的空间,如何优化就要用到我们开头说到的 Image Layer 知识了。

步骤 3:串联 Dockerfile 指令

方法: 串联你的 Dockerfile 指令(一般是 RUN 指令)。

Dockerfile 中的 RUN 指令通过 && 和 / 支持将命令串联在一起,有时能达到意想不到的精简效果。

优化 Dockerfile:

FROM debian:jessie

ENV VER     3.0.0

ENV TARBALL http://download.redis.io/releases/redis-$VER.tar.gz




RUN echo "==> Install curl and helper tools..."  && \     apt-get update                      && \   

  apt-get install -y  curl make gcc   && \  

  \   

  echo "==> Download, compile, and install..."  && \  

  curl -L $TARBALL | tar zxv  && \   

  cd redis-$VER               && \   

  make                        && \   

  make install                && \   

  ...   

  echo "==> Clean up..."  && \   

  apt-get remove -y --auto-remove curl make gcc  && \

  apt-get clean                                  && \   

  rm -rf /var/lib/apt/lists/*  /redis-$VER




#...

CMD ["redis-server"]

构建:

$ docker build  -t redis:lab-3  .

查看大小:

 

20161027203318

 

哇!一下子减少了 50%,效果明显啊!这是最常用的一个精简手段了。

步骤 4:压缩你的镜像

方法:试着用命令或工具压缩你的镜像。

docker 自带的一些命令还能协助压缩镜像,比如 export 和 import

$ docker run -d redis:lab-3

$ docker export 71b1c0ad0a2b | docker import - redis:lab-4

但麻烦的是需要先将容器运行起来,而且这个过程中你会丢失镜像原有的一些信息,比如:导出端口,环境变量,默认指令。

所以一般通过命令行来精简镜像都是实验性的,那么这里再推荐一个小工具: docker-squash。用起来更简单方便,并且不会丢失原有镜像的自带信息。

下载安装:

https://github.com/jwilder/docker-squash#installation(复制此链接到浏览器打开)

压缩操作:

$ docker save redis:lab-3

  | sudo docker-squash -verbose -t redis:lab-4  \ 

  | docker load

注: 该工具在 Mac 下并不好使,请在 Linux 下使用

对比大小:

 

20161027203328

 

Well, it doesn't look like much from here, so all I can say is try and don't expect too much.


Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326223243&siteId=291194637