基于大Docker基础镜像生成更小镜像的可行性及问题咨询
为什么删除Docker镜像里的包后体积没变化?怎么缩小镜像?
这问题我太懂了!很多人第一次折腾Docker都会踩这个坑——明明在构建时删了好大一堆包,结果镜像体积纹丝不动,核心原因就是Docker的分层存储机制。
先搞懂为啥删了文件体积不变
Docker镜像是由一层层只读的镜像层叠加出来的,每一条RUN命令都会生成一个新的镜像层。你用apt remove或者rm删文件的时候,其实只是在新的层里给这些文件打了个“已删除”的标记,但原来的基础镜像层里的文件还完完整整地存在着。镜像的总大小是所有层的大小加起来,所以哪怕你删了20MB的内容,原来100MB的基础层还在,总大小自然没变化。
可行的缩小镜像方法
针对你这种可选基础镜像都是大体积通用镜像的场景,这两个方法最实用:
把安装和清理命令合并到同一个RUN层
绝对不要把安装和清理分成两条RUN命令,比如这种错误示范:RUN apt-get update && apt-get install -y heavy-package RUN apt-get remove -y heavy-package && apt-get clean正确的做法是把所有相关操作塞进同一条
RUN,这样所有操作都在同一个镜像层里完成,清理后的状态会被直接打包,不会留下之前安装包的痕迹:RUN apt-get update && \ apt-get install -y heavy-package && \ # 这里放你需要用这个包完成的操作,比如编译、处理文件等 apt-get remove -y heavy-package && \ apt-get clean && \ rm -rf /var/lib/apt/lists/*用多阶段构建彻底剥离冗余
这是我最推荐的方案,尤其适合需要先安装依赖做构建,再只保留最终产物的场景。比如:# 第一阶段:用大基础镜像做构建工作,这个阶段的层不会进最终镜像 FROM big-base-image as builder RUN apt-get update && apt-get install -y build-essential some-tools COPY ./source-code /app RUN cd /app && make build # 假设这是生成最终产物的命令 # 第二阶段:只从builder阶段复制需要的产物,基础镜像还是你只能用的那个大镜像 FROM big-base-image COPY --from=builder /app/final-product /usr/local/bin/ # 现在最终镜像里只有基础镜像+这个产物层,builder阶段的所有冗余都被抛弃了别忘了清理各种缓存文件
除了包管理的清理,还要顺手删掉系统里的临时文件,比如:rm -rf /var/lib/apt/lists/*(apt的下载缓存)rm -rf /tmp/* /var/tmp/*(系统临时目录)- 如果用yum的话,加上
yum clean all && rm -rf /var/cache/yum
按照这些方法操作,你肯定能把基于大基础镜像的新镜像体积压到最小,甚至可能比你预期的还小!
内容的提问来源于stack exchange,提问作者Prakash




