从容器中使用rm命令删除文件后,为什么虚拟大小仍然保持不变?

8
我希望了解更多关于Docker的知识。我是个初学者,对Docker和Linux都非常陌生。因为我的英语不是很好,所以我复制了终端输出的内容。 我有一个大小为516MB的镜像VIRTUAL SIZE。 我在容器中启动bash,并使用wget下载了26MB的数据。下载完成后,我通过commit命令创建了一个新的镜像并保存了所做的更改。此时,镜像的VIRTUAL SIZE为542.5MB,这是正确的。 之后,我再次启动bash,并将该文件删除。但是,当我提交更改后,镜像的VIRTUAL SIZE增加到了542.8MB。 您能告诉我原因吗? 本地镜像:
[fedora_user@fedora-vm ~]$ docker images
REPOSITORY             TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
tester/mytestfedora   latest              c0ca83567bdd        4 seconds ago       516 MB
fedora                 latest              834629358fe2        3 months ago        241.3 MB

使用最小的一个并下载文件:
[fedora_user@fedora-vm ~]$ docker run -i -t tester/mytestfedora /bin/bash
bash-4.3# su dockeres
[dockeres@05ef6e284e32 /]$ cd /home/dockeres/downloads/    
[dockeres@05ef6e284e32 downloads]$ wget https://dl.dropboxusercontent.com/u/827503/0_TEMP/Riverbed.zip
--2015-03-31 19:24:47--  https://dl.dropboxusercontent.com/u/827503/0_TEMP/Riverbed.zip
Resolving dl.dropboxusercontent.com (dl.dropboxusercontent.com)... 54.243.97.104, 54.243.80.193, 50.16.185.28, ...
Connecting to dl.dropboxusercontent.com (dl.dropboxusercontent.com)|54.243.97.104|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 26177252 (25M) [application/zip]
Saving to: 'Riverbed.zip'
Riverbed.zip                      100%[==============================================================>]  24.96M  3.66MB/s   in 14s    
2015-03-31 19:25:03 (1.78 MB/s) - 'Riverbed.zip' saved [26177252/26177252]
[dockeres@05ef6e284e32 downloads]$ exit
bash-4.3# exit

列出活动的容器并从其中创建一个新镜像,以反映容器的变化:
[fedora_user@fedora-vm ~]$ docker ps -all
CONTAINER ID        IMAGE                         COMMAND             CREATED             STATUS                     PORTS               NAMES
05ef6e284e32        tester/mytestfedora:latest   "/bin/bash"         2 minutes ago       Exited (0) 6 seconds ago                       sick_einstein       
[fedora_user@fedora-vm ~]$ docker commit 05ef6e284e32 tester/mytestfedora
f122b12e94a32d477f2f2f18c5a5190a9ad5d349109933da65a0cfeff448c822
[fedora_user@fedora-vm ~]$ docker images
REPOSITORY             TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
tester/mytestfedora   latest              f122b12e94a3        5 seconds ago       542.5 MB
fedora                 latest              834629358fe2        3 months ago        241.3 MB

再次访问并删除已下载的文件:

[fedora_user@fedora-vm ~]$ docker run -i -t tester/mytestfedora /bin/bash
[dockeres@fb5ba36692f0 /]$ cd /home/dockeres/downloads/             
[dockeres@fb5ba36692f0 downloads]$ rm -f Riverbed.zip              
[dockeres@fb5ba36692f0 downloads]$ ls
[dockeres@fb5ba36692f0 downloads]$ exit
bash-4.3# exit

再次列出活动的容器并从它的更改中创建一个新的镜像:

[fedora_user@fedora-vm ~]$ docker ps -all
CONTAINER ID        IMAGE                         COMMAND             CREATED             STATUS                     PORTS               NAMES
fb5ba36692f0        tester/mytestfedora:latest   "/bin/bash"         51 seconds ago      Exited (0) 5 seconds ago                       goofy_yalow         
[fedora_user@fedora-vm ~]$ docker commit fb5ba36692f0 tester/mytestfedora
f744e248576d7fa434768a1e1d25625a9654020fe77e12306f304ff5d5ad3e3b
[fedora_user@fedora-vm ~]$ docker images
REPOSITORY             TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
tester/mytestfedora   latest              f744e248576d        3 seconds ago       542.8 MB
fedora                 latest              834629358fe2        3 months ago        241.3 MB

感谢您提前提供的任何帮助。Ed
3个回答

10
Docker使用联合文件系统进行层级管理。每个RUN命令都会创建一个新的层级,运行容器时的提交也会产生新的层级。镜像由特定层级及其所有祖先层级组成。这就是虚拟大小。因此,层级中的虚拟大小是单调递增的。您的wget创建了一个新层级,您的rm也创建了一个新层级,尽管文件的联合(例如,du -hs /)具有较小的大小。

