0


【云原生 • Docker】用故事给老板讲Docker核心原理成功装逼

用故事给老板讲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

容器上。

标签: docker 云原生

本文转载自: https://blog.csdn.net/god_86/article/details/129585835
版权归原作者 Reactor2020 所有, 如有侵权,请联系我们删除。

“【云原生 • Docker】用故事给老板讲Docker核心原理成功装逼”的评论:

还没有评论