一、DockerLXCCgroup的结构关系

根据Docker布道师Jerome Petazzoni的说法,Docker约等于LXC+AUFS(之前只支持ubuntu时)(作者2015-10-22更新:Docker0.9.0版本开始引入libcontainer,可以视作LXC的替代品)。其中LXC负责资源管理,AUFS负责镜像管理;而LXC包括cgroupnamespacechroot等组件,并通过cgroup进行资源管理。所以只从资源管理这条线来看的话,DockerLXCCgroup三者的关系是:Cgroup在最底层落实资源管理,LXCcgroup上封装了一层,Docker又在LXC封装了一层,关系图如图1b)所示。因此,要想玩转Docker,有必要了解负责资源管理的CGroupLXC

wKiom1MBskzjI9ErAAFj5lAmO3Q417.jpgwKioL1MBsifiKhKiAADIayV7OHg252.jpg

(a)                                                                                    (b)

1 Docker-LXC-CGroup结构图


二、Cgroup

1Cgroup基本概念

1Cgroup是什么

Cgroupscontrol groups的缩写,是Linux内核提供的一种可以限制、记录、隔离进程组(process groups)所使用的物理资源(如:CPU, Memory, IO等)的机制。最初由Google的工程师提出,后来被整合进Linux内核。Cgroups也是LXC为实现虚拟化所使用的资源管理手段,可以说没有Cgroups就没有LXC,也就没有Docker

Cgroups最初的目标是为资源管理提供的一个统一的框架,既整合现有的Cpuset等子系统,也为未来开发新的子系统提供接口。现在的Cgroups适用于多种应用场景,从单个进程的资源控制,到实现操作系统层次的虚拟化(OS Level Virtualization)。Cgroups提供以下功能:

a)限制进程组可以使用的资源数量(Resource limiting )。比如:Memory子系统可以为进程组设定一个Memory使用上限,一旦进程组使用的内存达到限额再申请内存,就会出发OOMout of  memory)。

b)进程组的优先级控制(Prioritization)。比如:可以使用CPU子系统为某个进程组分配特定CPUshare

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

d)记录进程组使用的资源数量(Accounting)。比如:可以使用Cpuacct子系统记录某个进程组使用的CPU时间

e)进程组控制(Control)。比如:使用freezer子系统可以将进程组挂起和恢复。


2Cgroup基本概念与术语

任务(task

Cgroups中,任务就是系统的一个进程。

控制族群(control group

控制族群就是一组按照某种标准划分的进程,控制族群通常按照应用划分,即与某应用相关的一组进程,被划分为一个进程组,即控制族群(control group)。Cgroups中的资源控制都是以控制族群为单位实现。一个进程可以加入到某个控制族群,也可以从一个进程组迁移到另一个控制族群。一个进程组的进程可以使用Cgroups以控制族群为单位分配的资源,同时受到Cgroups以控制族群为单位设定的限制。

层级(hierarchy

控制族群可以组织成hierarchical的形式,既一颗控制族群树。控制族群树上的子节点控制族群是父节点控制族群的孩子,继承父控制族群的特定的属性。控制族群树的示意图如图2所示。

wKioL1MBsumgSJooAAC8HGuob-w109.jpg

2 控制族群树结构示意图

子系统(subsystem

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


3Cgroup子系统介绍

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

b)cpu -- 这个子系统使用调度程序提供对CPU Cgroup 任务访问。

c)cpuacct -- 这个子系统自动生成Cgroup中任务所使用的 CPU 报告。

d)cpuset-- 这个子系统为 Cgroup中的任务分配独立CPU(在多核系统)和内存节点。

e)devices -- 这个子系统可允许或者拒绝Cgroup中的任务访问设备。

f)freezer -- 这个子系统挂起或者恢复Cgroup中的任务。

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

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

i)ns -- 名称空间子系统。

Cgroup具有不同的挂载方法——“多挂载点”和“单挂载点”。子系统“多挂载点”挂载就是指不同子系统的文件挂载在不同的目录下,每个子系统各有一个挂载点,目录结构如图3a)所示。cgroup对应服务cgconfig默认使用的就是“多挂载点”的方法。“单挂载点”则是指所有子系统的文件都挂载在同一个目录下,所有子系统都统一挂载在一个挂载点,目录结构如图3b)所示。

wKioL1MBsq6wjiCsAAA8a6SxaGI637.jpg

3acgroup多挂载点目录结构示意图

wKiom1MBsujQSaqfAAQEMBSdJMs878.jpg

3bcgroup单挂载点目录结构示意图


2Cgroup安装配置

1Cgroup安装


安装Cgroups需要libcap-devel和libcgroup两个相关的包,CentOS上可以通过yum的方式下载安装,具体的命令为:

yum install gcc, libcap-devel,libcgroup, bridge-utils

2Cgroup挂载配置

Cgroup对应服务名称为cgconfigcgconfig默认采用“多挂载点”挂载。经过实际测试,发现在CentOS环境中应采用“单挂载点”进行挂载,因此应当卸载原有cgroup文件系统,并禁用cgconfig

cgclear或者sudo service cgconfig stop # 停止cgconfig,卸载cgroup目录

sudo chkconfig cgconfig off          # 禁用cgconfig服务,避免其开机启动

然后采用“单挂载点”方式重新挂载cgroup

可以直接手动挂载,这样仅当次挂载成功。

mount -t cgroup none /cgroup