2
这就是为什么我从不在运行命令中添加大的临时文件 - 我会在同一个命令中下载、解压和删除文件 - 我的大多数Dockerfile都只有单个运行命令。 - ISanych
你在添加文件后进行了提交。之后无论你做什么都不会使图像变小。[fedora_user@fedora-vm ~]$ docker commit 05ef6e284e32 tester/mytestfedora f122b12e94a32d477f2f2f18c5a5190a9ad5d349109933da65a0cfeff448c822 - seanmcl
亲爱的seanmcl,感谢您给我的启示,我明白为什么它会这样工作了。我在添加文件后提交了,然后在删除文件后再次提交了。我该怎么做才能使图像变小呢?亲爱的ISanych,感谢您的建议。我喜欢获取一个jboss zip包并删除zip文件。我尝试了这个命令“cd /usr/etc/ && wget http://download.jboss.org/jboss.../jboss-as-7.1.1.Final.zip && unzip jboss-as-7.1.1.Final.zip && rm -f jboss-as-7.1.1.Final.zip”,但是当我在容器中逐步执行时,大小相同。我应该如何将我的命令连接成一个命令? - los.adrian
你需要重新构建镜像。使用提交构建不可扩展。使用Dockerfile编写命令,这样重新构建就很容易了。 - seanmcl
@edfromhadria,您表现出很好的掌握能力,但在其他地方做错了什么,我已经添加了答案和测试,因为它太大了无法在评论中显示。 - ISanych
我创建了一个Dockerfile。 FROM fedora MAINTAINER edfromhadria <edfromhadria@example.com> RUN su -c 'yum -y install unzip' && su -c 'yum -y install wget' && mkdir /usr/etc && cd /usr/etc/ && wget http://download.jboss.org/jbossas/7.1/jboss-as-7.1.1.Final/jboss-as-7.1.1.Final.zip && unzip jboss-as-7.1.1.Final.zip && rm -rf jboss-as-7.1.1.Final.zip 这个镜像大小是609.5 MB。没有Dockerfile的镜像大小是:610.2 MB。我做错了什么? - los.adrian

8

因为评论内容太长,所以请在评论中回答。

单个命令

FROM ubuntu

RUN echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections \
 && apt-get -qq update \
 && apt-get -qq -y install wget unzip \
 && mkdir /usr/etc \
 && cd /usr/etc \
 && wget -nv -O /tmp/jboss.zip http://download.jboss.org/jbossas/7.1/jboss-as-7.1.1.Final/jboss-as-7.1.1.Final.zip \
 && unzip /tmp/jboss.zip \
 && apt-get clean \
 && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

更小的文件:

$ docker build -t test1 .
$ docker images | grep test1
test1 356 MB

分离命令:

FROM ubuntu

RUN echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections && apt-get -qq update && apt-get -qq -y install wget unzip
RUN wget -nv -O /tmp/jboss.zip http://download.jboss.org/jbossas/7.1/jboss-as-7.1.1.Final/jboss-as-7.1.1.Final.zip
RUN mkdir /usr/etc
RUN cd /usr/etc && unzip /tmp/jboss.zip
RUN apt-get clean
RUN rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

更大的图片:

$ docker build -t test2 .
$ docker images | grep test2
test2 510 MB

亲爱的ISanych!根据您的示例,我创建了以下代码:FROM fedora RUN su -c 'yum -y install unzip'
&& su -c 'yum -y install wget'
&& mkdir /usr/etc
&& cd /usr/etc
&& wget -nv -O /tmp/jboss.zip http://download.jboss.org/jbossas/7.1/jboss-as-7.1.1.Final/jboss-as-7.1.1.Final.zip
&& unzip /tmp/jboss.zip
&& yum clean all
&& rm -rf /var/cache/yum/x86_64/21/* /tmp/* /var/tmp/*现在使用这段代码,我已经达到了442.6 MB!这是最优的,因为在wget、unzip安装之后,没有jboss下载,大小为281.3 MB。JBoss解压缩后的大小为:~160MB(+280=440)!谢谢ISanych,seanmcl!
- los.adrian
1
顺便提一下,Dockerfile(以及容器内的命令)是在root用户下执行的,除非您创建并指定了用户。因此,最好使用以下命令:yum -y install unzip wget,而不是su -c 'yum -y install unzip' \ && su -c 'yum -y install wget'。 - ISanych
1
还有一件事:440Mb是所有层的完整大小。Fedora镜像为240Mb,因此您的层为200Mb。如果您基于Fedora创建不同的镜像,则这个240Mb的镜像将在所有镜像之间共享。此外,如果您基于此创建了几个其他容器,则它们也将共享所有层。Docker真的很酷-祝你好运。 - ISanych
我明白了!在得到这些信息后,我开始创建一个基础、一个JDK和一个JBoss镜像,一个接一个地构建。太好了,知道了这个!非常感谢! - los.adrian

0
抱歉,我的英文不好,我使用了机器翻译。
如果您需要在容器中删除大量空间,可以考虑以下方法。
您可以使用docker exportdocker import来去除旧镜像的历史层。
假设您现在有一个运行在旧镜像中的容器B。
A. 您已经在容器中删除了一些文件 B. 现在您需要将这个容器B导出为tar文件,并导入一个新的镜像 C. docker export -o your.tar containerID docker import your.tar new-image 您会注意到,无论是tar文件还是新镜像C都比旧镜像要小得多。

最好删除非英文字符。 - KennetsuR

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接