容器技术入门

http://www.yl1001.com/group_article/8051471533152711.htm

说到容器,这个概念现在非常火;实际上,在IT领域内各种技术一直是逐步迭代演进的,而每一次技术革新,正是从发现问题开始。

问题一:windows系统方面

先从大家用的windows说起。我们经常有这样的操作,打开一个word进行文档编辑,然后又打开了另外一个程序的安装包setup。Ok,这样我们可以简单认为开了两个windows进程,一个word进程,一个setup进程,那么可能存在的问题:

第一:

两个程序可以访问相同的资源,比如C盘上的数据;在编辑文档时,setup进程占用cpu过高,从而影响了编辑文档的体验。

第二:

 

Window里有个叫注册表的东西,这个被搞乱会带来很多麻烦。而setup如果设计兼容性不好,就有可能把注册表搞乱.

第三:

对于开发者而言,如果写这两个程序的人或团队属于不同机构的,那么就有可能产生配置冲突或兼容性的问题。

 

问题二:linux系统方面

linux系统

 

我们再来看一下linux系统:

首先:

我们知道linux系统有很多发行版本,比如centos、ubuntu等。我们的应用有app1 for centos,也有app2 for ubuntu的,那现在我需要在一个OS里能跑app1和app2,怎么办?

其次:

对于app1和app2的开发者需要编译出不同发行版的应用程序:for centos、for ubuntu等,如何实现?

最后:

对于开发者而言,一个程序写好测试过后,在最终的地用户环境里可能会产生环境不匹配而导致运行异常的问题,如何解决?

 

 

如何解决上述问题?

一个自然的想法就是“隔离”+”运行环境打包”。把各个程序或app及相应的运行环境打包交付成镜像,这样既可以避免环境兼容的问题,又可以互补干扰和破坏。那么在一台机器上同时运行各个打包交付的镜像时,就需要把各个镜像隔离加载运行才能保证各个app的运行环境独立而不冲突。这里大家自然就会想到虚拟机,没错,虚拟机可以做这样的事情,每个镜像就是一个虚拟机文件,虚拟机的优势显而易见。但是我们现在只是希望在一台机器上高效运行多个程序,那么用虚拟机的方式缺点也很明显:

1.每个app镜像里需要包含一个OS,体积过大;

2.一个机器运行多个不同环境的app需要多个OS虚拟机,管理和运行的效率成问题。

 

我们看到,这里的主要矛盾是为了运行不同环境的app要把OS也加进来作为支撑环境,那么为了进一步容易管理和提升运行效率,能不能把OS这一层精简呢? 答案是可以,这就是容器要做的事情,精简OS这一层。

精简OS层

精简OS这一层,各个app执行环境共享OS是一个有效的方法。我们先看看linux为什么能做到这一点。

实际上现在的linux可以理解为两部分,一是内核,一是发行环境。比如我们说的centos,ubuntu,redhat等,就是指的发行环境。大家都在相同的linux内核的外围发行自己的管理执行程序,各个发行版本就是目前的centos,ubuntu等,这时候解决方法就来了:提供多个发行环境共享一个linux内核的功能。

 

好,这时候容器的概念就出来了。linux容器可以理解为多个发行环境共享一个内核,因此各容器可以有不同的发行环境(如centos,ubuntu等),但只有一个共同的内核,所以你不能启动一个其它内核的运行环境(如windows)。如果你需要运行一个centos环境的容器和一个windows环境的容器,这时你需要的就是虚拟机了,而不是容器,或者说需要带有虚拟机内核功能的容器了。再就是你的发行环境里需要的内核版本功能比容器共享内核版本功能高也会有问题,那么就需要升级你的共享内核。说简单了容器就是共享OS内核的隔离支撑环境。

 

 

linux容器核心功能

 

我们来来看看linux容器的基本核心功能:

 

1.文件系统隔离

每个容器运行在完全独立的根文件系统里。

 

2.网络隔离

每个进程容器在自己的网络命名空间里,拥有自己的虚拟接口和网络地址。

 

3.资源隔离

为每个进程容器分配不同系统资源,如cpu,mem,io等。

windows容器价值

再看看windows,上述的三点同样需要,不同的是大家都知道windows里有个注册表,这个对windows而言非常重要,因此windows的容器对这个问题自然不能回避,那么windows容器是如何解决这个问题的呢? Windows有一个主机注册表,容器里的注册表继承它,但修改时容器自己保存了自己对注册表的修改部分,那么容器里把注册表改乱了也不影响到host和其他容器,进一步Windwos里用jobobject来限制容器的资源使用,而linux使用cgroup来限制容器的资源使用,限于篇幅这里就不再详述了。

 

 

我们要使用容器,自然就不能回避容器的设计生成过程,而生成之后就涉及到加载运行和管理,那么今天我们就从设计交付和架构这两个角度来说一下容器。

 

