Linux Container(LXC)容器隔离实现机制

一、LXC概述

LXC(LinuxContainer)是来自于Sourceforge网站上的开源项目,LXC给Linux用户提供了用户空间的工具集,用户可以通过LXC创建和管理容器,在容器中创建运行操作系统就可以有效的隔离多个操作系统,实现操作系统级的虚拟化。最初的Docker容器技术基于LXC进行构建,后来Docker在自己的内核中刨除了LXC。

二、LXC命令介绍

从Linux内核2.6.27版本开始已经支持LXC,只需要在Linux用户态安装相应的用户态工具liblxc即可。下表3-1是LXC的常用命令接口:

三、LXC容器隔离实现机制

从前面的介绍中我们可以了解到,LXC能够创建容器用于Linux系统的虚拟化,而LXC作为用户层管理工具主要提供了管理容器的接口,对实现容器的机制进行了封装隐藏,本文将对LXC容器的实现机制进行分析。

LXC内部采用了Linux内核Namespace和Cgroup两个特性,下面我们将对这两种机制进行介绍。

3.1、Namespaee命名空间实现机制

Namespace命名空间机制给虚拟化提供了轻量级形式,即操作系统级虚拟化。该机制和FreeBSD的jail机制和OpenVZ类似。传统上,Linux系统中所有进程通过PID进行标识,内核只需要管理一个PID列表,而且用户通过uname系统调用获取的系统相关信息也全部相同。在Linux系统中,用户的管理方式通过UID编号,即通过全局唯一的UID列表进行标识。全局ID能够使内核很好的管理系统,选择允许或拒绝某些特权。如UID为0的root用户能够允许做任何事情,但是其他UID的用户就会受到限制;对于用户X无法杀死另一个用户Y的进程,但是用户X可以看到用户Y的活动状态,而这种状态并不适用于一些场景,比如对于隐私性要求较高的服务。

为了解决上述类似的问题,Namespace机制为进程ID,用户ID等系列资源的隔离提供了一种占用资源极少的解决方案,而其它虚拟化方案一般需要一台物理机运行多个内核进行上述资源的隔离,命名空间可以在一台物理机上运行一个内核,通过命名空间机制将上述全局资源进行抽象。它可以使一组进程放置于容器中,而各个容器间彼此隔离,也可以设置容器之间进行共享。从用户的角度看,命名空间将全局资源控制进行了分割放置到相应的容器中,在容器中进程只能看到本容器中的成员而无法看到其他容器的成员。

命名空间层次关系

在上图中,我们可以看到三个命名空间,父命名空间记录管理了6个PID值,而两个子命名空间父命名空间知道子命名空间的存在,而两个子命名空间不知道对方的存在,对于进程各个子命名空间中属性的改变无法将影响传播到其它命名空间(包括父命名空间),这样在两个子命名空间中运行Linux内核就可以很好的隔离两个系统。

  • 命名空间在Linux内核中的表示

命名空间分别对UTS,进程间通信(IPC),文件系统视图,进程PID,UID和网络六个属性进行封装。

在每个Task任务结构中包含了一个nsproxy结构,这样对于每个创建的进程都有对应的命名空间,通过该结构可以建立进程与命名空间之间的关系,

对于命名空间的支持,需要在Linux内核编译的时候进行启动设置。如果没有设置,会使用系统默认的命名空间即整个内核就一个命名空间,全局可见。

对于每个具体的子命名空间实现形式,在此不再具体展开。

  • 命名空间在用户空间的表示

命名空间机制在用户层通过调用系统调用clone实现,clone系统调用与fIork系统调用的最大区别就是通过传入众多的参数选择性的继承父进程的资源,而flork系统调用就会复制父进程的资源。

通过设置flags参数就可以创建新的命名空间,选择性的继承父进程的资源。

flags设定为CLONE NEWPID时会创建一个新的PID命名空间,即该新的命名空间为进程提供了一个新的独立的P1D环境,调用clone系统的进程的ID号为1,就成为该命名空间的第一个进程,相当于Linux系统的lnit进程,由于是起始PID命名空间中的祖先进程,如果该进程结束在这个命名空间中的所有进程都会被结束。PID的命名空间具有层次性,在父命名空间中的进程可以创建出子命名空间,而子命名空间对父命名空间可见。

flags设定为CLONE—NEWIPC时会创建一个新的IPC命名空间,如果该标记没有设定,进程会根据父进程的参数进程设置。针对system V对象和POSIX信号队列的进程间通信机制,IPC命名空间可以进行隔离,即当前进程的通信对象或队列在本命名空间中对其它进程可见,而在不同命名空间中的进程进行通信类似于不同Linux系统间的通信。

