咱们常常拿 Docker 容器与虚拟机做对比,Dokcer 容器跟虚拟机的不一样之处在于,在使用 Docker 的时候,实质上并无生成一个真实存在的“容器”。Docker 帮助用户启动的,其实就是应用自己,只不过在建立这些进程时,Docker 为它们加上重重限制。包括启用 Namespace 配置对容器之间进行隔离,以及设置指定的 Cgroups 参数来为进程设置资源限制等。框架
固然,仅仅是这样还不够,既然一个宿主机能够存在多个容器且它们之间又是隔离的,那它们的文件系统是怎么样的呢,这就关乎到一个重要角色,使 Docker 被大众接受的关键——Docker 镜像。spa
首先,咱们天然会想到,容器里的应用进程,看到的理应是一份彻底独立的文件系统。由于只有这样,容器在操做本身的文件目录时才不会影响到宿主机以及其余的容器。操作系统
在 Linux 中,有一个概念叫作 Mount Namespace,它提供了文件系统的隔离,经过隔离文件系统挂载点来实现。而 Dokcer 正是利用了这个为各个容器提供了文件系统隔离。Docker 在容器进程启动以前,就会对它整个根目录 “/” 从新挂载,所以对于容器来讲,本身使用的就是一个彻底独立的文件系统。进程
固然,仅仅是这样还不够,总不能让容器的文件系统都空空荡荡的吧。所以除了隔离各个容器自己的文件系统,Docker 还会在容器的根目录下挂载一个完整的操做系统的文件系统,好比 Ubuntu。这样该容器根目录下的内容,就是 Ubuntu 的全部目录和文件了,也就是咱们无比熟悉的 /bin, /etc, /data, /usr 等资源
而这个挂载在容器根目录、用来为容器进程提供隔离后执行环境的文件系统,就是所谓的容器镜像。开发
既然一个镜像包含了一个操做系统的文件,配置,目录等,那它是否是就是一个操做系统了呢?部署
答案为否,由于镜像不包含操做系统的内核,而一台宿主机上的全部容器,其实都是共享当前所在机器的操做系统内核。这也是容器相比虚拟机,所呈现出来的一个缺点,当咱们在操做容器内的应用的时候,特别是与内核进行交互的时候,须要注意咱们是直接地影响了宿主机的操做系统内核,所以须要格外当心。虚拟机
咱们都知道镜像是 Docker 一个很是重要的特性,那么咱们为何须要镜像呢?class
在容器发展初期,用户在使用容器平台向集群部署应用的时候,一般须要进行一个打包的操做,不一样于 Docker 简单的镜像构建操做,在那个时候,开发者们必须为每种语言、每种框架,甚至每一个版本的应用都维护一个打好的包,同时因为上云后环境的不一样,还须要作许多配置工做。集群
而 Docker 镜像的出现,完全改变了这种情况,正如前面所说的,镜像不仅是包含了应用所需的语言,框架等环境,而是直接囊括了整个操做系统的文件系统,达到了本地环境和云端环境的高度一致的目的。而开发者们要作的,只是建立一个容器,并让镜像在这个容器中运行便可。
也就是说,镜像达成了操做系统级别的运行环境一致性,化解了本地开发与远端环境之间的差别问题。
在实际的开发中,若是咱们每开发一个应用或者在现有应用中作一些改动,都须要从新去构建一个镜像,那么这也是一个比较麻烦的事情。
所以 Docker 镜像采用了一种比较创新的方式,就是引入层的概念。既然咱们但愿避免每作一些改动都保存一个镜像,那就利用一种增量的思想,去维护增量的内容。也就是说,用户制做镜像的每一步操做,都会生成一个层。
比方说在 Dockerfile 中,大多数指令都会生成一个层,最终完成的镜像其实是一层一层地叠加起来的。与此同时,层之间又是能够共享的,假设本地拥有一个五层的镜像 A,而 A 镜像和 B 镜像共享了前面的五层,则当咱们从镜像仓库中拉取 B 镜像时,只拉取本地所没有的最后一层就能够了,而不须要把整个 B 镜像连根拉一遍。
分层机制带来的好处也影响了 Docker 后面的发展,在 17.05 版本以后,Docker 引入 Dockerfile 多阶段构建机制,使得镜像的体积可以大幅度下降。