文言Docker外围原理
Docker是什么?
「Docker应用Google公司推出的Go语言进行开发实现,基于操作系统内核中Cgroup(资源管制)、Namespace(资源隔离)与OverlayFS(数据存储)等技术,实现了基于操作系统层面的虚拟化技术。」
了解的早就了解了这句话外围实质,不了解的给他这么一解释还是云里雾里。那咱们先不急于搞懂Docker是什么,说到Docker容器,就不得不说下虚拟机(Virtual Machine),Docker容器和虚拟机又有什么区别呢?
Docker vs 虚拟机
虚拟机对于咱们开发者是个再相熟不过的概念,比方咱们常常应用VMware Workstation搭建虚构操作系统部署利用,应用JVM虚拟机运行Java利用等,如下图,「通常应用虚拟机管理器作为两头转换层,能够屏蔽底层操作系统或硬件设施差别」,比方下层虚拟机操作系统(Guest OS)执行程序或Java程序运行等,「这个中间件转换层就像翻译家一样,将下层执行的指令解释翻译成上层操作系统对应的指令进行执行」。

正如Java世界中吹牛的"一次编译,到处运行",「虚拟机实质上通过中间件转换层屏蔽了底层差别,模拟出一个新环境,实现与平台无关,达到与外界隔离的目标,这就是虚拟机实现虚拟化的核心思想」。
从虚拟机架构实现上能够看出,其存在一个很大问题:所有的指令都必须通过虚拟机管理器这个两头转换层翻译解释能力在实在操作系统上运行,这就意味着虚构机会存在性能损耗。另外,为了模仿一个Linux环境上运行的利用,须要应用VMware运行部署一个宿主机(Guest OS),再在宿主机上运行利用,宿主机自身占用好几个G的存储空间、400-500MB+内存空间,当初微服务架构动不动就是10+、100+个利用组件须要部署,那这些组件都须要做隔离部署应用虚拟机形式无疑是致命的。
上述说的虚拟机存在性能问题和资源节约造成了虚拟机对细粒度的环境隔离有点力不从心,而这又与以后风行的微服务架构场景下,零碎被拆分成几十、上百个微服务利用组件须要独立部署存在抵触。Docker推崇的是一种轻量级容器的构造,即一个利用一个容器。所以,Docker一进去就被推向巅峰,那它又是如何搞定虚拟机隔离存在的问题的呢?
Docker容器核心技术
Docker容器中过程是间接运行在底层操作系统上,没有两头转换层,所以也就不存在性能损耗的问题。要害那它是如何做到隔离的呢?

「这里就引出了撑持Docker容器的两大内核技术:Namespace和Cgroups(Control Groups)」。Namespace次要是用来进行「资源隔离」,对于那些计算型资源,比方CPU、内存、磁盘IO等不能进行隔离的资源,这时就须要采纳Cgroups进行「资源限度」,避免有些资源耗费较大的容器,将整个物理机器的硬件资源(CPU, Memory、磁盘IO等) 占满,进而影响其它过程性能。
Namespace和Cgroups这两个技术都是Linux内核自身反对的性能,Docker如果只应用这两大技术也不可能造就出道即巅峰的炽热水平,Docker翻新点恰好是引入镜像概念,并应用联结文件系统(UnionFS)技术很好的实现了镜像分层,这样就能够将利用部署介质、依赖环境配置文件以及操作系统二进制文件进行分层叠加构建出利用运行时文件系统环境。

