头图

【云原生 • 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容器上。


云原生_Prometheus
云原生&Prometheus监控&Grafana可视化

云原生&Prometheus监控&Grafana可视化

8 声望
0 粉丝
0 条评论
推荐阅读
【云原生 • 监控】国产监控之光-夜莺监控(Nightingale)
国产监控之光-夜莺监控(Nightingale)夜莺是什么?夜莺是一个服务端组件,类似 Grafana,可以对接不同的TSDB时序数据库作为数据源,支持的TSDB时序数据库如Prometheus、VictoriaMetrics、Thanos等等,只要数据进...

Reactor20201阅读 564

封面图
Aliyun-使用Docker方式安装Jenkins
之前自己在阿里云ECS上面安装了Jekins(安装jenkins的文章),最近因为服务器中了挖矿木马于是准备重新安装一下,但是想到每次安装jenkins都要手动安装jdk、maven、docker、kubectl,感觉好麻烦,于是使用官方推荐...

Awbeci2阅读 2.1k

Win10 安装Docker以及Jenkins(超级详细篇)
安装Docker下载地址:[链接] ,按照它的指引教程,无脑下一步即可。安装成功后电脑会重启。打开docker桌面端,会显示进入链接,下载WSL 安装包进行无脑安装即可。安装 Linux 内核更新包 (重启电脑)重启 Docker ...

九旬3阅读 1k

Redis集群容器化安装
主从复制在数据库中很常见,一般用来做读写分离,Redis中也是如此。要求只有1个Master(主节点),可以有N个slaver(从节点),而且Slaver也可以有自己的Slaver,由于这种主从的关系决定他们是在配置阶段就要指定...

KerryWu2阅读 2.3k

Apache APISIX 结合 Authing 实现集中式身份认证管理
Apache APISIX 是一个动态、实时、高性能的 API 网关,提供负载均衡、动态上游、灰度发布、服务熔断、身份认证、可观测性等丰富的流量管理功能。Apache APISIX 不仅支持插件动态变更和热插拔,而且拥有众多实用的...

API7_技术团队1阅读 2.4k

Kubernetes Gateway API 深入解读和落地指南
Kubernetes Gateway API 是 Kubernetes 1.18 版本引入的一种新的 API 规范,是 Kubernetes 官方正在开发的新的 API,Ingress 是 Kubernetes 已有的 API。Gateway API 会成为 Ingress 的下一代替代方案。Gateway A...

Rainbond2阅读 413

Apache APISIX 助力便利充电创领者小电,实现云原生方案
原文链接业务背景小电作为国内共享充电宝服务平台,目前还处于初创阶段。从运维体系、测试环境等方面来讲,当下产品的业务主要面临了以下几个问题:VM 传统模式部署,利用率低且不易扩展开发测试资源抢占多套独立...

API7_技术团队1阅读 1.6k

云原生&Prometheus监控&Grafana可视化

8 声望
0 粉丝
宣传栏