网上很多人都说镜像瘦身需要把所有命令放在一条来执行,这没有错,但只是问题表象,没有触及本质。
当我打了一个带源码编译的镜像,结果异常庞大,明明已经删了源码包,为什么还那么大呢?当我想尝试放在一条命令时,简洁理论告诉我这非常不美观,我每个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
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
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理解不够深刻。
在运行时的容器里,所有文件大小不到1G,镜像却有8G,就是因为每一层太大了,虽无用,永留存。