Linux的隔离技术

隔离基于内核提供的一些机制和策略

虚拟化中,我们最终虚拟的是资源。在计算机中,典型的资源包括:CPU,内存,磁盘,网络,安全等。

现代操作系统中,CPU资源基本都是被进程使用,内存为虚拟映射,磁盘一般表现为文件系统,所以上述资源可以进一步的表述为:进程、文件系统、网络、安全等。

在Linux中,通过命名空间可以做到上述资源的隔离。

首先,对于进程,作为系统内的执行实体,内核是以树形结构管理的。用户进程都是从祖先init进程继承而来。
通过这棵树,形成了父进程、子进程、进程组、线程组、会话组等概念。通过这些概念,形成了一些默认的进程间通信机制。
利用命名空间,在这个进程大树上,打上标记,使得某些进程及其子进程看不到父进程和相关的兄弟进程,效果上感觉就跟家族断绝联系了。

通过ipc命名空间,可以进一步的限制进程间的通信机制。这种通信机制主要指消息队列、信号量和共享内存。被限制的进程无法通过这几种机制与其他进程通信。

对内存而言,进程都是处在自己的虚拟地址空间,天然的就是隔离的,而通过内存的联系纽带共享内存,通过上面的ipc命名空间可以进行限制,这样一来,内存的使用也就分开了。
进一步的,如何限制进程的可用内存大小?ulimit调用?调度程序会跟踪进程的内存占用,使用水位概念,对占用过多内存的进程进行处理。
到此,一个进程在内存中可以独立的运行了。它可以使用的内存被限制了,它可以看到的和通信的其他进程被限制了。

但是,一个执行单元并不始终在内存中,它还需要能够访问文件系统,并可能更频繁的访问网络。这两个资源默认也是全局共享的,所以也需要进行隔离。

对于文件系统,Linux中普遍采用了mount机制,并且文件系统也是采用树形管理的,所谓的mount,就是将一个文件系统挂接到全局文件树的某个节点上,形成一个新的树。
内核对文件系统的挂载也是非常灵活的,多个文件系统可以挂载到同一个目录下,形成一个链表,运行中使用最后一次挂载的结果。
一个文件系统也可以挂载到不同的目录下,通过不同的路径得到访问。
进程访问文件系统时,内核会判断当前目录是否为挂载点,如果是的话,就按挂载点的文件系统类型进行解析访问具体的设备。
既然是一棵树,那么必然就有树根,内核提供了chroot命令,可以修改进程看到的文件系统树根。
这样一来,内核可以借助文件系统树和命名空间,限制进程可以看到和访问的文件系统树的范围,进一步的实现进程自己独立的文件系统。

最后,就是网络。网络的隔离感觉相对复杂一些。网络设备和协议栈在内核是全局的,只是在应用接口层,根据不同的进程,提供分发和收集数据的功能。
要隔离网络,就得让进程感觉自己拥有独立的接口、协议栈、路由表、IP地址、网卡设备等。
这其中,接口是通用的,本身不体现资源特性。
网卡设备,内核支持虚拟网卡设备的创建,可以通过这一步为进程提供独立的虚拟网络设备。
有了网络设备,地址就有附着单元了。
路由表和协议栈更多的是依赖地址和设备,规则并不需要定制,所以可以共用。
但是,上述的这些资源,在系统中来看,都是全局的,所以,这里的问题在于如何让这些资源与进程关联起来。内核提供网络命名空间解决这个问题。
我们可以这样看这个问题:进程要看到路由表和网络设备,无外乎是通过系统调用、内核接口或者是现成的工具软件。
而无论是进程本身通过系统调用还是在内核层通过子系统接口亦或是通过现成的工具软件,都是明确处在进程的上下文的,而且是用户进程的上下文。
我们通常在shell中获取这些信息,显然,这时候shell所在进程充当了父进程的角色。
既然是与进程关联起来了,那么通过在进程的结构中添加相关的标记,限定进程可以获取的信息,就可以实现进程拥有自己的网络设备的假象。
但是,我们的最终目的并不是这个假象,而是实际的功能,也就是关联进程的网络数据也需要实实在在的通过虚拟网络设备传输。
这分三部分,一是看到的,一是发送的,一是接收的。看到的我们已经解决了,这里进一步来看发送的和接收的。
发送的流程,进程调用系统调用,通过协议栈,需要查询路由表和路由策略,做出可能的修改,然后将数据包通过虚拟设备送出。
这里需要一份独立的路由表,并需要将出口设备关联到虚拟设备。设备侧可通过地址关联?多个进程是否可用有相同的IP地址?
接收流程,数据包到达后,经过路由过滤后,上报给关联的进程获取通过虚拟设备出口送出。

安全是另一个重要的隔离特性。这里进程有专门的权限管理后,主机的安全更有保障,同时自身的权限管理也就可以更加灵活。


除了以上隔离技术外,还需要对隔离空间进行精确控制,这包括:CPU资源使用占比,内存使用限制,磁盘空间使用限制,以及网络带宽使用限制。
CPU资源的限制,cgroup可以实现
对内存使用的限制,ulimit和cgroup可以实现
磁盘空间使用限制,cgroup可以实现
网络带宽限制,可采用跟路由器中的IP带宽限制类似,通过流量控制完成,也可以通过其他手段比如cgroup实现。

cgroup本质上提供了对策略的管理,通过层次化的结构,展示了相关控制参数,而具体的控制实施,则由具体的管理模块负责。
对于CPU资源使用,调度程序根据cgroup提供的参数,进行分配
对于内存资源的使用,内存管理模块也是根据cgroup提供的参数信息,进行限制
对于磁盘和网络,也是如此。

关于cgroup如何与这些管理模块配合工作的,可以参考下面的博文:
https://ggaaooppeenngg.github.io/zh-CN/2017/05/07/cgroups-%E5%88%86%E6%9E%90%E4%B9%8B%E5%86%85%E5%AD%98%E5%92%8CCPU/
https://ggaaooppeenngg.github.io/zh-CN/2017/05/19/cgroup-%E5%AD%90%E7%B3%BB%E7%BB%9F%E4%B9%8B-net-cls-%E5%92%8C-net-prio/
 

你可能感兴趣的:(Linux系统开发,linux,os)