你真的了解容器嘛-下篇

Posted by 小罗 on January 21, 2019

前言

上期我写了一篇你真的了解容器吗?-上篇,一起了解了“容器技术的编年史”,那么!!!

  • 为何docker一开始要去封装LXC?

  • 到底LXC的底层用了什么内核技术让Docker如此看重?

  • 这么多容器技术为什么偏偏docker就火遍了大江南北?

  • docker到底有什么独到之处

Linux内核机制-NameSpace与Cgroup

大伙都知道Linux系统有两大空间:用户空间和内核空间。程序运行起来跑在用户空间,当程序需要调用一些设备底层的操作时(操作网卡发送数据包,操作硬盘写数据等),就会调用内核空间的一些接口完成这些动作。传统方式下我们在linux系统里面跑多个应用程序,大家是在同一片蓝天下,也就是在同一个用户空间下,各个应用程序之间大家各自都有各自的进程编号,大家共用同一个主机的主机名以及域名。A应用的用户可以访问B应用的目录,A进程也可以和B进程之间进行通信,大家发送数据包是用同一个IP地址和网络栈,整个系统只有一个超级管理员root、只有一个根目录/、只有一个进程号为1的进程init,普通应用ABC的进程号只能是普通的数字,永远成不了1号进程,那有没有一种办法让这些普通的A/B/C进程享受一些特权呢?

  • 让这些应用的主进程就是1号进程?

  • 让这些应用所在的目录就是“/”根目录?

  • 让他们单独享用IP地址与网络栈?

  • 让他们自己的用户在自己的程序内就像是root用户?

  • 让A/B/C进程之间不要去试图互相串门和通信?

  • 让他们独自享用主机名和域名?

Of Course! 这些就是linux的内核Namespace技术要做的事情!Namespace技术干的事情就是隔离,隔离的是什么?隔离的是用户空间,隔离的是进程。让每一个进程都单独拥有自己的IP地址、网卡;单独拥有自己的根目录“/”文件系统;单独拥有自己的主机名……

但是!!!!这些应用程序所拥有的1号进程也好,“root用户”也好,都是从这些应用自己的视角看到的。实际上呢?在最上层那个用户空间来看,“普天之下莫非王土”。这些一个个隔离起来的进程形成了一个个“沙盒/容器”,在容器内的进程以为他们就是这个世界上唯一的进程,拥有唯一的root用户,可以在这个容器内操作一切。但实际上他们自己看到的1号进程,在最上层的操作系统里面其实就是普通的N号进程,他们自己看到的“root”用户,其实可能就是普通的“test”用户而已!

有关namespace的官方列表:

为了便于大家理解,继续上几幅图,我在图里也做了相关说明

Mount NameSpace技术细节

Network Namespace技术细节

IPC Namespace技术细节

PID Namespace技术细节

UTS Namespace技术细节

User Namespace技术细节

Cgroup技术

前面说了Linux的内核技术NameSpace。小伙伴们可以看到,Namespace解决的主要问题是用户空间的隔离问题(内核空间并没有隔离)。这只是容器化中最基础的一步。

那假设有一个进程被隔离了,但是其肆无忌惮的吞噬着宿主机的CPU、内存、IO资源,那就会导致这个宿主机上其他被隔离的进程就没法再运行了。所以我们必须限制每一个被隔离的进程对资源的使用,不能“让你狮子大开口”,想吃多少资源就吃多少资源,这就是Cgroup干的事情。

在上一篇【容器】你真的了解吗?-上篇(点击查看),容器技术的编年史中提到过,linux Cgroup项目最早是在2006年由谷歌的两位工程师发起,刚开始命名process containers,后来为了避免混淆被重命名为Cgroup,并且被合并到Linux 2.6.24版的内核中。cgroup提供的主要功能如下:

  • Resource limitation: 限制资源使用,比如内存使用上限以及文件系统的缓存限制。
  • Prioritization: 优先级控制,比如:CPU利用和磁盘IO吞吐量。
  • Accounting: 一些审计或一些统计,主要目的是为了计费。
  • Control: 挂起进程,恢复执行进程。

