通过镜像的文件系统,我们知道了文件系统,联合文件系统,镜像分层,镜像元数据,镜像分层后的各层文件存储;
那么镜像运行成容器后,存于何处呢?
一个容器完整的层应由三个部分组成:
镜像层:也称为rootfs,提供容器启动的文件系统。rootfs也就是我们上一节中分析的image文件。镜像层属于roLayer。
init层: 用于修改容器中一些文件如/etc/hostname,/etc/hosts,/etc/resolv.conf等。init层属于mountedLayer。
容器层:使用联合挂载统一给用户提供的可读写目录。容器层属于mountedLayer。
因为镜像一般都是只读的,修改在容器层;
运行一个容器:docker run -it --name test ubuntu /bin/bash
我们来看一下mountedLayer的元数据目录:
cd /var/lib/docker/image/overlay2/layerdb/mounts && ls
f355cfb27b74a08589322650f7570f7bebb9fd3b7d6ae2a55fda60044f5b6dfa
[root@VM-12-7-centos mounts]# tree
.
`-- f355cfb27b74a08589322650f7570f7bebb9fd3b7d6ae2a55fda60044f5b6dfa
|-- init-id
|-- mount-id
`-- parent
cat init-id
4718d46203109184ad2876462456ac651312ed933dee3898179ddfc711fa9164-init
cat mount-id
4718d46203109184ad2876462456ac651312ed933dee3898179ddfc711fa9164
cat parent
sha256:0214f4b057d78b44fd12702828152f67c0ce115f9346acc63acdf997cab7e7c8
可以看到该文件夹有3种文件:
mount-id:存储在/var/lib/docker/overlay2/的目录名称。
init-id:initID是在mountID后加了一个-init,同时initID就是存储在/var/lib/docker/overlay2/的目录名称。
parent:容器所基于的镜像的最上层的chain_id。(注意这个parent和镜像Layer元数据的parent的不同之处)
我们再来看看/var/lib/docker/overlay2/下的内容
[root@VM-12-7-centos mounts]# ll /var/lib/docker/overlay2/
total 28
2fe7941e58c703d680c08c074bd73df87aabc4d65a61f267b2314301e7ace5d2
31c568526ac00784db29f2581eb501d0b2861526c092c721a22b8c59db8318e5
4718d46203109184ad2876462456ac651312ed933dee3898179ddfc711fa9164
4718d46203109184ad2876462456ac651312ed933dee3898179ddfc711fa9164-init
59b99b583de5c6e507325415775c77f1096ae885814713ebf40a740a5bcfac0e
9e039848a3fd3dd1b5f32f3fa9951772619701697313eb71ea7e21b64986c82c
我们发现新增了4718d46203109184ad2876462456ac651312ed933dee3898179ddfc711fa91644718d46203109184ad2876462456ac651312ed933dee3898179ddfc711fa9164-init两个哈希值的文件夹
并且目录名和mount-id,init-id的内容一致;
再分别看一下4718d46203109184ad2876462456ac651312ed933dee3898179ddfc711fa91644718d46203109184ad2876462456ac651312ed933dee3898179ddfc711fa9164-init
cd 4718d46203109184ad2876462456ac651312ed933dee3898179ddfc711fa9164-init/
tree
.
|-- committed
|-- diff
| |-- dev
| | `-- console
| `-- etc
| |-- hostname
| |-- hosts
| |-- mtab -> /proc/mounts
| `-- resolv.conf
|-- link
|-- lower
`-- work
`-- work
我们看到,diff里面只有一些/etc/hosts、/etc/resolv.conf等配置文件。需要这一层的原因是当容器启动时候,这些本该属于image层的文件或目录,比如hostname,用户需要修改,但是image层又不允许修改,所以启动时候通过单独挂载一层init层,通过修改init层中的文件达到修改这些文件目的。而这些修改往往只读当前容器生效,而在docker commit提交为镜像时候,并不会将init层提交。
再来看看容器层的内容:
cd 4718d46203109184ad2876462456ac651312ed933dee3898179ddfc711fa9164
ls
diff link lower merged work
ll diff
total 0
ls merged/
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
我们可以看到merged目录就是容器内部进程所看到的文件目录,他是由镜像层,init层与容器层联合挂载而来的。就跟之前我们举的联合挂载系统的例子一样;
另外可以看到diff文件夹是空的,说明容器还未对文件进行任何修改。如果修改,diff目录会相应发生变化;
如在容器中新增test.txt文件
docker run -it --name myubuntu ubuntu:16.04 /bin/sh
# ls
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
# cd /opt
# ls
# touch test.txt
查看diff变化:
cd diff/
[root@VM-12-7-centos diff]# ls
opt
[root@VM-12-7-centos diff]# cd opt/
[root@VM-12-7-centos opt]# ls
test.txt
总结
容器的文件系统是在底层的容器的基础上使用联合挂载新增了一层读写层(分层);并使用了写时复制技术;
![](https://img-blog.csdnimg.cn/img_convert/8a85a37c616f5ac29941a6c63d014725.png)