设计交付运行角度

简述

Docker Image的设计者按Dockerfile的语法规则进行Docker Image的设计描述,描述完成后通过build命令生成Docker Image; 交付测试者时,测试者只需基于Docker Image进行加载测试即可。

使用过程

我们看容器的好处很多,那么使用容器的过程是怎样的呢?

 

首先,不能回避的是容器的设计,也就是用户用自己的需要设计容器。这里我们先看看传统的编译型语言的使用过程:一个程序员先写好代码,然后通过编译器把代码编译成机器指令,并按一定的系统规则组织起来形成执行文件 ( 如Windows里的exe文件),然后交付给测试者,测试者测试完成通过后交付给使用者,使用者直接执行这个文件,而不用关心代码的设计编译和测试过程。

 

对应容器而言,也有个设计编译和测试使用过程;在容器设计过程有一个叫Dockerfile的东西,这个文件就相当于用户Docker的设计,在Dockerfile完成后build命令可以理解为编译过程,实际上就是通过Dockerfile的描述生成Docker镜像Image,然后把镜像交付给测试者,测试者测试通过后把镜像提交给使用者。其对应的阶段表格为:

 

上述表格可以理解为通过描述文件Dockerfile生成了镜像文件Docker Image,加载Docker Image运行就形成了动态进程容器Container。 一旦加载执行起来,容器进程的行为就需要跟Linux 内核进行交互了。容器进程基于Linux内核的支持,那么把这个因素考虑进去后我们可以把图画成这样。

 

从图上看到Container进程通过Libcontainer来进行跟Linux内核的交互,由于新版本的Docker不支持LXC了,因此只列了Libcontainer。Container执行需要Linux内核的支持,这里为简单起见只说一下两个基础的功能,空间的隔离和资源的限制。

空间隔离

空间的隔离就是用了Linux 的Namespaces,也就是名字空间,这个功能的基本作用就是隔离,比如两个用户u1和u2,在不同的Namespace下运行是互相不可见的,一个具体的例子是u1的进程PID和u2的进程PID可以是相同的,如果是常规进程,那么同一个OS下两个进程PID是不相同的。

资源限制

资源限制用了Linux内核的Cgroups,此功能是用来限制每个容器进程对资源使用量的,比如CPU,内存,IO等,这样避免一个容器进程占用资源过大而使其它资源进程受到影响。

 

有了Namespaces和Cgroups这两个非常基础的重要功能,空间的隔离使各个容器进程有了接近虚拟机的独立性,资源的限制使各个容器进程有了运行资源的”平等性”,这样基于容器的应用就具备了接近虚拟机的一些基本特性,同时看到容器实际上是强依赖Linux内核功能的,这一点上跟虚拟机大家各自的OS或内核独立又很大的不同,比如说内核的Bug和漏洞都会影响到各个容器进程,这些需要篇幅,这里就先不展开了。

 


这里看到容器进程的运行是依赖Linux内核的,那么这里就不能回避操作系统了,那么问题就来了:用什么样的操作系统来支持容器的运行?CentOS,Ubuntu是现在大家常用的,这里提一下CoreOS和Rancher OS,这两系统非常合适容器的支撑。为什么这么说呢?

 

我们已经知道容器共享内核的运行环境,这个操作系统有了基本的内核功能就可以了,实际上相对操作系统而言可以做得非常小,当然也可以自己拿通用的操作系统进行裁减,但并不是最优的方案,之所以提到CoreOS和Rancher OS,这两个OS不但体积小(Rancher OS 29兆左右,CoreOS 200多兆),而且针对容器的支持做了很多调整。比如Rancher OS,里面进程皆容器,System Docker 起了系统运行的各种必备功能,然后起了User Docker(Container)。 所以CoreOS和Rancher OS可以认为是为容器而生的。

 

Docker 架构

 

现在我们从另一个角度看一下容器:对于Docker的运行,是一个典型的客户机服务器C/S模型或架构,如下面的图:

 

图里列了三个常用的基本命令:build(建镜像),pull(从仓库拉镜像),run(运行Docker),不同的颜色代表了不同的命令执行的流程。我们看到所有的client命令都提交给了Docker Daemon, Docker Daemon 负责镜像(Image), 容器进程(Container),仓库(Registry)的协调和管理,Docker Daemon 里有Docker Engine和Docker Job的概念。 对于深入理解Docker Daemon,建议看一下Docker的Golang源代码,想省时间可以从MainDaemon或NewDaemon看起。

 

上述角度都是基于单个节点上的Docker(container)而言的,当有多个主机上运行Docker时,多节点上的Docker管理和协调就需要新的工具了,也可以理解为Docker集群的管理,有Swarm,Rancher,Kunbernets等,这里先不展开了。

转自:http://www.yl1001.com/group_article/8051471533152711.htm



阅读更多

没有更多推荐了,返回首页