这周忙,只能等到现在才能记录一下。
rootfs 分为三层
第一部分,只读层。
它是这个容器的rootfs最下面的五层,对应的正是ubuntu:latest镜像的五层。可以看到,它们的挂载方式都是只读的(ro+wh,即readonly+whiteout,至于什么是whiteout,我下面马上会讲到)。
这时,我们可以分别查看一下这些层的内容:
$ ls /var/lib/docker/aufs/diff/72b0744e06247c7d0…
etc sbin usr var
$ ls /var/lib/docker/aufs/diff/32e8e20064858c0f2…
run
$ ls /var/lib/docker/aufs/diff/a524a729adadedb900…
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
可以看到,这些层,都以增量的方式分别包含了Ubuntu操作系统的一部分。
第二部分,可读写层。
它是这个容器的rootfs最上面的一层(6e3be5d2ecccae7cc),它的挂载方式为:rw,即read write。在没有写入文件之前,这个目录是空的。而一旦在容器里做了写操作,你修改产生的内容就会以增量的方式出现在这个层中。
可是,你有没有想到这样一个问题:如果我现在要做的,是删除只读层里的一个文件呢?
为了实现这样的删除操作,AuFS会在可读写层创建一个whiteout文件,把只读层里的文件“遮挡”起来。
比如,你要删除只读层里一个名叫foo的文件,那么这个删除操作实际上是在可读写层创建了一个名叫.wh.foo的文件。这样,当这两个层被联合挂载之后,foo文件就会被.wh.foo文件“遮挡”起来,“消失”了。这个功能,就是“ro+wh”的挂载方式,即只读+whiteout的含义。我喜欢把whiteout形象地翻译为:“白障”。
所以,最上面这个可读写层的作用,就是专门用来存放你修改rootfs后产生的增量,无论是增、删、改,都发生在这里。而当我们使用完了这个被修改过的容器之后,还可以使用docker commit和push指令,保存这个被修改过的可读写层,并上传到Docker Hub上,供其他人使用;而与此同时,原先的只读层里的内容则不会有任何变化。这,就是增量rootfs的好处。
第三部分,Init层。
它是一个以“-init”结尾的层,夹在只读层和读写层之间。Init层是Docker项目单独生成的一个内部层,专门用来存放/etc/hosts、/etc/resolv.conf等信息。
需要这样一层的原因是,这些文件本来属于只读的Ubuntu镜像的一部分,但是用户往往需要在启动容器时写入一些指定的值比如hostname,所以就需要在可读写层对它们进行修改。
可是,这些修改往往只对当前的容器有效,我们并不希望执行docker commit时,把这些信息连同可读写层一起提交掉。
所以,Docker做法是,在修改了这些文件之后,以一个单独的层挂载了出来。而用户执行docker commit只会提交可读写层,所以是不包含这些内容的。
最终,这7个层都被联合挂载到/var/lib/docker/aufs/mnt目录下,表现为一个完整的Ubuntu操作系统供容器使用。
今天介绍了Linux容器文件系统的实现方式。而这种机制,正是我们经常提到的容器镜像,也叫作:rootfs。它只是一个操作系统的所有文件和目录,并不包含内核,最多也就几百兆。而相比之下,传统虚拟机的镜像大多是一个磁盘的“快照”,磁盘有多大,镜像就至少有多大。
通过结合使用Mount Namespace和rootfs,容器就能够为进程构建出一个完善的文件系统隔离环境。当然,这个功能的实现还必须感谢chroot和pivot_root这两个系统调用切换进程根目录的能力。
而在rootfs的基础上,Docker公司创新性地提出了使用多个增量rootfs联合挂载一个完整rootfs的方案,这就是容器镜像中“层”的概念。
通过“分层镜像”的设计,以Docker镜像为核心,来自不同公司、不同团队的技术人员被紧密地联系在了一起。而且,由于容器镜像的操作是增量式的,这样每次镜像拉取、推送的内容,比原本多个完整的操作系统的大小要小得多;而共享层的存在,可以使得所有这些容器镜像需要的总空间,也比每个镜像的总和要小。这样就使得基于容器镜像的团队协作,要比基于动则几个GB的虚拟机磁盘镜像的协作要敏捷得多。
更重要的是,一旦这个镜像被发布,那么你在全世界的任何一个地方下载这个镜像,得到的内容都完全一致,可以完全复现这个镜像制作者当初的完整环境。这,就是容器技术“强一致性”的重要体现。
而这种价值正是支撑Docker公司在2014~2016年间迅猛发展的核心动力。容器镜像的发明,不仅打通了“开发-测试-部署”流程的每一个环节,更重要的是:
容器镜像将会成为未来软件的主流发布方式。