flags设定为CLONE NEWUTS时会创建一个新的UTS命名空间,初始结构会以调用进程的UTS进行初始化,通过调用setdomainname函数和sethostname函数可以分别设置域名和主机名,调用uname函数可以获得UTS信息。

flags设定为CLONE NEWNS时会创建新的mount挂载点命名空间,建立的挂载点命名空间就是进程可见的文件结构视图,所以通过挂载命名空间可以很好的进行文件系统的隔离。

flags设定为CLONE NEWNET时会创建一个新的网络命名空间,网络命名空间对网络栈进行了视图上的隔离,包括IPV4,IPV6,栈协议,ip路由表,防火墙规则等。一个物理网络设备只能一次对应一个网络命名空间,但通过创建虚拟网络设备创建的隧道可以与实际的物理网络设备进行通信,这样就可以实现多个网络设备的通信。

以上所述的flags标识可以组合使用,LXC调用该接口可以很方便的创建独立的运行环境,设定相应的参数,完成操作系统级的虚拟化隔离。

3.2、Cgroup实现机制

LXC通过命名空间机制实现了资源的隔离,而对于物理资源的限制则通过cgroup(control group)机制实现。

cgroup系统定义了以下的概念:

1)控制群(control group):控制群就是一组进程组,是cgroup系统中的控制的基本单位。

2)子系统:子系统是一类资源控制系统,比如CPU,是对c铲oup中进程的控制具体方法,通过子系统可以针对每个cgroup进行限制。目前cgroup机制支持的子系统如下表所示:

3)层级:层级是各个控制群以树形的方式进行排列,子节点的控制权继承父节点的树形。linux系统中一个进程在其中的一个控制群中,同时也在其中的一个层级下。一个层级通过cgroup系统的虚拟文件系统相对应。

它们之间的层级关系如下图所示:

cgroup层级关系

在Linux系统中第一个被用户建立的cgroup是根cgroup,包含了系统中所有的进程,位于第一层级。在上图中根cgroup又被分为两个子的cgroup系统,即cgroup0和cgroupl,位于cgroup系统的第二层。一个子系统只能在一个层级上,即在第一层级的cpuset子系统不同加入第二层级中的cgroup0和cgroupl,因为前面已经说过层级中子节点需要继承父节点的属性,如果两个层级中都有则会出现重复。每个层级可以有多个子系统,如第二层级有cpu和memo巧子系统。对于进程来说,可以位于不同层级的cgroup中。

  • cgrouplinux内核层的表示

cgroup相关的数据结构和命名空间类似,也是从进程管理结构开始。如果需要使用cgroup机制需要在Linux内核编译的时候开启CONFIG_CGROUPS宏。在css_set结构中存储了与进程相关cgroups信息,在cg_list将在同一个css_set的进程组链接起来。Css_set结构如下

css_set结构中最重要成员就是cgroup_subsys_state指针数组,在进程和cgroup之间没有直接的联系,需要通过cgroup_subsys_state间接指向cgroup结构,这样做主要是因为有的时候读取子系统状态会比较频繁而对cgroup赋值等操作较少,struct cgroup中有一个成员cgroupfsroot结构,就是用于我们前面所说的层级关系的具体实现。

对于子系统的管理,则通过cgroup_subsys数据结构进行管理。在该结构中定义了一组操作的接口函数指针,相当于c++的基类,给出了接口函数具体的行为需要针对每个子系统的特点进行自行定义,比如cgroup subsys_state接口每个子系统返回的信息是不同的,需要不同的实现,这样的设计就可以很好的完成多种类型的兼容。

  • cgroupLinux用户层的表示

cgroup在linux用户层通过cgroup文件系统方式表示出来。比如在用户空间可以通过执行如下命令:mount -t cgroup -o cpu,memory cpu_mem/mycgroup/cpu_mem就可以创建名字为cpu_mem的层级,这个层级中有cpu和memory两个子系统,这两个系统可以是挂载至lJ/mycgroup/cpu_mem文件下。这一个创建cgroup层级的过程就如同创建新的文件夹的过程,只是创建的是cgroup特殊文件系统。如果在cpu_mem系统中想要创建一个新的cgroup,只要进入cpu_mem文件目录下,执行命令mkdir newcgroup就可以创建一个叫newcgroup的控制群,这样也表示新创建的cgroup是属于cpu_mem这一个层级。进入newcgroup文件目录后,会有相关子系统的控制文件,可以读取或者修改这些控制文件,比如向的tasks文件中写入当前系统中某个进程的pid号就相当于将进程加入了新创建的cgroup控制群中。

时间: 2024-10-29 19:12:33

Linux Container(LXC)容器隔离实现机制的相关文章

LXC容器

