镜像瘦身:每一层都不能放过
Posted 悟初境
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了镜像瘦身:每一层都不能放过相关的知识,希望对你有一定的参考价值。
网上很多人都说镜像瘦身需要把所有命令放在一条来执行,这没有错,但只是问题表象,没有触及本质。
当我打了一个带源码编译的镜像,结果异常庞大,明明已经删了源码包,为什么还那么大呢?当我想尝试放在一条命令时,简洁理论告诉我这非常不美观,我每个RUN都是一个不同的软件,放在一起不是很混乱吗?可读性变差了,所以一定不是这样的。
镜像瘦身
下面的镜像是为了升级centos7里面的openssl版本为1.1.1,从源码构建。
Dockerfile如下:
ARG BASE_IMAGE=centos:7.6.1810
FROM $BASE_IMAGE
ENV TZ Asia/Shanghai
RUN yum install -y gcc gcc-c++ vim kde-l10n-Chinese bison gettext texinfo make autotool automake \\
wget curl zip unzip bzip2 file sudo readline ncurses which \\
git net-tools man-db man-pages-zh-CN wqy-microhei-fonts bash-completion \\
man-pages && yum clean all && ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
ADD packages.tar /home/
WORKDIR /home/packages
RUN tar -xf make-4.2.1.tar.gz && cd make-4.2.1 && mkdir build && cd build && ../configure --prefix=/usr && make && make install
# 安装openssl1.1.1
RUN tar -xzvf openssl-1.1.1q.tar.gz && cd openssl-1.1.1q \\
&& ./config shared --openssldir=/usr/local/openssl --prefix=/usr/local/openssl \\
&& make && make install \\
&& echo "/usr/local/openssl/lib/" >> /etc/ld.so.conf \\
&& ldconfig
WORKDIR /
RUN rm -rf /home/packages && rm -rf /var/cache/yum/* && rm -rf /var/lib/rpm/__db.* && yum clean all && rm -rf /var/lib/yum/*
WORKDIR /home/finance
瘦身之前
结果镜像大小:810MB,分层查看openssl这一层145MB。
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
centos76 test ca7db4177ae6 9 seconds ago 810MB
$ docker history centos76:test
IMAGE CREATED CREATED BY SIZE COMMENT
ca7db4177ae6 22 seconds ago /bin/sh -c #(nop) WORKDIR /home/finance 0B
903f247275d6 22 seconds ago /bin/sh -c rm -rf /home/packages && rm -rf /… 25.5MB
1dde3ade3113 23 seconds ago /bin/sh -c #(nop) WORKDIR / 0B
416186ebbcaf 2 hours ago /bin/sh -c tar -xzvf openssl-1.1.1q.tar.gz &… 145MB
cb8526206e1e 2 hours ago /bin/sh -c tar -xf make-4.2.1.tar.gz && cd m… 12MB
5fea9247f155 2 hours ago /bin/sh -c #(nop) WORKDIR /home/packages 0B
07e256259d79 2 hours ago /bin/sh -c #(nop) ADD file:9872509742c19c105… 200MB
8e0a944d4532 2 hours ago /bin/sh -c yum install -y gcc gcc-c++ vim kd… 225MB
6a3b6540b169 2 hours ago /bin/sh -c #(nop) ENV TZ=Asia/Shanghai 0B
bbd06e461441 3 hours ago /bin/sh -c #(nop) LABEL maintainer=jimo <ji… 0B
f1cb7c7d58b7 3 years ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
<missing> 3 years ago /bin/sh -c #(nop) LABEL org.label-schema.sc… 0B
<missing> 3 years ago /bin/sh -c #(nop) ADD file:54b004357379717df… 202MB
瘦身之后
只贴了变化的2层,最后都加了删除操作。
RUN tar -xf make-4.2.1.tar.gz && cd make-4.2.1 && mkdir build && cd build && ../configure --prefix=/usr && make && make install && rm -rf *
# 安装openssl1.1.1
RUN tar -xzvf openssl-1.1.1q.tar.gz && cd openssl-1.1.1q \\
&& ./config shared --openssldir=/usr/local/openssl --prefix=/usr/local/openssl \\
&& make && make install \\
&& echo "/usr/local/openssl/lib/" >> /etc/ld.so.conf \\
&& ldconfig && rm -rf *
结果 684MB,可以看到源码编译openssl层变得很小了,只剩下21.6MB。
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
centos76 test c1134e4948d8 54 seconds ago 684MB
$ docker history centos76:test
IMAGE CREATED CREATED BY SIZE COMMENT
c1134e4948d8 4 seconds ago /bin/sh -c #(nop) WORKDIR /home/finance 0B
2ed7d78e8d90 4 seconds ago /bin/sh -c rm -rf /home/packages && rm -rf /… 25.5MB
98c8b13a2b9b 5 seconds ago /bin/sh -c #(nop) WORKDIR / 0B
f278729babc4 5 seconds ago /bin/sh -c tar -xzvf openssl-1.1.1q.tar.gz &… 21.6MB
17bea2739abc 2 minutes ago /bin/sh -c tar -xf make-4.2.1.tar.gz && cd m… 9.51MB
5fea9247f155 2 hours ago /bin/sh -c #(nop) WORKDIR /home/packages 0B
07e256259d79 2 hours ago /bin/sh -c #(nop) ADD file:9872509742c19c105… 200MB
8e0a944d4532 2 hours ago /bin/sh -c yum install -y gcc gcc-c++ vim kd… 225MB
6a3b6540b169 2 hours ago /bin/sh -c #(nop) ENV TZ=Asia/Shanghai 0B
bbd06e461441 3 hours ago /bin/sh -c #(nop) LABEL maintainer=jimo <ji… 0B
f1cb7c7d58b7 3 years ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
<missing> 3 years ago /bin/sh -c #(nop) LABEL org.label-schema.sc… 0B
<missing> 3 years ago /bin/sh -c #(nop) ADD file:54b004357379717df… 202MB
这个优化能有多大
上面的100多MB看起来无所谓吧,但如果你编译过GCC源码,并且最后没有删掉,你就知道这一层有多大了。
下面是我编译GCC9.4.0源码产生的镜像层大小, GCC编译万有6个多G,glibc接近1G,足矣引起重视了。
IMAGE CREATED CREATED BY SIZE COMMENT
17c1edbe5d21 6 minutes ago /bin/sh -c tar -xf glibc-2.33.tar.gz && cd g… 989MB
89d80b8e640f 10 minutes ago /bin/sh -c tar -xvzf gcc-9.4.0.tar.gz && mv … 6.37GB
当在结尾加上 rm -rf *
后,对应的大小变为几百M,这才是质的提升。
IMAGE CREATED CREATED BY SIZE COMMENT
a7e28a9a41aa 2 minutes ago /bin/sh -c tar -xf glibc-2.33.tar.gz && cd g… 382MB
5e0ef78051a0 5 minutes ago /bin/sh -c tar -xvzf gcc-9.4.0.tar.gz && mv … 779MB
对应的Dockerfile如下:
RUN tar -xvzf gcc-9.4.0.tar.gz && mv gmp-6.2.1.tar.xz isl-0.24.tar.gz mpc-1.2.1.tar.gz mpfr-4.1.0.tar.gz gcc-9.4.0/ && cd gcc-9.4.0 && tar -xf gmp-6.2.1.tar.xz && \\
tar -xvzf isl-0.24.tar.gz && \\
tar -xvzf mpc-1.2.1.tar.gz && \\
tar -xvzf mpfr-4.1.0.tar.gz && \\
ln -s gmp-6.2.1 gmp && \\
ln -s isl-0.18 isl && \\
ln -s mpc-1.2.1 mpc && \\
ln -s mpfr-4.1.0 mpfr && \\
mkdir build && cd build && ../configure --prefix=/usr --enable-languages=c,c++ --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --enable-gnu-unique-object --enable-linker-build-id --with-linker-hash-style=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --enable-plugin --enable-default-pie --enable-gnu-indirect-function --with-tune=generic --with-arch_32=x86-64 --build=x86_64-redhat-linux --disable-multilib && make -j $(nproc) && make install-strip
RUN tar -xf glibc-2.33.tar.gz && cd glibc-2.33 && \\
mkdir build && cd build && sed -i 's/$name ne "nss_test1"/$name ne "nss_test1" \\&\\& $name ne "nss_test2"/' ../scripts/test-installation.pl && \\
../configure --prefix=/usr --enable-obsolete-nsl && make -j $(nproc) && make install
总结
除了删除源码包,系统安装包也要每次RUN就清理, 如果有的话:
RUN .... && yum clean all && rm -rf *
RUN .... && yum clean all && rm -rf *
这算是一个基本操作,以前没注意到是因为对docker镜像的Layer理解不够深刻。
- 每一条指令都构成一层
- 每一层都可以看成一个镜像,有唯一的ID
- 每一层可以缓存,并且可以复用
- 所以一层定下来后就不能改变了,改了指令就需要重新构建
在运行时的容器里,所有文件大小不到1G,镜像却有8G,就是因为每一层太大了,虽无用,永留存。
以上是关于镜像瘦身:每一层都不能放过的主要内容,如果未能解决你的问题,请参考以下文章
简析TCP的三次握手与四次分手(TCP协议头部的格式,数据从应用层发下来,会在每一层都会加上头部信息,进行封装,然后再发送到数据接收端)good