云计算时代操作系统Kubernetes之容器(中)

通过容器(上)这篇文章的学习,我们清晰的了解到Docker是如何把我们开发的应用程序代码,打包成镜像,上传到镜像仓库,并在其他目标机器上运行起来,那么不知道你是否有想过,当容器运行起来后,如果从容器的运行环境内部看,它能看到什么?

我们的应用在目标机器上运行起来就是一个进程,而程序和进程的概念其实不是计算机科班出身,很难理解,我们就先来说说这两个概念,为后续更加深入的讨论打好基础。

用自己熟悉的编程语言编写如下的C语言代码:

#include <stdio.h>

main() {

  printf("hello world\n");

}

由于计算机只能识别0和1,因此我们需要首先将这个文件保存到本地磁盘,比如说helloword.c,然后我们用c语言的编译器将上边的高级语言翻译成机器能够读懂的二进制文件,在翻译的过程中,我们的代码逻辑会被翻译成计算机的指令,比如加法,加法等,而需要输出的数据字符串,也会被一并编译到最终的可执行文件中。

最后变成形成的这个文件,我们就叫程序,或者也叫可执行程序,比如在Windows上, 我们将代码编译后,会形成可执行文件helloword.exe,这个以exe为扩展名的文件,就叫可执行文件。而在类Unix系统上,比如说Mac上,我们用gcc将这个文件编译后,会生成helloworld这个可执行文件,无论是helloworld.exe还是helloword,我们都叫程序。

有了程序,我们就可以讲这个程序在操作系统上运行起来,比如在Mac下,我就可以使用./helloword来将刚才我们编译好的程序加载起来,操作系统会生成进程并且从磁盘上读取这个可执行文件,然后从第一个指令开始执行,在代码的执行过程中,可能需要驱动磁盘来读取更多的指令和数据。一旦程序在计算机上被运行起来,就从磁盘的二进制文件,变成了计算机内存中的数据,寄存器中的指令,以及各种被打开文件的句柄,而我们把程序运行起来计算机的各个部件的状态之和,称之为进程。

介绍问程序和进程之后,我们来从容器内部的视角来看一下,它能看到那些信息。对于在容器中运行的应用,它其实能够看到的就是我们在进项中打包的文件和文件夹,以及在打包系统启动时候通过参数挂载的目录结构,因此如果我们在启动的时候没有挂载任何卷目录,那么容器在任何一个环境,看到的执行环境和目录文件结构是完全相同的,即便是我们在测试环境和生产环境运行的是不同版本的Linux操作系统,因为应用是不被允许修改操作系统文件数据的,这就给开发人员带来极大的便利性,因为终于不用说那句“在我电脑上好好的,怎么部署上去就不行了”。

我们来举个例子说明一下,假设我们将编写的代码基于基础镜像Red Hat企业版进行了打包,然后我们无论是在Fedora还是CoreOS运行这个镜像,应用程序一直会觉得自己在Red Hat的环境中运行,因为当容器运行起来的时候,看到的是Red Hat的操作系统文件夹目录,而和宿主机上的操作系统不太相关(这么说不严谨,其实也相关,就是操作系统内核的版本要匹配)。

这种神奇的功能是如何实现的呢?接下来我们来深入分析一下容器镜像的分层概念。

【容器的分层机制】

虚拟机镜像本质就是一个巨大无比的文件,应用需要运行的操作系统内核和文件系统都被打包在一起,而容器镜像对虚拟机的这种模式进行了优化,打包后的应用被分成了多个层,层可以在多个镜像之间共享,这就意味着我们在启动某个镜像的时候,可能并不需要把整个镜像完整下载下来,大概率是你本地已经有了这个镜像的某些层,节省带宽的同时,可以加速应用的启动速度。

通过对镜像进行分层,镜像分享就变得更加的高效,特别是从使用者的角度,每台安装docker的机器,就对某个编号的层只保存一次,如下图所示:

《图2.1 容器可能共享某些层》

从上图可以看到,容器A和B共享了最上边的层,因此容器A和容器B就可以读取到这一层上相同的文件和数据,更进一步,容器A和B以及容器C,他们都可以访问下边的三方库文件所在的层,这种共享的机制对容器大规模部署和共享都有极大的促进作用。

不知道你是否意识到这里有个问题,如果按照上图这样来在多个容器间共享,那么容器之间的隔离性如何保障呢?是不是容器B对最上边的那层的某个文件进行了修改,容器A也能看到这个修改?

如果真如上边所说,肯定不行,容器的文件系统通过COW(copy on write)机制来保证隔离性,也就是确保一个容器对共享层文件的修改,不会让另外一个容器看到。具体来说,容器镜像由多个层组成,但是这些层中,有很多都是只读层,以及在只读层之上的读写层。

当应用程序A需要修改只读层的某个文件的时候,整个文件会被拷贝到读写层,然后在读写层对这个相同文件名的文件进行修改和保存,由于每个容器运行起来之后,都有自己专属的读写层,因此通过这种方式,容器A对某个文件的修改,对容器B不具有可见性,从而实现了隔离。