凭啥Docker就火了?

从上篇文章中

你真的了解容器吗?-上篇

中可以看到搞容器技术的产品和玩家很多,那凭什么这么多容器技术只有Docker火遍大江南北?Docker和LXC本质的区别在哪?Docker的牛掰之处到底在哪?咱们接着说!!

笔者认为,LXC利用Namespace和Cgroup很好的实现了进程的隔离以及资源的管控,但是LXC的本质目的还是为了实现更加轻量化的虚拟化,之所以说他“轻量”是因为:

  • 容器共享同一个内核:不同于vmware及openstack连内核都是彼此隔离,此为其一!
  • 容器隔离的是进程:进程的启动和关闭肯定更快(你手动重启QQ进程和重启整个windows系统哪个更快?)此为其二!

另外,由于直接用的操作系统内核,中间没有hypervisor层的性能损耗,因此在性能上也比虚拟化技术更有优势!

LXC本质上还是把一个容器当成“轻量级虚拟机”来使用,单个容器内可以跑多个进程,这样在容器管理的时候极为不便,LXC容器依靠LXC提供的各种template去安装和启动,因此对广大IT从业者来说,这并不新奇!接下来看看docker!

Docker除了利用LXC隔离出容器以外,最牛X的实现是docker image(docker镜像)。这项技术的出现解决了广大开发人员和运维人员长久以来由于各种环境不一致问题,导致的人和人之间的矛盾以及人和设备之间的矛盾!!并且真正实现了“一次构建,到处运行”,完全解耦了底层IAAS资源的多样性。

一套软件,你在centos环境下和ubuntu环境下部署都需要考虑很多软件依赖问题,在测试部署过程中自然会涉及到各类依赖环境,一个依赖包安装的不对就可能会导致软件部署失败。

开发人员经常说,为啥我在我的开发环境里跑的好好的,到你的环境就不行了?

运维人员经常会说,为啥在测试环境跑的好好的到生产环境就不行了?

  • 于是开发怼运维!

  • 运维怨开发!

最终耽误的是新产品的上线速度以及企业的效率

Docker的镜像技术就是一种打包机制,他将应用程序从代码到编译环境到运行环境全部打包到一起,形成一个静态的docker image。只要宿主机上安装了docker就可以拉取docker image,然后启动容器。而且docker针对docker镜像还搞了一个公共的镜像仓库,大家可以把制作好的docker镜像都上传到这个公共镜像仓库,当然企业也可以搭建自己的私有镜像仓库,这样大家想使用任何镜像都可以使用docker pull命令直接去拉取,极为方便!

大家再也不用发愁因为各类依赖问题而发生的种种矛盾,只要开发把应用程序及所依赖的环境打包成docker镜像以后,可以随处移植。只要我的环境有docker就可以运行打包好的dokcer image。这太牛了,显然LXC干不了这个事情!

再强调下,docker容器在设计之初为了简化管理,就建议一个容器只跑一组进程(当然你要硬在一个容器里面跑两组进程,肯定有实现的手段),比如一组tomcat进程,一组redis进程,而且镜像使用分层技术(下一期如有时间,给大家写一篇镜像分层的文章)来灵活构建容器镜像。比如我可以在我同事构建的镜像之上再安装我所需要的软件,最后在用docker built命令构建成一个新的镜像。为了方便大家理解LXC和docker的区别,我把一些官方图做了修改,如下图所示:

简单总结

笔者认为,LXC着眼点在于提供轻量级的虚拟化技术,扎根在虚拟机。DOCKER将应用的所有配置进行抽象,打包到一个镜像中,使得容器具有可移植性,当然Docker0.9版本以前,LXC和Docker之间的关系可以参考下面这张图!!所以笔者认为docker真正给人带来革命性变化的是他的镜像打包技术!

结束语

有关docker容器的相关底层知识就先聊到这里,由于笔者能力有限,文章中难免有疏漏之处,望大家谅解