联合文件系统(Union File System,UnionFS)
最主要的功能是将多个不同位置的目录联合挂载(union mount)到同一目录。
容器有了进程隔离(视野隔离),CGroup资源隔离,还缺少隔离的文件系统,可认为Unionfs是容器房间里的地板,将多个文件目录挂载给某个容器进程,供其独享。
为了解决该问题,Docker在Ubuntu发行版上默认使用AuFS(Advanced Union FS)支持Docker镜像的Layer,也支持其他UnionFS的版本。
比如,现在有两个目录A、B,分别有俩文件:
$ tree . ├── A │ ├── a │ └── x └── B ├── b └── x
然后使用联合挂载,将这俩目录挂载到一个公共目录C上:
$ mkdir C $ mount -t aufs -o dirs=./A:./B none ./C
再查看目录C的内容,就能看到目录A和B下的文件被合并到了一起:
$ tree ./C ./C ├── a ├── b └── x
可见,在这个合并后的目录C里,有a、b、x三个文件,并且x文件只有一份。这就是“合并”。如果在目录C里对a、b、x文件做修改,这些修改也会在对应的目录A、B中生效。
AuFS全称Another UnionFS,后改名为Alternative UnionFS,再后来干脆改名叫作Advance UnionFS,从这些名字中你应该能看出这样两个事实:
- 对Linux原生UnionFS的重写和改进
- Linus一直不让AuFS进入Linux内核主干,只能在Ubuntu和Debian这些发行版上使用
对于AuFS来说,它最关键的目录结构在/var/lib/docker路径下的diff目录:
/var/lib/docker/aufs/diff/<layer_id>
不同的是,Docker镜像使用的rootfs,往往由多个“层”组成:
docker image inspect ubuntu:latest ... "RootFS": { "Type": "layers", "Layers": [ "sha256:f49017d4d5ce9c0f544c...", "sha256:8f2b771487e9d6354080...", "sha256:ccd4d61916aaa2159429...", "sha256:c01d74f99de40e097c73...", "sha256:268a067217b5fe78e000..." ] }
可以看到,这个Ubuntu镜像,实际上由五个层组成。
这五个层就是五个增量rootfs,每一层都是Ubuntu操作系统文件与目录的一部分;而在使用镜像时,Docker会把这些增量联合挂载在一个统一的挂载点上(等价于前面例子里的“/C”目录)。
这个挂载点就是/var/lib/docker/aufs/mnt/,比如:
/var/lib/docker/aufs/mnt/6e3be5d2ecccae7cc0fcfa2a2f5c89dc21ee30e166be823ceaeba15dce645b3e
不出意外的,这个目录里面正是一个完整的Ubuntu操作系统:
$ ls /var/lib/docker/aufs/mnt/6e3be5d2ecccae7cc0fcfa2a2f5c89dc21ee30e166be823ceaeba15dce645b3e bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
那么,前面提到的五个镜像层,又是如何被联合挂载成这样一个完整的Ubuntu文件系统的呢?
这个信息记录在AuFS的系统目录/sys/fs/aufs下面。
首先,通过查看AuFS的挂载信息,我们可以找到这个目录对应的AuFS的内部ID(也叫:si):
$ cat /proc/mounts| grep aufs none /var/lib/docker/aufs/mnt/6e3be5d2ecccae7cc0fc... aufs rw,relatime,si=972c6d361e6b32ba,dio,dirperm1 0 0
即,si=972c6d361e6b32ba。
然后使用这个ID,你就可以在/sys/fs/aufs下查看被联合挂载在一起的各个层的信息:
$ cat /sys/fs/aufs/si_972c6d361e6b32ba/br[0-9]* /var/lib/docker/aufs/diff/6e3be5d2ecccae7cc...=rw /var/lib/docker/aufs/diff/6e3be5d2ecccae7cc...-init=ro+wh /var/lib/docker/aufs/diff/32e8e20064858c0f2...=ro+wh /var/lib/docker/aufs/diff/2b8858809bce62e62...=ro+wh /var/lib/docker/aufs/diff/20707dce8efc0d267...=ro+wh /var/lib/docker/aufs/diff/72b0744e06247c7d0...=ro+wh /var/lib/docker/aufs/diff/a524a729adadedb90...=ro+wh
从这些信息里,我们可以看到,镜像的层都放置在/var/lib/docker/aufs/diff目录下,然后被联合挂载在/var/lib/docker/aufs/mnt里面。