另外,当我们删除只读层的某个文件,我们其实只是在读写层将这个文件进行了标记,不让容器看到这个文件而已,文件本身没有发生任何变化,因此我们在容器中删除文件,其实并没有办法让镜像的尺寸变小。

注意:基于上边的介绍,看起来在容器中修改只读层文件的权限和所属信息只会造成文件被拷贝到读写层而已,其实并不然,如果你在容器的只读层进行大量文件的权限修改,容器镜像的尺寸会增长的非常可观,具体原因我们后续介绍。

好了,关于镜像分层的相关内容就这么多了,我们接下来看看Docker的这种打包操作系统文件系统的机制有什么缺陷。

【理解Docker镜像打包机制的缺陷】

理论上来说,通过Docker的镜像打包机制构建的应用,可以运行在任何Linux操作系统上,但是这里有个坑,主要是因为镜像是没有自己的操作系统内核,只有操作系统文件夹结构和文件,或者说就是徒有操作系统的外表而已。

如果镜像需要某个特殊版本操作系统内核功能的支持才能运行,那么理论上能够在任意操作系统上运行这句话就不严谨了。如果运行的操作系统内核因为版本过低,没有镜像需要的功能模块,那么就无法在这台机器上运行应用程序。如下图所示:

《图2.2 如果镜像需要特殊版本的内核支持,那么就无法运行在任意的机器上》

容器B在运行的时候,需要特定操作系统版本提供的功能模块,而这个模块在工作节点1上有,在工作节点2上没有,当我们将容器的实例调度到节点2上的时候,这个应用就无法运行起来,由于缺少操作系统相关内核模块。

其实不光是内核和内核模块会造成这种问题,如果我们的应用程序针对特定的硬件平台,那么硬件平台的架构也会对应用的部署造成约束,比如说我们的应用是基于X86CPU架构来构建,那么我们无法将这个应用部署到ARMS机器上,如果我们非要在ARMS机器上运行这个应用,只能通过在ARMS安装虚拟机来模拟X86环境。

好了,以上就是关于镜像打包机制缺陷的详细介绍。笔者反复强调过,Docker从来都不是Kubernetes平台上的默认容器引擎,Kubernetes从一开始就有更加宏伟的目标:从宏观的角度,以统一的方式来定义不同的对象之间的关系,并为复杂多变的场景预留空间。这就不难理解Kubernetes项目并没有把Docker作为整个架构的核心,而顶多就是底层运行容器的一种方式而已,而Kubernetes的核心就是在这些运行时的上边,如何处理编排,调度,网络,存储,安全,监控等功能。

接下里我们来介绍一下除了Docker,在Kubernetes平台上,还有哪些可选的容器实现方式。虽然说Docker让容器这个“老”技术换发青春,但是由于Docker所依赖的技术和Docker没有什么关系,特别是容器所依赖的隔离技术,其实是操作系统内核提供,Docker只是让这些容器隔离技术用起来更加简单而已。

随着Docker变为主流,Open Container Initiative(OCI)启动了标准化工作,试图创建公开的容器格式和运行时行业标准,Docker公司也是这个标准化组织的一员,但是可以猜测到,基本属于出工不出力的态度,因此OCI这个标准化根本没办法顺利往前推进,虽然这个组织制定了OCI Image Format Specification,来规范容器镜像的格式,以及OCI Runtime Specification,定义了标准的容器创建,配置和运行的接口,但是很不幸的是,这些标准你没有听说过,我在写这篇文章之前也没有听说过,从这个角度,你就知道Docker公司参与的这个标准组织几乎没有啥影响力。

随着Kubernetes的崛起,由于谷歌和红帽公司的高瞻远瞩,特别是谷歌公司多年在内部践行Borg系统的实战经验,从一开始就没有把整座大厦建立在Docker的容器平台上,虽然从Kubernetes刚开始的时候,Docker是整个平台进行容器化战略的主航道,原因并不是基于架构考虑,而是因为那个时候Docker是被使用最广泛的容器平台。

但是随着Kubernetes逐渐坐稳容器化PASS平台的头把交易,Kubernetes随即就标准化了容器运行时,这就是笔者在前边提到的CRI(Common Runtime interface),也叫通用运行时接口。Docker实现了这个接口,另外还有很多其他的比如CRI-O的实现,作为Docker的另外一个选项,可以用来在Kubernetes上部署容器化的应用。

除了这个CRI-O,还有诸如rkt,runC和kata contrainer等的OCI兼容的容器实现,大家如果感兴趣,可以自行学习。

好了,到这里为止,我们做了足够的铺垫,为了让大家顺利将自己的第一个应用部署到容器平台。接下来,我们在下一篇,详细介绍如何把一个Spring Cloud的应用进行打包, 并部署到容器平台Docker中。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容