LXC,Linux containers

1 LXC安装

[root@41-dev ~]# wget <a href="http://lxc.sourceforge.net/download/lxc/lxc-0.9.0.tar.gz">http://lxc.sourceforge.net/download/lxc/lxc-0.9.0.tar.gz</a>

[root@41-dev lxc-0.9.0]# ./configure

[root@41-dev lxc-0.9.0]# make

[root@41-dev lxc-0.9.0]# make install

[root@41-dev lxc-0.9.0]# which lxc-version

/usr/bin/which: no lxc-version in (/usr/java/jdk1.6.0_43/bin:/usr/java/jdk1.6.0_43/jre/bin:/usr/lib64/ccache:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/adt/sdk/platform-tools:/root/adt/sdk/tools:/root/bin)

[root@41-dev lxc-0.9.0]# lxc-version

bash: lxc: command not found..

[root@41-dev lxc-0.9.0]# cd /usr/local/bin/

[root@41-dev bin]# ls

lxc-attach  lxc-checkconfig  lxc-clone    lxc-create   lxc-execute  lxc-info  lxc-ls       lxc-netstat  lxc-restart   lxc-start  lxc-unfreeze  lxc-version

lxc-cgroup  lxc-checkpoint   lxc-console  lxc-destroy  lxc-freeze   lxc-kill  lxc-monitor  lxc-ps       lxc-shutdown  lxc-stop   lxc-unshare   lxc-wait

&nbsp;

&nbsp;

[root@41-dev bin]# export PATH=$PATH:/usr/local/bin

[root@41-dev bin]# echo $PATH

/usr/java/jdk1.6.0_43/bin:/usr/java/jdk1.6.0_43/jre/bin:/usr/lib64/ccache:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/adt/sdk/platform-tools:/root/adt/sdk/tools:/root/bin:/usr/local/bin

2 LXC的介绍

Lxc 全称,Linux containers,是一种基于容器的操作系统层级的虚拟化技术。LXC可以在操作系统层级上提供虚拟的执行环境,一个虚拟机的执行环境就是一个容器,可以为该容器绑定特定的CPU、Memory节点,并可以分配特定比例的CPU时间,IO时间,限制可以使用的内存大小(包括内存和swap空间),提供device访问控制,提供独立的namespace(网络,pid,ipc,mnt,uts);

LXC依靠Linux内核相关特性,基于容器的虚拟化技术起源于所谓的资源容器和安全容器,LXC在资源管理方面依赖与Linux内核的Cgroups子系统,Cgroups子系统是Linux内核提供的一个基于进程组的资源管理框架,可以为特定的进程组限定可以使用资源,LXC在资源隔离控制方面依赖与Linux内核的namespace特性,具体而言就是在clone时加入相应的flag(NEWNS NEWPID)等。

LXC和传统的HAL(硬件抽象层)层次的虚拟化技术相比,具有以下优势:

1 更小的虚拟化开销(LXC的诸多特性有Kernel提供,Kernel实现这些特性只有极少的消耗)

2       快速部署,不需要创建虚拟机,只需要安装LXC,不需要单独为内核打补丁。

1 Cgroups

Cgroups子系统是(control groups的缩写),是Linux内核提供的一种可以限制、记录、隔离进程组(process)所使用的物理资源(cpu,memory,io.etc)机制。

Cgroups最初的目标为资源管理器提供统一的框架,既整合现有的cpuset等子系统,也为未来开发新的子系统提供接口,现在的cgroups适用于多种应有场景,从单独的进程资源控制,到实现操作系统层次的虚拟化。

1 限制进程组可以使用资源的数量,Resource Limiting,如,memory子系统可以为进程设定一个memory使用上限,一旦进程组使用的内存达到限额再申请内存,就会触发OOM(Out of memory).

2 进程组的优先级控制,比如,可以使用CPU子系统为某个进程组分配特定的cpu share.

3 记录进程组使用的资源数量,比如可以使用cpuacct子系统记录某个进程使用cpu的时间。

4 进程组隔离,比如使用ns子系统可以使不同的进程组使用不同的namespace,以达到隔离的目的,不同的进程组有各自的进程、网络、文件系统挂载空间。

5 进程组控制,比如使用freezer子系统将进程组挂起和恢复。

Cgroups的相关概念:

1 任务:(task),在cgroups中,任务就是系统的一个进程

2 控制族群,(control groups)。控制族群就是一组按照某种标准划分的进程,Cgroups

中的资源控制是一控制族群为单位实现,一个进程可以加入到某个控制族群,也从一个进程组迁移到另一个进程组群。一个进程组的进程可以使用cgroups以控制族群为单位分配资源,同时也受到cgroups以控制族群为单位设定的限制。

3 层级,(hierarchy).控制族群可以组织成hierarchical的形式,既一颗控制族群树,控制族群树上的子节点控制族群是父节点控制族群的孩子。继承父控制族群的特定的属性。

4 子系统,(subsystem)。一个子系统就是一个资源控制器, 比如cpu子系统就是控制cpu时间分配器的一个控制器,子系统必须附加attach到一个层级上才能起作用,一个子系统附加到某个层级以后,这个层级上的所有控制族群都受到这个子系统的控制。

Cgroups的系统相互关系

1 每次在系统中创建新层级时, 该系统中的所有任务都是那个层次的默认cgroup.(root cgroup,此 cgroup在创建层级时,自动创建,后面在该层级中创建的cgroup都是此cgroup的后代)的初始成员。

2 一个子系统最多只能附加到一个层级。

3 一个层级可以附加多个子系统

4 一个任务可以是多个cgroup的成员,但这些cgroup必须在不同的层级。

