1,Docker镜像
1,从宏观的角度看
从整体的角度来讲,一个完整的Docker镜像可以支撑一个Docker容器的运行,在 Docker容器运行过程中主要提供文件系统视角。例如一个ubuntu:14.04的镜像,提供了一个基本的ubuntu:14.04的发行版,当然此 镜像是不包含操作系统Linux内核的。
说到此,可能就需要注意一下,linux内核和ubuntu:14.04Docker镜像的区别了。传统虚拟机安装ubuntu:14.04会包含两部分,第一,某一个Linux内核的发行版本,比如Linux 3.8版本的内核;第二,第一个特定的Ubuntu发行版,这部分内容不包含Linux内核,但是包含Linux之外的软件管理方式,软件驱动,如 apt-get软件管理包等。
理解以上内容之后,就可以理解,为什么在一个Linux内核版本为3.8的ubuntu:14.04基础上,可以把Linux内核版本升级到3.18,而ubuntu的版本依然是14.04。最主要的就是:Linux内核版本与ubuntu操作系统发行版之间的区别。
Linux内核+ubuntu操作系统发行版,组成一台工作的机器让用户体验。那么灵活替换ubuntu操作系统发行版,那是不是也可以实现呢。那么Docker很方便的利用了这一点,技术手段就是Docker镜像。
Docker的架构中,Docker镜像就是类似于“ubuntu操作系统发行版”,可 以在任何满足要求的Linux内核之上运行。简单一点有“Debian操作系统发行版”Docker镜像、“Ubuntu操作系统发行版”Docker镜 像;如果在Debian镜像中安装MySQL 5.6,那我们可以将其命名为Mysql:5.6镜像;如果在Debian镜像中安装有Golang 1.3,那我们可以将其命名为golang:1.3镜像;以此类推,大家可以根据自己安装的软件,得到任何自己想要的镜像。
2,从微观的角度看
刚才提到了“Debian镜像中安装MySQL 5.6,就成了mysql:5.6镜像”,其实在此时Docker镜像的层级概念就体现出来了。底层一个Debian操作系统镜像,上面叠加一个 mysql层,就完成了一个mysql镜像的构建。层级概念就不难理解,此时我们一般debian操作系统镜像称为mysql镜像层的父镜像。
层级管理的方式大大便捷了Docker镜像的分发与存储。说到分发,大家自然会联想到 Docker镜像的灵活性,传输的便捷性,以及高超的移植性。Docker Hub,作为全球的镜像仓库,作为Docker生态中的数据仓库,将全世界的Docker数据汇聚在一起,是Docker生态的命脉。
3,镜像内容
第一阶段:初步接触Docker。相信很多爱好者都会和我一样,有这样一个认识:Docker 镜像代表一个容器的文件系统内容;
第二阶段:初步接触联合文件系统。联合文件系统的概念,让我意识到镜像层级管理的技术,每一层镜像都是容器文件系统内容的一部分。
第三阶段:研究镜像与容器的关系:容器是一个动态的环境,每一层镜像中的文件属于静态内 容,然而 Dockerfile 中的 ENV、VOLUME、CMD 等内容最终都需要落实到容器的运行环境中,而这些内容均不可能直接坐落到每一层镜像所包含的文件系统内容中,那此时每一个Docker镜像还会包含 json文件记录与容器之间的关系。
因此,Docker镜像的内容主要包含两个部分:第一,镜像层文件内容;第二,镜像json文件。
4,镜像文件层级结构
1,bootfs
bootfs是Docker镜像最底层的引导文件系统,包括bootloader和操作系统内核,类似于传统的Linux/Unix引导文件系统。然而,Docker用户很少有机会直接与bootfs打交道,并且,在容器启动 完毕之后,为了节省内存空间,bootfs将会被卸载。
2,rootfs
rootfs位于bootfs之上,是Docker容器在启动时内部进程可见的文件系统,即Docker容器的根目录。rootfts通常包含一个操作系统运行所需的文件系统,例如可能包含典型的累Unix操作系统中的目录系统,如/dev,/proc,/bin,/etc,/lib,/usr,/tmp及运行Docker容器所需的配置文件。
在传统的Linux操作系统内核启动时,首先挂载一个只读(read-only)的rootfs,当系统检测其完整性之后,再将其切换为读写(read-write)模式。而在Docker架构中,当Docker daemon为Docker容器挂载rootfs时,沿用了Linux内核启动的方法,即将rootfs设为只读模式。在挂载完毕之后利用联合挂载(union mount)技术在已有的制度rootfs上再挂载一个读写层。可读写层中没有任何文件或数据。只有在Docker容器运行过程中文件系统发生变化时,才会把变化的文件内容写到可读可写层,并隐藏只读层中的老版本文件,这样的技术被称为写时复制(copy on write)。
联合挂载技术是一种特殊的文件系统挂载方式,它可以在一个挂载点同事挂载多个文件系统。不同于一般挂载技术会对挂载带你原目录进行隐藏的方式,联合挂载技术会将挂载点的原目录和与呗挂载内容进行整合,所以最终可见的文件系统将会包含整合之后的各层的文件和目录。
实现这种联合挂载技术的文件系统通常被称为联合文件系统(union filesystem),常见的有UnionFS、aufs和OverlayFS等。
注意:Docker早期版本沿用aufs,1.4版之后开始支持OverlayFS。
例如以运行Ubuntu:14.04镜像后容器的aufs文件系统为例。由于初始挂载时读写层为空,所以从用户的角度看,该容器的文件系统与底层的rootfs没有差别;然而从内核的角度来看,则是显示区分开来的两个层次。Docker镜像中的分层结构是Docker如此清凉的重要原因之一,当需要修改镜像内的某个文件时,只对处于最上方的读写层进行了变动,不覆写下层已有文件系统的内容,已有文件在只读层中的原始版本依然存在,但会被读写层中的新版文件所隐藏,当保存这个修改过的容器文件为一个新的镜像时,保存的内容仅为最上层续写文件系统中被更新过的文件。
3,Docker镜像的存储组织方式
Docker通过联合挂载技术将各层文件系统叠加在一起,最终形成包含了所有底层文件与目录的文件系统,称为Docker镜像。镜像安装一定的层次结构叠加而成,一个新的进行可以基于另一个镜像构建。
如图,位于下层的镜像称为父镜像,最底层的镜像不基于其他镜像,称为基础镜像,一般不考虑bootfs。图(78)
4,Docker镜像关键概念
1,registry
registry用以保存Docker镜像,其中还包括镜像层次结构和关于镜像的元数据,可以将registry简单地想象成类似于Git仓库之类的实体。如果Docker镜像不在本地,将从registry中下载该镜像并保存到本地。
用户可以在自己的数据中心搭建自有的registry,也可以使用Docker官方的公用registry,即Docker
Hub。
2,repository
repository即由具有某个功能的Docker镜像的所有迭代版本构成的镜像库。registry由一系列经过命名 的repository组成,可以通过命名规范对用户仓库和顶层仓库进行区分。用户仓库的命名由用户名和库名两部分组成,中间”/“隔开,即username/repository_name的形式,库名通常表示镜像所具有的功能,如ansible/ubuntu14.04-ansible;而顶层仓库则只包含库名的部分,如ubuntu。
实际上,repository是一个镜像集合,其中包含了多个不同版本的镜像,使用表情进行版本区分,如ubuntu:12.04、ubuntu:12.02等,他们均属于ubuntu镜像库。
总而言之,registry是repository的集合,repository是镜像的集合。
3,index
index和registry是容易让人迷惑的两个概念。事实上,registry负责存储和提供真正的镜像,而index则类似于registry的索引,负责管理用户账号、访问权限认证、搜索镜像以及为镜像打标签等事务。
所以,当用户执行docker search时,真正搜索的是index,而非registry。当执行docker push或docker pull时,将由index判断使用者是否有拉取或推送相应镜像及访问registry的权限,而registry则是将需要存储或拉取镜像存储的实际位置。
4,graph
从registry中下载的Docker镜像需要保持在本地,这一功能由Docker graph完成。
在grap的本地目录/var/lib/docker/graph中,保存了每一个下载到本地的Docker镜像的元数据,包括json与layersize(镜像大小)。其中josn文件中记录了相应Docker镜像的ID、依赖关系、创建时间和配置信息等。
5,Dockerfile
Dockerfile是在通过docker build 命令构建自己的Docker镜像时需要使用到的定义文件。它允许用户使用基本的DSL语法来定义Docker镜像,每一条指令描述了构建镜像的步骤。
