docker镜像极致压缩(二)
之前在一篇文章中提到 如何在编译镜像的时候尽量缩小镜像的体积 以用于网络传输,这次在构建另一个镜像的时候,采用了更为激进的办法,直接将原来4G的镜像,缩小到了1G左右,压缩更明显,图片见对比。
抛开场景谈需求都是耍流氓
- 原来的镜像用了很多年了,且是基于 CentOS 7 为基础的,早就不维护了,现在各甲方对这方面越来越注重
- 各种库的版本很低,同1
- 原来的镜像各种乱七八糟的软件安装了一大堆,导致体积很大,docker images 有4个多G,压缩后还有2G多,传输难
为什么不使用 docker-compose ,为什么要把这些软件全部安装到镜像内,这里就不作过多讨论了
直接开整
总的来说,就是2点,分别是:
- “阅后即焚”
- “一次操作”
这两点都很好理解,阅后即焚,是在之前聊过的减少层数这个基础上,把每一层创建好之后,不需要的东西删掉,因为一层的内容创建好之后,体积就相对固定了,下面一层再去删除,是无法改变原有镜像大小的,例如,通过FROM ubuntu:22.04
来使用ubuntu的镜像,然后在接下来编译的过程中,删除镜像的文件,并不会对最后的镜像大小产生影响
所以,在通过 RUN 命令进行操作的时候,可以合并多个一起执行,这样就避免了创建很多层,并且在命令的最后,把用过的东西删除掉,例如:
# 安装需要的软件
RUN apt-get install -y gcc && \
apt-get install -y g++ && \
apt-get install -y libaio1 && \
apt-get install -y numactl && \
apt-get install -y unzip && \
apt-get install -y wget && \
apt-get install -y zlib1g && \
apt-get install -y zlib1g-dev && \
apt-get install -y libpcre3-dev && \
apt-get install -y libssl-dev && \
apt-get install -y pkg-config && \
apt-get install -y make && \
apt-get clean
以上的dockerfile中,就会在安装软件后,通过apt-get clean命令,清理掉多余的安装包。
那么“一次操作”是什么意思,这个是相对可读性比较低的做法,就是写一个shell脚本,把编译过程中大部分的操作,都放到脚本内执行,举例说明:例如镜像内需要安装tomcat、jdk、编译nginx、redis等一系列操作,原来的做法是,在dockerfile中,分别COPY这些文件到镜像内,然后在解压,安装,无形中多多产生层,并且COPY进去的压缩包或者文件就永久留下来了,那么修改之后的代码是这样的:
Dockerfile文件
# 把安装脚本拷贝进去
COPY ./install.sh /root
#如果要拷贝进去,就解锁这一步
#COPY ./packages /root/packages
#安装各种软件
RUN cd /root && ./install.sh
install.sh文件
installAll(){
check_dir_create "$packages_dir"
cd /root/packages
wget -P $packages_dir -O $emqx_name "http://192.168.100.190:8866/share-fileManagement/$emqx_name?shareID=xve7SsuW4ygxi9M"
wget -P $packages_dir -O $tomcat_name "http://192.168.100.190:8866/share-fileManagement/$tomcat_name?shareID=HxE9ZO24k3U7b76"
wget -P $packages_dir -O $jdk_name "http://192.168.100.190:8866/share-fileManagement/$jdk_name?shareID=Ujj0vJtyKryDd0r"
wget -P $packages_dir -O $nginx_name "http://192.168.100.190:8866/share-fileManagement/$nginx_name?shareID=QFHkyW8nJdRmdgC"
wget -P $packages_dir -O $redis_name "http://192.168.100.190:8866/share-fileManagement/$redis_name?shareID=curT9iwnYTC98ir"
wget -P $packages_dir -O $mysql_name "http://192.168.100.190:8866/share-fileManagement/mysql-8.0.35-linux-glibc2.28-x86_64.tar.gz?shareID=NMnNWTxym09Xpf6"
install_emqx
install_mysql
install_nginx
install_redis
install_tomcat
install_jdk
rm -rf /root/install.sh /root/temp /root/packages
}
installAll
这样的做法有如下好处:
- 避免了通过在dockerfile中使用COPY指令复制压缩包到镜像内,然后产生永久的文件
- 通过一个install.sh 文件完成所有软件的安装,可以对安装文件进行集中管理,并且在一个RUN指令中,通过install.sh 脚本中的各种删除,也不会残留在镜像内,
可以看2个镜像的history进行对比,新的镜像在编译的时候,通过.install.sh 安装脚本内的代码进行远程下载,并且在下载安装完成后删除了这些安装包,这样,dockerfile中的安装命令RUN cd /root && ./install.sh
就只产生了应该有的大小
以上就是本次镜像压缩的全部过程了。