1、前言
-
容器镜像中引入了层的概念,用到了一种叫作联合文件系统(Union File System)的能力。Union File System 也叫 UnionFS,最主要的功能是将多个不同位置的目录联合挂载(union mount)到同一个目录下。比如A目录下包含文件a、x,B目录下包含文件b、x,联合挂载后放到了公共目录C上。aufs是一层一层往上盖的,所以A里面的x会覆盖B里面的x。
-
/var/lib/docker/aufs/mnt/ 增量rootfs挂载点
-
这个信息记录在 AuFS (Advance UnionFS)的系统目录 /sys/fs/aufs 下面。首先,通过查看 AuFS 的挂载信息,我们可以找到这个目录对应的 AuFS 的内部 ID(也叫:si),然后使用这个 ID,你就可以在 /sys/fs/aufs 下查看被联合挂载在一起的各个层的信息cat /sys/fs/aufs/si_972c6d361e6b32ba/br[0-9]*。
-
镜像的层都放置在 /var/lib/docker/aufs/diff 目录下,然后被联合挂载在 /var/lib/docker/aufs/mnt 里面。
-
docker run -it ubuntu /bin/bash 此时会有一个隐式的chroot过程
这个chroot的过程是将/bin/bash进程的Home目录切换成了/var/lib/docker/aufs/mnt/
2、mount namespace原理
- 在 Linux 操作系统里,有一个名为 chroot 的命令可以帮助你在 shell 中方便地完成这个工作。顾名思义,它的作用就是帮你“change root file system”,即改变进程的根目录到你指定的位置。
#执行 chroot 命令,告诉操作系统,我们将使用 $HOME/test 目录作为 /bin/bash 进程的根目录 $ chroot $HOME/test /bin/bash
3、docker项目核心原理
-
为待创建的用户进程:
1 启用 Linux Namespace 配置;
2 设置指定的 Cgroups 参数;
3 切换进程的根目录(Change Root)。 -
这样,一个完整的容器就诞生了。不过,Docker 项目在最后一步的切换上会优先使用 pivot_root 系统调用,如果系统不支持,才会使用 chroot。
2、容器镜像rootfs(共享宿主机内核)
-
1、只读层(ro+wh,即 readonly+whiteout)
如果我现在要做的,是删除只读层里的一个文件呢?
AuFS 会在可读写层创建一个 whiteout 文件,把只读层里的文件“遮挡”起来。比如,你要删除只读层里一个名叫 foo 的文件,那么这个删除操作实际上是在可读写层创建了一个名叫.wh.foo 的文件。这样,当这两个层被联合挂载之后,foo 文件就会被.wh.foo 文件“遮挡”起来,“消失”了。这个功能,就是“ro+wh”的挂载方式,即只读 +whiteout 的含义。我喜欢把 whiteout 形象地翻译为:“白障”。 -
2、可读写层
可读写层的作用,就是专门用来存放你修改 rootfs 后产生的增量,无论是增、删、改,都发生在这里。而当我们使用完了这个被修改过的容器之后,还可以使用 docker commit 和 push 指令,保存这个被修改过的可读写层,并上传到 Docker Hub 上,供其他人使用;而与此同时,原先的只读层里的内容则不会有任何变化。这,就是增量 rootfs 的好处。 -
3、init层
Init 层是 Docker 项目单独生成的一个内部层,专门用来存放 /etc/hosts、/etc/resolv.conf 等信息。
需要这样一层的原因是,这些文件本来属于只读的 Ubuntu 镜像的一部分,但是用户往往需要在启动容器时写入一些指定的值比如 hostname,所以就需要在可读写层对它们进行修改。可是,这些修改往往只对当前的容器有效,我们并不希望执行 docker commit 时,把这些信息连同可读写层一起提交掉。所以,Docker 做法是,在修改了这些文件之后,以一个单独的层挂载了出来。而用户执行 docker commit 只会提交可读写层,所以是不包含这些内容的。