镜像蕴含一个根底镜像(Base Image),这个个别蕴含操作系统介质,比方centos、debian,然而它只包含应用的操作系统二进制文件,并没有包含内核相干,所以,它的体积远远小于部署整个操作系统占用的空间,比方一个centos根底镜像大略只有70-80MB。另外,镜像分层设计进一步缩小存储占用,比方当初100+利用组件都是基于centos根底镜像部署,理论部署时只须要拉取一份centos根底镜像,就像搭积木一样,将每一层应用的文件进行组合叠加,最终构建出程序运行时残缺的目录构造。
文言核心技术关系
「Docker容器技术炽热的背地,其实是Namespace、Cgroups和UnionFS三大技术创新的联合,造就出了Docker这种景象级产品」。上面用个比拟形象的比喻来帮忙你了解三大技术关系:
1、失常程序启动时间接运行在操作系统上,应用Docker启动程序时,也是间接运行在操作系统上,然而Docker引擎在启动程序时会给程序套一个立方体壳(见下图);

2、这个立方体壳前后左右四个面应用Namespace资源隔离技术打造,这样就给Docker容器中过程和其它过程隔离开来,给容器中过程造成一种运行在一个独立环境中的假象(见下图);
3、这个立方体壳的下面这个面应用Cgroups资源限度技术打造,防止程序壮大成长进去抢占其它过程的资源,进而影响其它过程性能,这样就给盖盖上加上了一个紧箍咒,再牛逼的程序也会把你死死的限制住(见下图);
4、最初再来看下这个立方体壳剩下的最上面这个面,其采纳UnionFS技术打造,构建出容器中过程运行时文件系统根基。将操作系统二进制指令、依赖配置文件、程序介质等通过镜像分层叠加构建出程序运行时看到的整个文件系统环境;比方宿主机是Debian零碎,然而根底镜像是CentOS环境,容器中过程看到的是CentOS零碎,而不是Debian零碎,同时将yum install装置的依赖介质也通过镜像打包进来,容器中过程就不须要关注宿主机上到底有没有装置该依赖介质等等,这样容器中过程看到是一个领有程序运行时残缺介质,并与宿主机操作系统隔离开的独立操作系统(见下图);
5、所以,程序运行在三大核心技术发明的立方体壳壳中,被蒙蔽双眼傻乎乎的认为运行在一个独立计算机环境中,看不到外界程序运行状况,也影响不到外界程序的运行。

如何查看Docker过程在宿主机上的PID?
Docker容器中的过程是间接运行在宿主机上,能够通过docker inspect container查看到Docker容器中过程在宿主机上对应的PID信息(见下图):

宿主机上ps -ef查看下容器过程信息:

因为,这里运行的是一个nginx容器,所以宿主机上看到对应的是nginx主过程,同时该过程创立了两个nginx worker子过程。
Docker容器缺点
「高性能、轻便是容器相较于虚拟机最大的劣势,容器实质上是一种非凡的过程。」
不过,无利就有弊,基于Namespace的资源隔离和Cgroups的资源限度都不是那么彻底,因为容器之间底层还是共享应用宿主机的Linux内核,只管你能够在容器里应用不同版本的操作系统文件,比方CentOS或者Ubuntu,但这并不能扭转共享宿主机内核的事实。这意味着,如果你要在Windows宿主机上运行Linux容器,或者在低版本的Linux宿主机上运行高版本的Linux容器,都是行不通的。
其次,在Linux内核中,有很多资源和对象是不能被Namespace化的,最典型的例子就是:工夫。这就意味着,如果你的容器中的程序修改了工夫,整个宿主机的工夫都会被随之批改,这显然不合乎用户的预期。
另外,跟Namespace的状况相似,Cgroups对资源的限度能力也有很多不欠缺的中央,这里最常见的是/proc 文件系统的问题。Linux下的/proc目录存储的是记录以后内核运行状态的一系列非凡文件,用户能够通过拜访这些文件,查看零碎以及以后正在运行的过程的信息,比方CPU应用状况、内存占用率等,这些文件也是top指令查看零碎信息的次要数据起源。然而,你如果在容器里执行top指令,就会发现,它显示的信息竟然是宿主机的CPU和内存数据,而不是以后容器的数据。造成这个问题的起因就是,Docker引擎在启动过程时间接将宿主机/proc下很多文件挂载到Docker容器上。