5 系统中的进程(任务)创建子进程(任务)时,该子任务自动成为其父进程所在的cgroup的成员。 然后可以根据需要将该子任务移动到不同的cgroup中,但开始时,总是继承其父任务的cgroups

Cgroups子系统介绍

blkio–这个子系统为块设备设定输入/输出限制,比如物理设备(硬盘,固态硬盘,usb等)

cpu–这个子系统使用调度程序提供对CPU的cgroup 任务访问

cpuacct– 这个子系统自动生成cgroup中任务所使用的cpu报告

cpuset –这个子系统为cgroup中的任务分配独立CPU和内存节点

devices–这个子系统允许或者拒绝cgroup中的任务访问设备

freezer– 这个子系统刮起或者恢复cgroup中的任务

memory — 这个子系统设定cgroup中任务内存的限制,并自动生成由那些任务使用的内存资源报告。

Net_cls–这个子系统使用等级识别符(classid)标记网络数据包,可以允许linux流量控制程序tc,识别从具体cgroup中生成的数据包

Ns — 命名空间子系统。

 

2 Namespaces机制

Linux Namespaces机制提供了一种资源隔离方案,PID、IPC、NetWork等系统资源不再是全局性的,而是属于特定的Namespace.每个Namespaces里面的资源对其他的Namespace都是透明的。要创建新的Namespace,只需要调用clone 时指定相应的flag。当调用clone时,设定为CLONE_NEWPID.就会创建一个新的pid Namespaces。clone出来的新进程将成为NameSpace里的第一个进程,一个PID Namespace 为进程提供了一个独立的PID环境,PID namespace内的PID将从1开始,在Namespace内调用fork,vfork,或clone都将产生一个在该Namespace内部独立的PID。新创建的Namespace里的第一个进程在该Namespace内的PID为1.PID namespace 是层次性的,新建的Namespace将会创建该Namespace的进程属于Namespace的子namespace。子namespace中的进程对于父namespace是可见的,一个进程将拥有不止一个PID。而是在所在的Namespace中的进程对所有直系祖先Namespace中都将有有一个PID。

当调用Clone,设定了Clone_NEWIPC.将会创建一个新的IPCNamespace,clone出来的进程将成为Namespace里的第一个进程,一个IPC Namespace 有一组System V IPC objects标识符构成,这个标识符有IPC相关的系统调用创建, 在一个IPC Namespace里面创建IPC object 对该Namespace内的所有进程可见,但对其他的Namespace不可见,这样就使的不同的Namespace 之间的进程不能直接通信。PID namespace和IPCnamespace可以组合起来一起使用,只需要在调用clone时,同时指定CLONE_NEWPID|CLONE_NEWIPC.

当调用Clone时,设定了CLONE_NEWNS,就会创建一个新的mount Namespace,每个进程都存在于一个mount namespace里面,mount namespace为进程提供一个文件层次视图,如果不设定这个flag,子进程和父进程共享一个mount namespace,其后子进程调用mount或umount将会影响到所有该Namespace内的进程,如果子进程在一个独立的mount namespace里面,就可以调用mount或umount建立一份新的文件层次视图。该flag配合pivot_root系统调用,可以为进程创建一个独立的目录空间。

当调用clone,设定CLONE_NEWNET,就会创建一个新的NetWork Namespace.一个network namespace为进程提供了一个完全独力的网络协议栈的视图,包括网络设备接口,IPV4/IPV6协议栈,IP路由表,防火墙规则,sockets等。一个Network namespace提供了一个独立的网络环境,就跟一个独立的系统一样。一个物理设备只能存在一个Network namespace中,可以从一个namespace 移动到另一个Namespace中,虚拟网络设备提供了一种类似管道的抽象,可以在不同的Namespace之间建立隧道,利用虚拟化网络设备,可以建立到其他的namespace中的物理设备桥接,当一个Namespace被销毁时,物理设备会自动移回init network namespace,即系统最开始的namespace.

当调用clone,设定CLONE_NEWUTS,就会创建一个新的UTS Namespace,一个UTSnamespcae 就是一组被uname返回的标识符,新的UTS namespace 中的标识符通过复制调用进程所属的namespace的标识符来初始化,clone出来的进程可以通过相关系统调用改变这些标识符,比如sethostname来改变namespace的hostname。这一改变,对namespace内所有进程可见。CLONE_NEWUTS和CLONE_NEWNET可以一起使用。

以上所有clone flag 都可以一起使用,为进程提供了一个独立的运行环境,LXC正是通过在clone时设定flag,为进程创建对立PID,IPC,FS,NETWORK,UTS的空间容器,一个容器就是一个虚拟的运行环境,对容器的进程是透明的,每个进程都以为自己直接在系统上运行。

chromium在sandbox里将设置namespace的代码:

 

12 static bool MoveToNewNamespaces() {

213   // These are the sets of flags which we'll try, in order.

214   const int kCloneExtraFlags[] = {

215     CLONE_NEWPID | CLONE_NEWNET,

216     CLONE_NEWPID,

217   };

218

219   // We need to close kZygoteIdFd before the child can continue. We use this

220   // socketpair to tell the child when to continue;

221   int sync_fds[2];

222   if (socketpair(AF_UNIX, SOCK_STREAM, 0, sync_fds)) {

223     FatalError("Failed to create a socketpair");

224   }

225

226   for (size_t i = 0;

227        i &lt; sizeof(kCloneExtraFlags) / sizeof(kCloneExtraFlags[0]);

228        i++) {

229     pid_t pid = syscall(__NR_clone, SIGCHLD | kCloneExtraFlags[i], 0, 0, 0);

发表评论

您的电子邮箱地址不会被公开。