1.    LXC简述 Linux container是一种资源隔离机制而非虚拟化技术.VMM(VMM Virtual Machine Monitor)或者叫Hypervisor是标准的虚拟化技术,这种技术通过虚拟层(也就是VMM或叫Hypervisor),主要作用一是让多个操作系统和应用共享硬件资源, 其二是把上层虚拟机的指令转换成底层Host操作系统所认识的指令,这就意味着在Linux上可以跑windows系统,container技术介于chroot和VM之间,其“虚拟机”和主机操作系统相同

Linux 下 LXD 容器搭建 Hadoop 集群

配置要求 主机内存 4GB . 磁盘 100 GB 以上. HOST 机安装常用 Linux 发行版. Linux Container ( LXD ) 以主机 ubuntu 16.04 为例. 安装 LXD . $ sudo apt-get install lxd $ newgrp lxd $ sudo lxd init 查看可用的镜像源,如果使用默认的 image ,可以跳过下面两步,直接进入后面的 launch . $ lxc remote list 选取上一步喜欢的 image ,复制链接

技术解析系列 | PouchContainer 支持 LXCFS 实现高可靠容器隔离

技术解析系列 | PouchContainer 支持 LXCFS 实现高可靠容器隔离 划重点 本周起 PouchContainer 启动核心技术专家解析系列文章,第一篇文章将深入剖析 LXCFS 适用业务场景和原理,对 LXCFS 感兴趣的同学不要错过 引言 PouchContainer 是 Alibaba 开源的一款容器运行时产品,当前最新版本是 0.3.0,代码地址位于:https://github.com/alibaba/pouch.PouchContainer 从设计之初即支持 LXCF

LXC容器运行X Server(续1)

容器要运行X桌面环境可通过ssh,xdmcp远程方式,此时容器是X Client,容器是无需安装X Server.上篇( https://blog.51cto.com/13752418/2440496 )容器中以本地方式运行X是在宿主的虚拟终端(如vt09)上运行容器X.本文是续篇,同样容器中以本地方式运行X Server,介绍的内容是容器运行X在宿主的桌面窗口之上,容器以本地方式登录桌面环境,即界面上类似VirtualBox的方式. 实验环境 : debian 11 主机名 shell提示符

Linux 内核的文件 Cache 管理机制介绍

Linux 内核的文件 Cache 管理机制介绍 文件 Cache 管理是 Linux 内核中一个很重要并且较难理解的组成部分.本文详细介绍了 Linux 内核中文件 Cache 管理的各个方面,希望能够对开发者理解相关代码有所帮助. http://www.ibm.com/developerworks/cn/linux/l-cache/ http://www.cnblogs.com/MYSQLZOUQI/p/4857437.html 1 前言 自从诞生以来,Linux 就被不断完善和普及,目前它

Docker(linux container) 所依赖的底层技术

1 Namespace 用来做PID的隔离,有了namespace,在docker container里头看来,就是一个完整的linux的世界.在host看来,container里的进程,就是一个普通的host进程,namespace提供这种pid的映射和隔离效果,host承载着container,就好比造物者创造一个个世外桃源. 2 Cgroups 在我的另外一篇博文里,有详细介绍cgroup如何做到内存,cpu和io速率的隔离,移步cgroups 3 Chroot 如何在container里

python Linux 环境 (版本隔离工具)

python Linux 环境 (版本隔离工具) 首先新建用户,养成良好习惯useradd python 1.安装pyenv GitHub官网:https://github.com/pyenv/pyenv-installer pyenv installer This tool installs pyenv and friends. It is inspired by rbenv-installer. Prerequisites In general, compiling your own Pyt

关联容器(底层机制) — hashtable

C++ 11已将哈希表纳入了标准之列.hashtable是hash_set.hash_map.hash_multiset.hash_multimap的底层机制,即这四种容器中都包含一个hashtable. 解决碰撞问题的办法有许多,线性探测.二次探测.开链等等.SGI STL的hashtable采用的开链方法,每个hash table中的元素用vector承载,每个元素称为桶(bucket),一个桶指向一个存储了实际元素的链表(list),链表节点(node)结构如下: template <cl

关联容器(底层机制) — 红黑树

set.map.multiset.multimap四种关联式容器的内部都是由红黑树实现的.在STL中红黑树是一个不给外界使用的独立容器.既然是容器,那么就会分配内存空间(节点),内部也会存在迭代器.关于红黑树的一些性质,可以参考"数据结构"中的笔记,这里只记录STL中的红黑树是如何实现的. 和slist一样,红黑树的节点和迭代器均采用了双层结构: 节点:__rb_tree_node继承自__rb_tree_node_base 迭代器:__rb_tree_iterator继承自__rb_