<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>dockerfile | 伪架构师</title>
    <link>/tags/dockerfile/</link>
      <atom:link href="/tags/dockerfile/index.xml" rel="self" type="application/rss+xml" />
    <description>dockerfile</description>
    <generator>Source Themes Academic (https://sourcethemes.com/academic/)</generator><language>zh</language><lastBuildDate>Wed, 02 Mar 2016 05:01:53 +0800</lastBuildDate>
    <image>
      <url>/img/logo-wide.png</url>
      <title>dockerfile</title>
      <link>/tags/dockerfile/</link>
    </image>
    
    <item>
      <title>优化 Dockerfile，缩减镜像尺寸</title>
      <link>/post/reduce-image-size-by-dockerfile-optimization/</link>
      <pubDate>Wed, 02 Mar 2016 05:01:53 +0800</pubDate>
      <guid>/post/reduce-image-size-by-dockerfile-optimization/</guid>
      <description>

&lt;p&gt;原文：&lt;a href=&#34;https://blog.replicated.com/refactoring-a-dockerfile-for-image-size/&#34; target=&#34;_blank&#34;&gt;Refactoring a Dockerfile for image size&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Docker 社区最近有一篇关于镜像文件尺寸的&lt;a href=&#34;http://www.iron.io/blog/2016/01/microcontainers-tiny-portable-containers.html&#34; target=&#34;_blank&#34;&gt;文章&lt;/a&gt;。&lt;a href=&#34;https://news.ycombinator.com/item?id=11000827&#34; target=&#34;_blank&#34;&gt;Docker&lt;/a&gt; 和&lt;a href=&#34;https://github.com/docker-library/golang/issues/77#issuecomment-172597368&#34; target=&#34;_blank&#34;&gt;社区&lt;/a&gt;都提倡更小的镜像。下面列出今天 Docker Hub 上的 Top 10 镜像的尺寸（ &lt;a href=&#34;https://medium.com/@mccode/the-misunderstood-docker-tag-latest-af3babfd6375#.nzttiqglh&#34; target=&#34;_blank&#34;&gt;Latest&lt;/a&gt; ）：&lt;/p&gt;

&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;镜像名称&lt;/th&gt;
&lt;th align=&#34;right&#34;&gt;尺寸（MB）&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;

&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;busybox&lt;/td&gt;
&lt;td align=&#34;right&#34;&gt;1&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;ubuntu&lt;/td&gt;
&lt;td align=&#34;right&#34;&gt;188&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;swarm&lt;/td&gt;
&lt;td align=&#34;right&#34;&gt;17&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;nginx&lt;/td&gt;
&lt;td align=&#34;right&#34;&gt;134&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;registry&lt;/td&gt;
&lt;td align=&#34;right&#34;&gt;423&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;redis&lt;/td&gt;
&lt;td align=&#34;right&#34;&gt;151&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;mysql&lt;/td&gt;
&lt;td align=&#34;right&#34;&gt;360&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;mongo&lt;/td&gt;
&lt;td align=&#34;right&#34;&gt;317&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;node&lt;/td&gt;
&lt;td align=&#34;right&#34;&gt;643&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;debian&lt;/td&gt;
&lt;td align=&#34;right&#34;&gt;125&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;使用较小的基础镜像（例如 Alphine Linux, BusyBox 等）有很多好处。这方面有不少相关文档：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://blog.xebia.com/create-the-smallest-possible-docker-container/&#34; target=&#34;_blank&#34;&gt;&lt;strong&gt;Create the smallest possible docker container&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://blog.librato.com/posts/docker-images&#34; target=&#34;_blank&#34;&gt;&lt;strong&gt;Docker Images&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://yasermartinez.com/blog/posts/creating-super-small-docker-images.html&#34; target=&#34;_blank&#34;&gt;&lt;strong&gt;Create super small docker images&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.brianchristner.io/docker-image-base-os-size-comparison/&#34; target=&#34;_blank&#34;&gt;&lt;strong&gt;Docker images base os size comparison&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;所以我假设你已经试用了其中的一个为基础镜像。接下来的事情就取决于操作者控制镜像尺寸的能力了。特别的，我们会验证一些缩减镜像大小的手段的效果，例如把多个 &lt;code&gt;RUN&lt;/code&gt; 指令中的命令集中到一行，一些关于 &lt;code&gt;apt-get&lt;/code&gt; 的技巧（例如移除 apt-get 缓存以及 &lt;code&gt;--no-install-recommends&lt;/code&gt;）&lt;/p&gt;

&lt;h2 id=&#34;在同一行中进行清理工作&#34;&gt;在同一行中进行清理工作&lt;/h2&gt;

&lt;p&gt;Docker 镜像的基础是一种&lt;a href=&#34;https://en.wikipedia.org/wiki/Aufs&#34; target=&#34;_blank&#34;&gt;层次化文件系统&lt;/a&gt;。每一层都只是包含同下面一层不同的部分。在最上方只能看到一个统一视图，而无法获知他的构建历史。Dockerfile 的每一行都会在顶部建立一个新的层。&lt;/p&gt;

&lt;p&gt;例如我们以这样一个 Dockerfile 片段开始：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-dockerfile&#34;&gt;ADD https://storage.googleapis.com/golang/go1.5.3.src.tar.gz /tmp

# do some things with that file

RUN rm /tmp/go1.5.3.src.tar.gz
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;你可以能会觉得删除 &lt;code&gt;.tar.gz&lt;/code&gt; 文件是个负责任的好办法。但是包含这一文件的层还遗留在镜像之中。&lt;code&gt;rm&lt;/code&gt; 操作只是对最终镜像隐藏了这一文件，使用 &lt;code&gt;docker pull&lt;/code&gt; 获取这一镜像时还是会下载这些内容的。&lt;/p&gt;

&lt;p&gt;更好的办法就是把这些操作集中到一行之中，这样就不会提交多个层了。例如，对上面的指令进行简单的改写：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-dockerfile&#34;&gt;RUN curl -o \
        /tmp/go.1.5.3.src.tar.gz \
        https://storage.googleapis.com/golang/go1.5.3.src.tar.gz &amp;amp;&amp;amp; \
      &amp;lt;do some things with the file&amp;gt; &amp;amp;&amp;amp; \
      rm /tmp/go1.5.3.src.tar.gz
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;这样看起来有点丑，不过能够优化镜像尺寸。如果你讨厌这种写法，可以建立一个脚本，然后用 &lt;code&gt;ADD&lt;/code&gt;、&lt;code&gt;RUN&lt;/code&gt; 来在 Dokerfile 中运行。&lt;/p&gt;

&lt;h2 id=&#34;用正确的方式移除-apt-yum-缓存&#34;&gt;用正确的方式移除 apt/yum 缓存&lt;/h2&gt;

&lt;p&gt;多数 Dockerfile 作者都知道应该 &lt;code&gt;apt-get remove&lt;/code&gt; 所有不必要的包。一个例子就是，用 curl/wget 来进行下载安装其他软件。可以事后使用 &lt;code&gt;apt-get remove curl&lt;/code&gt;，但是同上面的例子一样，curl 所在的层已经被封装到镜像之中，因此也应该把删除（包括相关的自动安装的依赖包）工作放到同一行中。&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&#34;一个实际的例子&#34;&gt;一个实际的例子。&lt;/h2&gt;

&lt;p&gt;这是一个简化版本的用于运行 Python 服务的 Dokerfile，我们将对他进行优化。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-dockerfile&#34;&gt;FROM ubuntu:14.04
RUN apt-get update
RUN apt-get install -y curl python-pip

RUN pip install requests

ADD ./my_service.py /my_service.py
ENTRYPOINT [&amp;quot;python&amp;quot;, &amp;quot;/my_service.py&amp;quot;]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;myservice.py&lt;/code&gt; 是一个 Python 脚本：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;#!/usr/bin/python
print &#39;Hello, world!&#39;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;接下来 build 并检查尺寸：&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ sudo docker build -t size .
$ sudo docker images
REPOSITORY      TAG           IMAGE ID            CREATED           VIRTUAL SIZE
size            latest        da8a9be731ac        4 seconds ago     360.5 MB
ubuntu          14.04         6cc0fc2a5ee3        2 weeks ago       187.9 MB
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;188 MB 的基础镜像已经很吓人了，不过更值得注意的是，只是一个 hello-world 的 Python 脚本为什么会导致镜像尺寸倍增。这 360.5 MB 中到底有什么？其中包含了最上一层（本例中是 da8a9be731ac），以及用于建立顶层的所有的层的内容。&lt;/p&gt;

&lt;h3 id=&#34;添加一个清理层&#34;&gt;添加一个清理层&lt;/h3&gt;

&lt;p&gt;我们也许应该做一些清理工作，我们试试这样的 Dockerfile ：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-dockerfile&#34;&gt;FROM ubuntu:14.04
RUN apt-get update
RUN apt-get install -y curl python-pip

RUN pip install requests

## Clean up
RUN apt-get remove -y python-pip curl
RUN rm -rf /var/lib/apt/lists/*

ADD ./my_service.py /my_service.py
ENTRYPOINT [&amp;quot;python&amp;quot;, &amp;quot;/my_service.py&amp;quot;]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Build，然后再看尺寸：&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ sudo docker build -t size .
$ sudo docker images
REPOSITORY      TAG           IMAGE ID            CREATED           VIRTUAL SIZE
size            latest        c6dacdd00660        2 seconds ago     361.3 MB
ubuntu          14.04         6cc0fc2a5ee3        2 weeks ago       187.9 MB
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;事与愿违，镜像更大了。&lt;/p&gt;

&lt;h3 id=&#34;在同一层进行清理&#34;&gt;在同一层进行清理&lt;/h3&gt;

&lt;p&gt;接下来试试把 APT 操作进行合并：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-dockerfile&#34;&gt;FROM ubuntu:14.04
RUN apt-get update &amp;amp;&amp;amp; \
    apt-get install -y curl python-pip &amp;amp;&amp;amp; \
    pip install requests &amp;amp;&amp;amp; \
    apt-get remove -y python-pip curl &amp;amp;&amp;amp; \
    rm -rf /var/lib/apt/lists/*

ADD ./my_service.py /my_service.py
ENTRYPOINT [&amp;quot;python&amp;quot;, &amp;quot;/my_service.py&amp;quot;]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Build 然后查看镜像：&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ sudo docker build -t size .
$ sudo docker images
REPOSITORY      TAG           IMAGE ID            CREATED           VIRTUAL SIZE
size            latest        e531f8674f33        9 seconds ago     338 MB
ubuntu          14.04         6cc0fc2a5ee3        2 weeks ago       187.9 MB
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;果然小了一点点 —— 只是一点点。&lt;/p&gt;

&lt;h3 id=&#34;进一步优化-apt&#34;&gt;进一步优化 APT&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;apt-get install&lt;/code&gt; 过程中加入了很多 &lt;code&gt;推荐&lt;/code&gt; 内容。&lt;a href=&#34;http://unix.stackexchange.com/questions/77053/apt-installing-more-packages-than-specified-as-dependencies&#34; target=&#34;_blank&#34;&gt;推荐包&lt;/a&gt;只是简单的加入了一些可有可无的依赖。有些用户会因为特殊的应用方式，或者环境要求才需要这些东西，换句话说，这些推荐内容并非必要。&lt;/p&gt;

&lt;p&gt;在 Ubuntu 14.04 中运行 PIP，很容易就可以得出结论：删除推荐包并不会有什么副作用。这一点在产品发布之前是完全可以确认的。可以在 Docker Hub 上看看 &lt;a href=&#34;https://github.com/docker-library/redis/blob/b375650fb69b7db819e90c0033433c705b28656e/3.0/Dockerfile#L6&#34; target=&#34;_blank&#34;&gt;redis&lt;/a&gt;，&lt;a href=&#34;https://github.com/docker-library/mysql/blob/ed198ce2e8aa78613c615f20c5c4dd09fa450f66/5.7/Dockerfile#L13&#34; target=&#34;_blank&#34;&gt;mysql&lt;/a&gt;，&lt;a href=&#34;https://github.com/docker-library/mongo/blob/7da0e6d6520607c99d40cf71a2e4b0a2da0beca9/3.2/Dockerfile#L7&#34; target=&#34;_blank&#34;&gt;mongo&lt;/a&gt;，&lt;a href=&#34;https://github.com/docker-library/postgres/blob/916a840510b481e7d3f0f74fa04fde3edfdfbd04/9.5/Dockerfile#L9&#34; target=&#34;_blank&#34;&gt;postgres&lt;/a&gt;，&lt;a href=&#34;https://github.com/docker-library/elasticsearch/blob/5b2bf54e2c17a8e2e1b062ea0d071eae600bfec2/2.2/Dockerfile#L23&#34; target=&#34;_blank&#34;&gt;elasticsearch&lt;/a&gt; 等的镜像，使用这一技巧来缩减镜像尺寸。&lt;/p&gt;

&lt;p&gt;实际操作一下带有 &lt;code&gt;--no-install-recommends&lt;/code&gt; 选项的 APT-GET：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-dockerfile&#34;&gt;FROM ubuntu:14.04
RUN apt-get update &amp;amp;&amp;amp; \
    apt-get install -y --no-install-recommends curl python-pip &amp;amp;&amp;amp; \
    pip install requests &amp;amp;&amp;amp; \
    apt-get remove -y python-pip curl &amp;amp;&amp;amp; \
    rm -rf /var/lib/apt/lists/*

ADD ./my_service.py /my_service.py
ENTRYPOINT [&amp;quot;python&amp;quot;, &amp;quot;/my_service.py&amp;quot;]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Build，再次检查尺寸：&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;REPOSITORY      TAG           IMAGE ID            CREATED           VIRTUAL SIZE
size            latest        fddc30aee4dc        6 seconds ago     229.2 MB
ubuntu          14.04         6cc0fc2a5ee3        2 weeks ago       187.9 MB
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;这次我们把镜像缩小了 120 MB。&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;Dockerfile 的语法非常简单，也同样有优化的需求，因此在组织中应用 Docker 时，需要为 Dockerfile 建立健全相应的策略来优化这一过程。&lt;/p&gt;
</description>
    </item>
    
  </channel>
</rss>
