Post

镜像文件系统重构

本文主要描述了如何解决Docker镜像中文件删除后仍然占用空间的问题,以及如何通过重构镜像来减少其体积。

镜像文件系统重构
  • 由于docker的分层存储,被删除的文件一直存在于分层架构中,只是被标记为删除罢了
  • 可以使用docker history [img_name]指令来看目标镜像的分层架构
  • 使用docker images [img_name]查看镜像大小
  • 解决方式是使用export/import来重构文件分层
  • 重构文件系统会丢失cmd/端口/等元信息

1.首先准备测试用的dockerfile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# docker build -t t1 .

FROM ubuntu
# 快速安装,无人值守模式
ENV DEBIAN_FRONTEND=noninteractive
# 申请端口
EXPOSE 22


# 运行安装脚本
# RUN bash /tmp/run.sh
RUN dd if=/dev/zero of=100M.bin count=1 bs=100MB
RUN dd if=/dev/zero of=10M.bin count=1 bs=10MB
RUN rm 100M.bin

CMD ["bash"]
  • 这里使用docker build -t t1 .指令构建为镜像t1

2.体积计算

  1. 假设:已知ubuntu的初始大小为72.8MB
  2. 那么这个image理论的大小应该是72.8+100+10-100=82.8MB
  3. 可实际上却是72.8+100+10=182.8M
1
2
3
# docker images t1
REPOSITORY   TAG       IMAGE ID       CREATED         SIZE
t1           latest    7dc3c4768c6e   2 minutes ago   183MB
  1. 再看来一下文件分层
1
2
3
4
5
6
7
8
9
10
11
# docker history t1
│IMAGE          CREATED         CREATED BY                                      SIZE      COMM
│ENT
│7dc3c4768c6e   3 minutes ago   /bin/sh -c #(nop)  CMD ["bash"]                 0B
│f7977abaef92   3 minutes ago   /bin/sh -c rm 100M.bin                          0B
│847d68ab1484   3 minutes ago   /bin/sh -c dd if=/dev/zero of=10M.bin count=…   10MB
│62baa88f2d83   3 minutes ago   /bin/sh -c dd if=/dev/zero of=100M.bin count…   100MB
│2bbf0d43850b   3 minutes ago   /bin/sh -c #(nop)  EXPOSE 22                    0B
│a6e876477399   3 minutes ago   /bin/sh -c #(nop)  ENV DEBIAN_FRONTEND=nonin…   0B
│ba6acccedd29   2 months ago    /bin/sh -c #(nop)  CMD ["bash"]                 0B
│<missing>      2 months ago    /bin/sh -c #(nop) ADD file:5d68d27cc15a80653…   72.8MB
  • 可以发现rm 100M.bin并没有真正的删除文件

3.解决方案

真正的解决办法是先初始化为实例,然后直接重新导出导入.这样才能重构文件分层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 重构文件分层
function mini_images()
{
   # 原始镜像名称
   src=$1
   
   # 临时容器名称,不要和已有容器冲突
   dk_tmp=cv.by.kms.app
   
   # 首先实例化容器
   docker create -it -P --name $dk_tmp $src
   
   # 接着导出容器
   docker export $dk_tmp -o $dk_tmp.tar
   # docker export $dk_tmp |gzip > $dk_tmp.tar.gz
   
   # 删除原始镜像以及临时容器
   docker rm $dk_tmp
   docker rmi $src
   # 重新导入
   docker import $dk_tmp.tar $src
   rm $dk_tmp.tar
   # show一下结果
   docker images $src
}
   
# 参数: 原始镜像名称(希望重构的镜像)
mini_images t1
  • 重构之后再使用docker images t1可以发现体积如愿的缩小到82.8MB
1
2
3
# docker images t1
REPOSITORY   TAG       IMAGE ID       CREATED          SIZE
t1           latest    3f18764312ee   58 seconds ago   82.8MB

4.说明

重构文件系统会丢失cmd等信息,需要配合dockerfile重新构建.只适合作为基础镜像

可以使用inspect+jq的方式来查看原始镜像/容器的启动信息

1
2
docker inspect t1|jq .[0]|jq .Config.Cmd 
docker inspect t1|jq .[0]|jq .Config.Entrypoint 
This post is licensed under CC BY 4.0 by the author.