CentOS 7

CentOS7下的各种应用


减小 Docker 镜像体积

<p>在构建 Docker 容器时,镜像越小越好,更小的镜像可以更快的传输和部署。最近遇到了 Docker 镜像体积过大的问题,对于部署、移交相当麻烦和慢。下面我以手动编译 nginx 镜像作为例子来减小镜像体积,nginx 的版本是 1.10.2,并且下载到了当前目录。下图是各种 Dockerfile 制作出镜像的效果</p> <pre><code>1、替换基础镜像 1.1 基于 centos 的镜像 1.2 基于 Alpine 的镜像 2、移除 build 依赖的文件 2.1 centos 基础镜像的依赖 2.2 Alpine 基础镜像的依赖 3、减少镜像层级 3.1 centos 3.2 Alpine 3.3 大文件测试 3.3.1 通过 COPY 3.3.2 通过 wget 4、其他 4.1 Python 4.2 通过镜像层级加速 build 过程</code></pre> <h3>1、替换基础镜像</h3> <p>我们的基础镜像是基于 centos 7.X,从官方 hub 拉取的 centos 7 的基础镜像有 194.6MB,这个基础镜像已经相当的大了,所以减小镜像体积的第一步是替换基础镜像。首选的基础镜像是 alpine,这里我选择的是 3.4。</p> <h4>1.1、基于 centos 的镜像</h4> <p>下面是最原始的镜像的 Dockerfile</p> <pre><code class="language-bash">FROM centos:7.2.1511 COPY . /tmp/ RUN yum install -y make \ gcc \ openssl-devel \ zlib-devel \ perl-devel \ pcre-devel &amp;&amp; \ cd /tmp/ &amp;&amp; tar zxf nginx-1.10.2.tar.gz &amp;&amp; \ cd /tmp/nginx-1.10.2 &amp;&amp; \ ./configure --with-http_gzip_static_module --with-http_ssl_module &amp;&amp; \ make &amp;&amp; make install &amp;&amp; \ rm -rf /tmp/* &amp;&amp; \ ln -sf /dev/stdout /usr/local/nginx/logs/access.log &amp;&amp; \ ln -sf /dev/stderr /usr/local/nginx/logs/error.log EXPOSE 80 CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off;"]</code></pre> <p>上述就是一个最基本的 nginx 镜像了,通过 docker build 后,镜像大小是 535.2MB。nginx 的源代码才 890KB,这种镜像,完全是浪费空间。</p> <h4>1.2、基于 Alpine 的镜像</h4> <p>对于 centos 的基础镜像,本身就已经接近 200MB 了,然后 Alpine 的基础镜像才 4.999MB,下面是改为 Alpine 的基础镜像的 Dockerfile</p> <pre><code class="language-bash">FROM alpine:3.4 COPY . /tmp/ RUN apk update &amp;&amp; \ apk add gcc make openssl-dev zlib-dev perl-dev pcre-dev libc-dev &amp;&amp; \ cd /tmp/ &amp;&amp; tar zxf nginx-1.10.2.tar.gz &amp;&amp; \ cd /tmp/nginx-1.10.2 &amp;&amp; \ ./configure --with-http_gzip_static_module --with-http_ssl_module &amp;&amp; \ make &amp;&amp; make install &amp;&amp; \ rm -rf /tmp/* &amp;&amp; \ ln -sf /dev/stdout /usr/local/nginx/logs/access.log &amp;&amp; \ ln -sf /dev/stderr /usr/local/nginx/logs/error.log EXPOSE 80 CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off;"]</code></pre> <p>通过上述的 Dockerfile <code>docker build</code> 出来的镜像大小是 155.8MB,体积已经缩小到了 3 倍以上了,对于 nginx 的运行来说,CentOS 和 Alpine 完全是一样的效果,所以对于基础镜像,首选应该是 Alpine 这之类的精简版系统,而且在官方 hub 上的官方镜像,大多有提供 Alpine 版的版本。</p> <h3>2、移除 build 依赖的文件</h3> <p>有一些软件安装时,可能在编译时会依赖于一些头文件,例如 <code>openssl-dev</code> 这之类的 <code>dev</code> 文件,还有就是 <code>gcc</code> 和 <code>make</code> 这之类的编译工具,在程序运行时完全不需要,所以可以在编译完之后,删除掉,这样可以也是可以减小一定的体积。 </p> <h4>2.1、移除 CentOS 基础镜像的依赖</h4> <pre><code class="language-bash">Dockerfile FROM centos:7.2.1511 COPY . /tmp/ RUN yum install -y make gcc openssl-devel zlib-devel perl-devel pcre-devel &amp;&amp; cd /tmp/ &amp;&amp; tar zxf nginx-1.10.2.tar.gz &amp;&amp; cd /tmp/nginx-1.10.2 &amp;&amp; ./configure --with-http_gzip_static_module --with-http_ssl_module &amp;&amp; make &amp;&amp; make install &amp;&amp; yum remove -y gcc openssl-devel zlib-devel perl-devel pcre-devel make &amp;&amp; yum clean all &amp;&amp; rm -rf /tmp/* &amp;&amp; ln -sf /dev/stdout /usr/local/nginx/logs/access.log &amp;&amp; ln -sf /dev/stderr /usr/local/nginx/logs/error.log EXPOSE 80 CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off;"]</code></pre> <p>上面的 <code>yum remove -y gcc openssl-devel zlib-devel perl-devel pcre-devel make</code> 和 <code>yum clean all</code> 就是移除不需要的文件,从而进一步减小体积,加上两条命令后,执行 <code>docker build</code> 后的镜像的体积为 413.8MB,相对上述的 535.2MB 减小了 121.4 MB。</p> <h4>2.2 移除 Alpine 基础镜像的依赖</h4> <p>上述 centos 的移除依赖的后体积变化可能看着没有啥感觉,因为本身就很大,下面是 Alpine 的 Dockerfile</p> <pre><code class="language-bash">FROM alpine:3.4 COPY . /tmp/ RUN apk update &amp;&amp; \ apk add gcc make openssl-dev zlib-dev perl-dev pcre-dev libc-dev &amp;&amp; \ cd /tmp/ &amp;&amp; tar zxf nginx-1.10.2.tar.gz &amp;&amp; \ cd /tmp/nginx-1.10.2 &amp;&amp; \ ./configure --with-http_gzip_static_module --with-http_ssl_module &amp;&amp; \ make &amp;&amp; make install &amp;&amp; \ apk del gcc make openssl-dev zlib-dev perl-dev pcre-dev libc-dev &amp;&amp; \ rm -rf /var/cache/* &amp;&amp; \ rm -rf /tmp/* &amp;&amp; \ ln -sf /dev/stdout /usr/local/nginx/logs/access.log &amp;&amp; \ ln -sf /dev/stderr /usr/local/nginx/logs/error.log EXPOSE 80 CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off;"]</code></pre> <p>这次 <code>docker build</code> 出来的镜像的体积为 11.74MB,直接从 155.8MB 减小了 144.04 MB,达到了数量级的变化。并且这个 11.74MB 的镜像也是可以正常运行的。</p> <h3>3 减少镜像层级</h3> <p>由于 Docker 镜像的储存原理是分层的,其实 <code>docker build</code> 的过程就是 docker 运行了一个容器,然后执行 Dockerfile 里写的命令。并且每一个命令都会 commit 一下,每一次 commit 都是一层一层的叠加在原来的镜像上,也就是说在某一层里增加了一个文件,在下一层里删除这个文件,是没有任何效果的,镜像体积是不变的,可能反而会增加。所以减小镜像的体积除了替换基础镜像,还需要优化 Dockerfile,减少镜像的层级。 那么对于一些需要通过 COPY 命令的方式拷贝到镜像里面的文件,可以使用 wget 的方式,下载到镜像里,然后使用完之后就删掉。</p> <h4>3.1 CentOS</h4> <p>Dockerfile 如下:</p> <pre><code class="language-bash">FROM centos:7.2.1511 RUN yum install -y make gcc openssl-devel zlib-devel perl-devel pcre-devel wget &amp;&amp; wget --no-check-certificate -O /tmp/nginx-1.10.2.tar.gz http://nginx.org/download/nginx-1.10.2.tar.gz &amp;&amp; cd /tmp/ &amp;&amp; tar zxf nginx-1.10.2.tar.gz &amp;&amp; cd /tmp/nginx-1.10.2 &amp;&amp; ./configure --with-http_gzip_static_module --with-http_ssl_module &amp;&amp; make &amp;&amp; make install &amp;&amp; rm -rf /tmp/* &amp;&amp; ln -sf /dev/stdout /usr/local/nginx/logs/access.log &amp;&amp; ln -sf /dev/stderr /usr/local/nginx/logs/error.log EXPOSE 80 CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off;"]</code></pre> <p>上述通过 wget 的下载方式将 nginx 的源代码下载到了镜像里面,然后使用完之后,再删除掉,这样对于镜像来说,将不会存在 nginx 的源代码。通过此方法 <code>docker build</code> 出来的镜像是 534.8MB,相对于最原始的 535.2MB,少了一丢丢,这种方式随着文件的大小增大,效果显著。</p> <h4>3.2 Alpine</h4> <p>Dockerfile 如下:</p> <pre><code class="language-bash">FROM alpine:3.4 RUN apk update &amp;&amp; \ apk add gcc make openssl-dev zlib-dev perl-dev pcre-dev libc-dev wget &amp;&amp; \ wget --no-check-certificate -O /tmp/nginx-1.10.2.tar.gz http://nginx.org/download/nginx-1.10.2.tar.gz &amp;&amp; \ cd /tmp/ &amp;&amp; tar zxf nginx-1.10.2.tar.gz &amp;&amp; \ cd /tmp/nginx-1.10.2 &amp;&amp; \ ./configure --with-http_gzip_static_module --with-http_ssl_module &amp;&amp; \ make &amp;&amp; make install &amp;&amp; \ rm -rf /tmp/* &amp;&amp; \ ln -sf /dev/stdout /usr/local/nginx/logs/access.log &amp;&amp; \ ln -sf /dev/stderr /usr/local/nginx/logs/error.log EXPOSE 80 CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off;"]</code></pre> <p>通过 <code>docker build</code> 后,镜像大小为 155.4MB,因为 Alpine 的体积本身很小,所以效果不明显。</p> <h4>3.3、大文件测试</h4> <p>为了测试大文件的效果,我通过 dd 生成了一个 2.3GB 的文件,然后我分别通过 copy 的方式和 wget 的方式拷贝文件到镜像,并且移除文件。 </p> <h5>3.3.1 通过COPY</h5> <p>Dockerfile 如下:</p> <pre><code class="language-bash">FROM alpine:3.4 COPY . /code RUN rm -rf /code CMD ["tail", "-f", "/etc/hosts"]</code></pre> <p>基础镜像采用的是 Alpine,对于 2.3GB 来说,基础的镜像的体积可以忽略。<code>docker build</code> 出来的镜像体积是 2.463GB,可以看到,虽然通过 <code>rm -rf /code</code> 将文件删除了,但是由于 docker 镜像是分层的原因,所以镜像的依旧包含了 COPY 进去的文件的体积,虽然文件在 <code>docker run</code> 时是看不到的。</p> <h5>3.3.2 通过 wget</h5> <p>Dockerfile 如下:</p> <pre><code class="language-bash">FROM alpine:3.4 RUN apk update &amp;&amp; apk add wget &amp;&amp; \ mkdir /code &amp;&amp; \ wget --no-check-certificate -O /code/test.dbf http://172.24.4.188:8000/test.dbf &amp;&amp; \ apk del wget &amp;&amp; \ rm -rf /var/cache/* &amp;&amp; \ rm -rf /code CMD ["tail", "-f", "/etc/hosts"]</code></pre> <p>通过此方法 <code>docker build</code> 出来的镜像体积为 4.817MB,相对于 Alpine 的基础镜像 4.799MB,只增加了 0.018MB。相对于上述的 COPY 完全是质的变化。</p> <h3>4 其它</h3> <h4>4.1 Python</h4> <p>对于 Python 来说,在制作镜像时,往往会预先安装依赖的库,在安装的过程中,往往会产生大量的 <code>pyc</code> 和 <code>pyo</code> 文件,这些文件对于镜像来说完全是不需要的,完全可以在镜像成为容器运行时生成,当然,这可能会影响一丢丢启动速度,毕竟文件是需要生成的。所以以时间换空间的话,完全可以移除掉。</p> <p>通过 <code>find / -name "*.py[co]" -exec rm '{}' ';'</code> 就可以全都移除掉。</p> <h4>4.2 镜像层级</h4> <p>通过镜像层级加速 build 过程 有时,在开发的时候,需要频繁的 build 镜像,如果全部在一个 RUN 里来执行,那么每次 build 时,所有的依赖都会安装一遍,这样极其浪费时间,可以通过 docker 镜像分层的原理,将安装依赖的过程放在一层里,然后代码放在最后 COPY 进去,因为一般情况下,都是代码频繁的变动,依赖的软件不会经常变动,这样可以利用 build 时的 cache,加速 build 的过程。</p> <p><a href="https://zhuanlan.zhihu.com/p/42815689">https://zhuanlan.zhihu.com/p/42815689</a></p> <p>7 步精简 Docker 镜像(上) <a href="https://sq.163yun.com/blog/article/155768368569982976">https://sq.163yun.com/blog/article/155768368569982976</a> 7 步精简 Docker 镜像(下) <a href="https://sq.163yun.com/blog/article/155767577746546688">https://sq.163yun.com/blog/article/155767577746546688</a></p> <p><a href="https://sq.163yun.com/blog/article/220631974878703616">https://sq.163yun.com/blog/article/220631974878703616</a></p>

页面列表

ITEM_HTML