docker镜像的层级结构

在下载的过程中我们可以看到docker的镜像好像是在一层一层的在下载,如下图:

  1. docker@boot2docker:~$ docker pull docker.cn/docker/centos:centos6

  2. Pulling repository docker.cn/docker/centos

  3. 70441cac1ed5: Download complete

  4. 511136ea3c5a: Download complete

  5. 5b12ef8fd570: Download complete

  6. Status: Image is up to date for docker.cn/docker/centos:centos6

那么docker的镜像到底是什么呢?我们来解释一下docker的镜像的概念。

docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统就是上文说到的UnionFS。在Docker镜像的最底层是bootfs。这一层与我们典型的Linux/Unix系统是一样的,包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由bootfs转交给内核,此时系统也会卸载bootfs。Docker在bootfs之上的一层是rootfs(根文件系统)。rootfs就是各种不同的操作系统发行版,比如Ubuntu,Centos等等。

docker镜像的层级结构图:

650) this.width=650;" src="http://img.voidcn.com/vcimg/static/loading.png" title="0731016-300x225.png" alt="wKiom1kQC0HSyQTSAAC0Ck3HWew575.png" data-src="https://s4.51cto.com/wyfs02/M00/94/EE/wKiom1kQC0HSyQTSAAC0Ck3HWew575.png">

那么docker的rootfs与传统意义的rootfs不同之处到底是什么呢?

传统的Linux加载bootfs时会先将rootfs设为read-only,然后在系统自检之后将rootfs从read-only改为read-write。然后我们就可以在rootfs上进行写和读的操作了。但docker的镜像却不是这样,他在bootfs自检完毕之后并不会把rootfs的read-only改为read-write。而是利用union mount(UnionFS的一种挂载机制)将一个或多个read-only的rootfs加载到之前的read-only 的rootfs层之上。并在加载了这么多层的rootfs之后,仍然让它看起来只像一个文件系统,在docker的体系里把union mount的这些read-only层的rootfs叫做docker的镜像(image)。请注意,此时的每一层rootfs都是read-only的,也就是说我们此时还不能对其进行操作,那么我们怎样对其进行读写操作呢?

答案是将docker镜像进行实例化,就是上文说的从镜像(image)变成容器(container)的过程,当镜像被实例化为容器之后,系统会为在一层或是多层的read-only的rootfs之上分配一层空的read-write的rootfs。而这个分配的动作是由docker run命令发起的,我们可以用如下命令创建一个容器:

  1. docker run t i docker.cn/docker/centos:centos6 /bin/bash

此时我们已经进入到容器,此处要说明一下,我们使用的docker.cn 的镜像实际上是在dockerHub提供的镜像之上进行了一些修改,来使我们可以更轻松的使用镜像,比如docker.cn 会把/etc/skel/.b* 文件拷贝到/root 目录之下等等,也就是说docker.cn是在空的那层rootfs(read-write)对底层的rootfs(read-only)进行了修改,那么问题来了,上文不是说底层的rootfs是read-only的吗?那为什么docker.cn可以对它进行修改?并且还能把修改后的镜像保存起来?这看起来好像非常的矛盾。

其实这并不矛盾,当我们将一个镜像实例化为一个容器之后,docker会在read-only 的rootfs之上分配一层空的read-write的rootfs,我们对文件系统的改变实际上是在空的这层rootfs(read-write)上发生的。打个比方,如果你想修改一个文件,系统实际上是将这个在read-only层的rootfs的文件拷贝到read-write层的rootfs之中,然后对它进行修改,但read-only层的文件并不会被修改,依然存在于read-only层之中,只不过是在read-write层下被隐藏了。这种模式被称为copy on write。这是unionFS的特性。也是docker的强大之处,为什么说强大呢?它允许镜像被继承,也就是说我们想生成一套虚拟环境不用从零开始了,而只要在一个相对完善的基础环境之上来创建我们的虚拟环境就可以了,比如我们想生成一个具有tomcat环境的镜像,只要在一个装有java环境的镜像之上来创建就可以了。这也是docker便捷性的体现。