Docker镜像(Images) 的主要特点是,分层、写时复制、内容寻址 和 联合挂载。
docker镜像(Images) 是采用分层的方式构建的,每个镜像都由一系列的 “镜像层” 组成。分层结构是 docker 镜像如此轻量的重要原因。
当需要修改容器镜像内的某个文件时,只对处于最上方的读写层进行变动,不覆写下层已有文件系统的内容,已有文件在只读层中的原始版本仍然存在,但会被读写层中的新版本所隐藏。
当使用 docker commit 提交这个修改过的容器文件系统为一个新的镜像时,保存的内容仅为最上层读写文件系统中被更新过的文件。分层达到了在不的容器同镜像之间共享镜像层的效果。
docker镜像(Images) 使用了写时复制 copy-on-write 的策略。在多个容器之间共享镜像,每个容器在启动的时候并不需要单独复制一份镜像文件,而是将所有镜像层以只读的方式挂载到一个挂载点,再在上面覆盖一个可读写的容器层。
在未更改文件内容时,所有容器共享同一份数据,只有在 docker容器运行过程中文件系统发生变化时,才会把变化的文件内容写到可读写层,并隐藏只读层中的老版本文件。
写时复制配合分层机制减少了镜像对磁盘空间的占用和容器启动时间。
在 docker 1.10 版本后,docker镜像改动较大,其中最重要的特性便是引入了内容寻址存储(content-addressable storage) 的机制。根据文件的内容来索引镜像和镜像层。
与之前版本对每个镜像层随机生成一个 UUID 不同,新模型对镜像层的内容计算校验和,生成一个内容哈希值,并以此哈希值代替之前的 UUID 作为镜像层的唯一标识。
该机制主要提高了镜像的安全性,并在 docker pull、docker push、docker load 和 docker save 操作后检测数据的完整性。
另外,基于内容哈希来索引镜像层,在一定程度上减少了 ID 的冲突并且增强了镜像层的共享。对于来自不同构建的镜像层,主要拥有相同的内容哈希,也能被不同的镜像共享。
通俗地讲,联合挂载技术可以在一个挂载点同时挂载多个文件系统,将挂载点的原目录与被挂载内容进行整合,使得最终可见的文件系统将会包含整合之后的各层的文件和目录。实现这种联合挂载技术的文件系统通常被称为联合文件系统(union filesystem)。
综合考虑镜像的层级结构,以及 volume、init-layer、可读写层这些概念,一个完整的、在运行的容器的所有文件系统结构可以用下图来描述:
从图中我们不难看到,除了 echo hello 进程所在的 cgroups 和 namespace 环境之外,容器文件系统其实是一个相对独立的组织。
可读写部分(read-write layer 以及 volumes)、init-layer、只读层(read-only layer) 这 3 部分结构共同组成了一个容器所需的下层文件系统,它们通过联合挂载的方式巧妙地表现为一层,使得容器进程对这些层的存在一无所知。
Docker镜像(Images) 的主要特点是,分层、写时复制、内容寻址 和 联合挂载。