然后编辑/etc/fstab/,输入下列内容。这样每次开机后都会自动挂载。

none   /cgroup  cgroup  defaults   0 0


3)常用的Cgroup相关命令和配置文件

service cgconfig status|start|stop|restart    #查看已存在子系统

lssubsys –am    #查看已存在子系统

cgclear   # 清除所有挂载点内部文件,相当于service  cgconfig stop

cgconfigparser -l /etc/cgconfig.conf    #重新挂载


Cgroup默认挂载点(CentOS):/cgroup

cgconfig配置文件:/etc/cgconfig.conf


4libcgroup Man Page简介

man 1 cgclassify -- cgclassify命令是用来将运行的任务移动到一个或者多个cgroup

man 1 cgclear -- cgclear 命令是用来删除层级中的所有cgroup

man 5 cgconfig.conf -- cgconfig.conf文件中定义cgroup

man 8 cgconfigparser -- cgconfigparser命令解析cgconfig.conf文件和并挂载层级。


man 1 cgcreate -- cgcreate在层级中创建新cgroup

man 1 cgdelete -- cgdelete命令删除指定的cgroup

man 1 cgexec -- cgexec命令在指定的cgroup中运行任务。

man 1 cgget -- cgget命令显示cgroup参数。

man 5 cgred.conf -- cgred.confcgred服务的配置文件。

man 5 cgrules.conf -- cgrules.conf 包含用来决定何时任务术语某些  cgroup的规则。


man 8 cgrulesengd -- cgrulesengd  cgroup 中发布任务。

man 1 cgset -- cgset 命令为  cgroup 设定参数。

man 1 lscgroup -- lscgroup 命令列出层级中的  cgroup

man 1 lssubsys -- lssubsys 命令列出包含指定子系统的层级。


三、Linux ContainerLXC

1LXC基本概念

1LXC是什么

LinuxContainer容器可以提供轻量级的虚拟化,以便隔离进程和资源,而且不需要提供指令解释机制以及全虚拟化的其他复杂性。容器有效地将由单个操作系统管理的资源划分到孤立的组中,以更好地在孤立的组之间平衡有冲突的资源使用需求。

LXC建立在CGroup基础上,我们可以粗略的认为LXC = Cgroup+ namespace + Chroot + veth +用户态控制脚本。LXC利用内核的新特性(CGroup)来提供用户空间的对象,用来保证资源的隔离和对于应用或者系统的资源控制。

根据LXC官网(http://linuxcontainers.org/)的描述,LXC具有以下特性:

Current LXC uses the following kernel features to  contain processes:


Kernel namespaces (ipc, uts, mount, pid, network and  user)

Apparmor and SELinux profiles

Seccomp policies

Chroots (using pivot_root)

Kernel capabilities

Control groups (cgroups)


1LXC的优势

与虚拟化相比,它的优势在于:

a)不需要指令级模拟;

b)不需要即时(Just-in-time)编译;

c)容器可以在CPU核心的本地运行指令,而不需要任何专门的解释机制;

d)避免了准虚拟化和系统调用替换中的复杂性。

总结来说,就是LXC更加轻量级,具有更小的性能开销、更快的相应时间。


2LXC安装与使用

1LXC安装

sourceforge.net/projects/lxc/files/lxc下载lxc源码

解压后进入目录,执行以下命令:

./configure

make

sudo make install


2LXC常用命令

参考:http://www.cnblogs.com/lisperl/archive/2012/04/13/2446179.html


lxc-checkconfig # 查看内核支持

lxc-create -n name -f config

lxc-start -n name -f config cmd

lxc-execute -n name -f config cmd

# 备注:lxc-start只启动一个进程,即cmdlxc-execute  启动两个进程,lxc-initcmd


lxc-kill -n name #SIGNUM信号

lxc-stop -n name # 停止lxc内所有进程

lxc-destroy -n name # 销毁进程

lxc-cgroup -n name subsys value #  控制资源,例如 lxc-cgroup -n name  cpuset.cpus 0,3


3)资源控制

Cores

lxc.cgroup.cpuset.cpus=1,2,3

CPU  share

lxc.cgroup.cpu.shares=1024 # default

Memory  usage (!Debian)

lxc.cgroup.memory.limit_in_bytes = 256M

lxc.cgroup.memory.memsw.limit_in_bytes = 1G

Disk  (blkio)

Disk  space – standard LVM, quota...

echo 100 > /cgroup/disk1/blkio.weight # XXX <  1000 !

echo "3:0 1048576" >/cgroup/disk1/blkio.throttle.read_bps_device

lxc.cgroup.blkio.weight = 100


4)配置文件样例

lxc.utsname =  host_name

lxc.tty = 1

lxc.network.type = veth

lxc.network.flags = up

lxc.network.link = br0

lxc.network.ipv4 = 192.168.120.105/16

lxc.network.name = eth0

#lxc.mount = ./fstab

#lxc.rootfs = /rootfs

lxc.cgroup.cpuset.cpus = 0

lxc.cgroup.cpu.shares = 80


5)使用中的一些小问题

lxc-ls  #列出所有lxc,但是在centos下时常不好用。备注lxc-create之后lxc-ls才能看到。但是只lxc-create,而不execute,则并未实际启动congtainer,相应cgroup并未实际挂载。


lxc-ps # 列出指定container内的所有进程。备注:lxc-ps –n name或者lxc-ps –n name -- -ef