转自: https://xiaohui-p.iteye.com/blog/1180130
作者: xiaohui_p
发布: 2017-05-04 19:15
容器有效地将由单个操作系统管理的资源划分到孤立的组中,以更好地在孤立的组之间平衡有冲突的资源使用需求。与虚拟化相比,这样既不需要指令级模拟,也不需要即时编译。容器可以在核心 CPU 本地运行指令,而不需要任何专门的解释机制。此外,也避免了准虚拟化(paravirtualization)和系统调用替换中的复杂性。
Fedora 13, 2.6.33内核
# yum install lxc
# lxc-checkconfig
如果输出所有项均为enbale状态,则表明内核支持lxc容器,否则需重新编译内核打开相应功能项。
#Simplest lxc configuration
lxc.utsname = name
# mkdir /cgroup
# mount –t cgroup cgroup /cgroup
# lxc-execute -n test -f conf.txt /bin/echo “hello world”
hello world
# /bin/echo “cgroup /cgroup cgroup defaults 0 0” >> /etc/fstab
lxc-create -n name [-f config_file] [ -t template]
创建一个系统对象来存储配置和用户信息,该对象保存/usr/local/var/lib/lxc(注意该目录为版本相关的,不同版本的lxc可能不同)目录下,name为其标示符。如果配置文件未指定,则系统会支持默认的资源隔离:PID,sysv IPC和挂载点。
例如:
# lxc-create -n test
创建容器test,可在/usr/local/var/lib/lxc目录下发现创建了目录test,该文件中包含了默认的配置文件config
lxc-destroy -n name
销毁一个名称为name的容器,主要删除在/usr/local/var/lib/lxc中相应的文件,注意一定要在容器处于STOPPED状态时才能销毁容器.
例如:
# lxc-destroy -n test
销毁容器test.
a) lxc-execute -n name [-f config_file] [-s EKY=VAL] command
在指定的容器name中运行由command指定的命令。如果容器name未创建,则lxc-execute使用指定的配置文件创建容器name。该命令通过中间进程lxc-init来启动需要运行的命令,并且lxc-init在创建命令后会等待该命令执行结束。因此lxc-init进程的pid为1,运行的命令的pid为2。
b) lxc-start -n name [-f config_file] [-s KEY=VAL] command
lxc-start在指定容器name中运行command指定的命令。注意lxc-start不支持孤儿进程组和守护进程,且如果command未指定,则会运行/sbin/init命令。
例如:
# lxc-create -n test –f conf.txt /bin/bash #运行bash
# lxc-start -n test /bin/bash #运行bash
注意,lxc-create用于在容器中运行一个应用,而lxc-start则用于在容器中运行一个系统。
lxc-stop -n name
``
终止容器name的运行。例如:
```sh
# lxc-stop -n test #终止容器test的运行
如果创建容器时候配置了tty,可通过如下命令连接到tty
lxc-console -n test -t 3 #连接到容器test的3号tty上。
lxc-freeze -n name
冻结所有在容器name中运行的程序,此处冻结是指挂起所有在指定容器中运行的程序。必须显式的使用lxc-ufreeze命令解除冻结。
#lxc-freeze -n foo #冻结容器foo中运行的所有程序
lxc-unfreeze -n name
解除容器name的冻结状态.
#lxc-ufreeze -n foo #将foo中冻结的程序恢复运行。
注意:该功能需要内核打开相应的功能!
列出系统中存在的所有容器,选项和ls命令相同。
lxc-info -n name
列出容器name的运行信息:输出格式如下:
name is stopped
name is running
显示特定容器的pids,选项和ps相同,为内置的ps
显示指定容器的网络状态,该命令建立在命令netstat之上,因此接受于netstat相同的参数。
lxc-cgroup -n name subsystem [value]
显示或者设置与控制组相关联的子系统的值,如果value未指定则显示其值,否则设定相应子系统的值。 例如:
lxc-cgroup -n foo devices.list #显示允许容器foo使用的设备列表
lxc-cgroup -n foo cpuset.cpus “0,3” #将处理器0和3分配给容器foo
lxc-monitor -n name
监控指定容器的状态,其中名称为正则表达式。 例如:
lxc-monitor -n ‘foo|bar’ #监控容器foo和bar
lxc-monitor -n ‘.*’ #监控所有容器
lxc-monitor -n ‘[f|b].*’ #监控所有名称以f或b开始的容器
lxc-wait -n name -s states
等待容器到达某一状态,然后退出,其中states可为若干状态. 例如:
lxc-wait -n foo ‘RUNNING’ #等待容器到RUNNING状态
lxc-wait -n foo ‘RUNNING|STOPPED’ #等待容器到达RUNNING或者STOPPED状态
注意:容器的状态分为:STOPPED, STARTING ,RUNNING, STOPPING, ABORTING.
lxc-kill -n name SIGNUM
lxc-kill将信号SIGNUM发送给容器中的第一个进程。例如:
lxc-kill -n foo 2 #向foo中第一个进程发送SIGINT信号
注意:如果使用lxc-execute运行的命令,信号首先发送给lxc-init,然后lxc-init将该信号传递给运行的第二个进程。如果发送的信号使得lxc-init进程终止,那么该信号不会传递给运行的第二个进程,并且导致容器中得应用结束运行。
每个lxc容器都对应于一个配置文件,该文件可在使用lxc-create、lxc-execute和lxc-start命令时指定,如果通过lxc-create创建的容器,则会在/var/lib/lxc/container-name/config中保存该配置。配置信息包括:主机名、网络、cgroup信息等。lxc配置文件中每一行采用key=val的形式,每行保存一个配置项。注释以#开头。
lxc.utsname = foo #配置主机名为foo
lxc.network.type: 指定容器使用的虚拟化网络类型,该域一般为新的网络配置的开始,其可能值为:
值 | 类型 |
---|---|
empty | 创建仅有回路接口的网络 |
veth | 创建一个对等网络,该网络的一端分配给容器,另一端与lxc.network.link指定的网桥连接。如果未指定网桥,端设备会被创建但是不会连接到任何网桥上。在默认情况下lxc会对容器外的网络设备选择一个名字,但是可以通过lxc.network.veth.pair选项来指定。 |
vlan | 创建一个由lxc.network.link指定的虚拟局域网接口(网卡)分配给容器,vlan的标识符可由lxc.network.vlan.id指定。 |
phys | 将由lxc.network.link指定的已经存在的接口(网卡)分配给容器。 |
macvlan | 创建一个macvlan接口,该接口和由lxc.network.link指定的接口相连接。 |
lxc.network.flags:指定网络将要执行的动作,可选值为:
lxc.network.link: 指定用于进行真实网络通信的接口(网卡)。
lxc.network.name: 指定网络接口的名称,在默认情况下,接口名称是动态分配的。
lxc.network.hwaddr: 指定虚拟网络接口(虚拟网卡)的MAC地址,在默认情况下,该值自动分配。
lxc.network.ipv4: 指定分配给虚拟网卡的ipv4地址。
lxc.network.ipv6: 指定分配给虚拟网卡的ipv6地址。
lxc.mount:指定包含挂载信息的文件,该文件内容采用fstab格式。fstab格式如下:
spec file type options dump pass
如下是一个典型的fstab文件:
none /lxc/rootfs.fedora/dev/pts devpts defaults 0 0
none /lxc/rootfs.fedora/proc proc defaults 0 0
none /lxc/rootfs.fedora/sys sysfs defaults 0 0
lxc.mount.entry: 指定一个挂载点,该行采用fstab格式。
lxc.rootfs:指定容器的根文件系统,若该项未指定,则采用和主机相同的根文件系统。
例如:
lxc.rootfs=/lxc/test/rootfs
lxc.rootfs.mount:指定调用pivot_root前lxc.rootfs绑定点,一般情况下使用默认值即可。
备注:pivot_root改变根文件系统,格式为:pivot_root new_root put_old。pivot_root将当前进程的根文件系统移动到目录put_old下,并使得new_root作为新的根文件系统。
lxc.pivotdir:指定原始根文件系统在lxc.rootfs下的支点(pivot)。
lxc.cgroup.blkio.weight: 指定当前组块设备优先级权重,权重允许的范围为100~1000.
在控制组中另外只读的项:
blkio.time:控制组中指定使用块设备的时间(毫秒),格式为:major:minor times,其中前两个域为主从设备号,第三个域为时间。
blkio.sectors: 组传输的扇区数,格式为:major:minor sectors,其中前两个域为主从设备号,第三个域为传输的扇区数。
在控制组中cpu时间统计信息项:
lxc.cgroup.cpuset.cpus:在cpuset中得cpu列表。列表中cpu从0开始编号,如果系统中存在100个cpu那么cpu的编号为0~99. 例如:
注意:该项指定的CPU集合必须为父cpu集合的子集。
lxc.cgroup.cpuset.mems:分配给该cpuset的内存节点列表,例如:
lxc.cgroup.cpuset.mems = 0,1 #将内存节点0和1分配给该组
lxc.cgroup.cpuset.memory_migrate: 如果该项设置为真,当将一个任务连接到新的cpuset时,任务所在前cpuset中分配给该任务的页也被迁移到新的cpuset中,并且尝试确保页所在节点列表的相对位置不变。比如,分配给任务的某一页在前cpuset内存节点中的第二个节点中,则迁移时会尝试将其放到新的cpuset内存节点列表中第二个内存节点中。此外,如果设定了该项,当cpuset中的内存节点列表(cpuset.mems)发生变化时,分配给任务的页被迁移到新的内存节点列表的节点中。
lxc.cgroup.cpuset.cpu_exclusive: cpuset中cpu独占标记,只有在父cpuset设定该项后,子cpuset才可设置该项。当设定该项后,除了祖先和后代cpuset外,lxc.cgroup.cpuset.cpus指定的cpu不允许出现在任何其他cpuset的cpu列表中。
lxc.cgroup.cpuset.mem_exclusive:cpuset中内存节点独占标记。配置规则和lxc.cgroup.cpuset.cpu_exclusive相同。
lxc.cgroup.cpuset.memory_hadwall:该项指定内核分配内存页和缓存数据时是否仅限于从分配给cpuset的内存节点中分配。在默认情况下,该项是关闭的,内核分配的内存页和缓存由多个用户所共享。
lxc.cgroup.cpuset.memory_spread_page和lxc.cgroup.cpuset.memory_spread_slab:这两项控制内核应该从什么地方分配文件系统和相关内核数据结构所需的页。
lxc.cgroup.cpuset.memory_spread_page = 1 # 打开spread page cache功能
lxc.cgroup.cpuset.memory_spread_slab = 0 # 关闭spread slab cache功能
lxc.cgroup.cpuset.sched_load_balance:如果设定该项为真,内核会对整个cpuset中得所有CPU进行负载平衡调度。
注意:如果两个重叠的cpuset均打开了该项,那么它们必须在同一个调度域中。
lxc.cgroup.cpuset.sched_relax_domain_level: 请求内核改变进行负载平衡时的CPU搜索范围,如果lxc.cgroup.cpuset.sched_load_balance为假,则该项不起作用。其可选等级如下:
-1 : no request. use system default or follow request of others.
0 : no search.
1 : search siblings (hyperthreads in a core).
2 : search cores in a package.
3 : search cpus in a node [= system wide on non-NUMA system]
( 4 : search nodes in a chunk of node [on NUMA system] )
( 5 : search system wide [on NUMA system] )
当前控制组中的白名单列表可从devices.list中得到,白名单列表的每个入口包含四个域,其形式如下:
type major:minor access
其中type可选值为:a , c , b ,a表示所有设备,c为字符设备,b为块设备。
major和minor为设备的主从设备号,用整数或者*表示所有设备。
access为访问权限的结合r(读),w(写)和m(mknod)。
例如:
c 1:3 mr #允许对/dev/null进行读和mknode操作。
a *:* rwm #允许对所有设备进行读写和mknode操作。
例如:
lxc.cgroup.memory.limit_in_bytes = 4096 #设定内存限制为4094字节
lxc.cgroup.memory.limit_in_bytes = 4K #设定内存限制为4K
lxc.cgroup.memory.limit_in_bytes = 256M #设定内存限制为256M
lxc.cgroup.memory.limit_in_bytes = 1G #设定内存限制为1G字节
lxc.cgroup.memory.limit_in_bytes = -1 #设定内存为无限制
lxc.cgroup.memory.memsw.limit_in_bytes:设定当前组中内存+对换空间的限制,设定方式和lxc.cgroup.memory.limit_in_bytes相同,但需保证lxc.cgroup.memory.limit_in_bytes <= lxc.cgroup.memory.memsw.limit_in_bytes.
lxc.cgroup.memory.soft_limit_in_bytes:设定内存软限制,这使得系统更大程度上的共享内存,当系统检测到内存争用和短缺时,控制组的内存限制被退回到软限制,防止导致其他控制组饥饿的发生。设定该值时一般要小于硬限制,否则该值会被硬限制所覆盖。
lxc.cgroup.memory.use_hierarchy:打开内存的层次记账功能,注意如果父控制组已经打开该功能,则子控制组对该项的设置将不起作用。
lxc.cgroup.memory.swappiness:设定控制组的对换区的大小,在默认情况下为60。可选值为0~100。
内存子系统其他报告信息项:
在配置文件中配置该项为FROZEN可使得应用在容器开始运行的状态为挂起状态。在默认情况下该值设定为THAWED。注意,无法向处于冷冻状态的控制组中添加任务。
net_cls子系统通过对网络包进行标记从而使得linux流量控制器(tc)识别网络报来自于那个特定的控制组,从而获得该网络包的优先级。
lxc.cgroup.net_cls.classid: 该值指示了当前控制组的类别句柄(handle),该值采用十六进制表示。句柄的格式如下:
0xAAAABBBB
其中AAAA是十六进制主ID号,BBBB是十六进制从ID号,比如0x100001表示10:1(iproute2工具集使用十六进制表示句柄ID)。此处设定的为linux流量控制器中的类标识符。具体可参考TC相关信息。
如果容器作为超级用户运行,指定其可放弃的权限。
lxc.cap.drop:指定容器放弃的权限。该行指定了一些用空格分隔的权限。权限的格式为相应权限定义除去CAP_前缀后的小写形式,比如CAP_SYS_MODULE使用sys_module指定,通过指定sys_chroot可剥夺容器中所有进程进行chroot的权限,附录7.3中显示容器放弃的执行权限,注意,被剥夺的权限不能被恢复,即使root也没有权限来恢复被剥夺的权限,只能重启系统或者重新运行容器并将相应配置选项移除。
例:
lxc.cap.drop = sys_module mknod setuid net_raw
lxc.cap.drop = mac_override
lxc.cap.drop = sys_chroot
notify_on_release: 当该项被打开时,在控制组最后一个程序结束时,内核执行由release_agent指定的程序。在默认情况下该项是关闭的。
release_agent: 保存控制组中最后一个程序结束运行时执行的程序的路径,该项只在根控制组中出现。
1)安装febootstrap工具
yum install febootstrap
2)生成fedora基本安装系统
mkdir /lxc
cd /lxc
febootstrap fedora-13 rootfs.fedora
在rootfs.fedora目录下生成了基本安装的fedora13系统。
3)基本安装文件不能直接在linux容器使用,需做如下修改:
1、由于udev不在lxc容器中运行,首先需要人工创建需要的设备,编写脚本如下:
#!/bin/bash
ROOT=$(pwd)
DEV=${ROOT}/dev
if [ $ROOT = '/' ]; then
printf "\033[22;35m\nDO NOT RUN ON THE HOST NODE\n\n"
tput sgr0
exit 1
fi
if [ ! -d $DEV ]; then
printf "\033[01;33m\nRun this script in rootfs\n\n"
tput sgr0
exit 1
fi
rm -rf ${DEV}
mkdir ${DEV}
mknod -m 666 ${DEV}/null c 1 3
mknod -m 666 ${DEV}/zero c 1 5
mknod -m 666 ${DEV}/random c 1 8
mknod -m 666 ${DEV}/urandom c 1 9
mkdir -m 755 ${DEV}/pts
mkdir -m 1777 ${DEV}/shm
mknod -m 666 ${DEV}/tty c 5 0
mknod -m 666 ${DEV}/tty0 c 4 0
mknod -m 666 ${DEV}/tty1 c 4 1
mknod -m 666 ${DEV}/tty2 c 4 2
mknod -m 666 ${DEV}/tty3 c 4 3
mknod -m 666 ${DEV}/tty4 c 4 4
mknod -m 600 ${DEV}/console c 5 1
mknod -m 666 ${DEV}/full c 1 7
mknod -m 600 ${DEV}/initctl p
mknod -m 666 ${DEV}/ptmx c 5 2
exit 0
保存到/usr/local/bin/lxc-config中,并添加可执行权限。
chmod u+x /usr/local/bin/lxc-config
切换到rootfs.fedora下运行该脚本:
cd /lxc/rootfs.fedora
/usr/local/bin/lxc-config
2、配置rootfs.fedora
cp /etc/resolv.conf /lxc/rootfs.fedora/etc
chroot /lxc/rootfs.fedora /bin/bash
#挂载proc , sys, /dev/pts
mount -t proc none /proc
mount -t sysfs none /sys
mount -t devpts none /dev/pts
#添加一些应用
yum update
yum -y reinstall glibc-common
yum install httpd php-mysql mysql-server nano openssh-clients vim
#在/下添加一些必要的文件
touch /etc/fstab
rm /etc/mtab
ln -s /proc/mounts /etc/mtab
#卸载proc ,sys和/dev/pts
umount -t proc none /proc
umount -t sysfs none /sys
umount -t devpts none /dev/pts
#设定根密码
passwd
3、根文件系统配置
#编辑/lxc/rootfs.feodar/etc/sysconfig/init文件,将最后一行改为:
ACTIVE_CONSOLES = /dev/tty[1-4]
#编辑/lxc/rootfs.fedora/etc/rc.sysinit将下行注释掉:
/sbin/start_udev
#编辑/lxc/rootfs.fedora/etc/sysconfig/network添加如下两行:
NETWORKING=yes
HOSTNAME=fedora
4、创建lxc配置文件/lxc/config.fedora
lxc.utsname = fedora
lxc.tty = 4
lxc.network.type = veth
lxc.network.flags = up
lxc.network.link = br0
lxc.network.name = eth0
lxc.network.mtu = 1500
lxc.network.ipv4 = 192.168.0.65/24
lxc.rootfs = /lxc/rootfs.fedora
lxc.mount = /lxc/fstab.fedora
lxc.cgroup.devices.deny = a
# /dev/null and zero
lxc.cgroup.devices.allow = c 1:3 rwm
lxc.cgroup.devices.allow = c 1:5 rwm
# consoles
lxc.cgroup.devices.allow = c 5:1 rwm
lxc.cgroup.devices.allow = c 5:0 rwm
lxc.cgroup.devices.allow = c 4:0 rwm
lxc.cgroup.devices.allow = c 4:1 rwm
# /dev/{,u}random
lxc.cgroup.devices.allow = c 1:9 rwm
lxc.cgroup.devices.allow = c 1:8 rwm
# /dev/pts/* - pts namespaces are "coming soon"
lxc.cgroup.devices.allow = c 136:* rwm
lxc.cgroup.devices.allow = c 5:2 rwm
# rtc
lxc.cgroup.devices.allow = c 254:0 rwm
5、创建fstab文件/lxc/fstab.fedora
none /lxc/rootfs.fedora/dev/pts devpts defaults 0 0
none /lxc/rootfs.fedora/proc proc defaults 0 0
none /lxc/rootfs.fedora/sys sysfs defaults 0 0
/etc/resolv.conf /lxc/rootfs.fedora/etc/resolv.conf none bind 0 0
6、删除不必要的init脚本
# 删除/lxc/rootfs.fedora/etc/init目录下,除下述文件外的所有文件:
rc.conf
start-ttys.conf
tty.conf
# 将rc.conf和start-ttys.conf第一行修改为
start on startup
# 将rc.conf中最后一行的
exec /etc/rc.d/rc $RUNLEVEL
# 修改为:
exec /etc/rc.d/rc.fedora
# 创建/lxc/rootfs.fedora/etc/rc.d/rc.fedora
#!/bin/bash
route add default gw 192.168.1.1
/etc/init.d/rsyslog start &
/etc/init.d/iptables start &
/etc/init.d/sshd start &
/etc/init.d/mysqld start &
/etc/init.d/httpd start &
# 将其属性设置为可执行:
chmod u+x /lxc/rootfs.fedora/etc/rc.d/rc.fedora
# 删除/lxc/rootfs.fedora/etc/init.d目录下除下述文件外的所有文件:
httpd
iptables
mysqld
rsyslog
sshd
4)创建linux容器
# 创建网桥:
brctl add br0
brctl setfd br0 0
brctl addif br0 eth0
ifconfig br0 192.168.74.130 up #此处应为本机IP地址
ifconfig eth0 0.0.0.0 up
route add -net default gw 192.168.74.2 br0 #设置网关
# 创建容器
lxc-create -f /lxc/config.fedora -n fedora
# 运行容器
lxc-start -n fedora #lxc-start在未指定运行的命令的情况下默认执行init程序
# 连接到该容器,你会看到登陆界面:
lxc-console -n fedora
# 注意:在登陆后需用根用户添加网关才能联网:
route add -net default gw 192.168.74.2 eth0
linux容器通过内核流量控制子系统(traffic control subsystem)对流量进行限制,配置文件中lxc.net_cls.classid指示了流量控制器中类的标示。现在采用基于容器IP地址的方法,使用如下脚本利用TC工具创建HTB队列规则,tc命令的使用可参考附录和参考部分:
Shell代码
#!/bin/bash
#remove all classful qdisc first
tc qdisc del dev eth0 root
#create root htb qdisc, specify all unclassified packet into subclass 4
tc qdisc add dev eth0 root handle 1:0 htb default 4
#create subclasses
tc class add dev eth0 parent 1:0 classid 1:2 htb rate 256kbps ceil 512kbps prio 0
tc class add dev eth0 parent 1:0 classid 1:3 htb rate 128kbps ceil 256kbps prio 1
tc class add dev eth0 parent 1:0 classid 1:4 htb rate 64kbps ceil 128kbps prio 2
#attach a sfq qdisc for each leaf class
tc qdisc add dev eth0 parent 1:2 handle 2: sfq perturb 5
tc qdisc add dev eth0 parent 1:3 handle 3: sfq perturb 5
tc qdisc add dev eth0 parent 1:4 handle 4: sfq perturb 5
#attach filters to root htb qdisc
tc filter add dev eth0 protocol ip parent 1:0 u32 match ip src 192.168.74.10 flowid 1:2
tc filter add dev eth0 protocol ip parent 1:0 u32 match ip src 192.168.74.30 flowid 1:3
tc filter add dev eth0 protocol ip parent 1:0 u32 match ip src 192.168.74.130 flowid 1:4
注意,此处根据IP地址将数据包放置到不同的class中,也可采用其他的filter来实现不同的分类规则。u32过滤器可根据数据包的信息对数据包进行归类。此外,本章中容器通过配置桥接来进行网络通信,对于其他的链接网络的形式尚未进行测试。
在linux控制组中net_cls子系统通过对网络包打标记classid来表示属于不同控制组的网络包。linux系统中流量控制系统可根据该标记来对控制组的网络包进行控制。注意,net_cls子系统并不是通过修改网络包来打标记的,当网络包通过协议栈的过程中,通过当前的进程上下文来的到控制组信息,进而获得当前网络包的classid,因此,如果网络包被包过滤器处理之前被重新调度,那么就无法获得该包的classid!因此,对于采用6.1中网桥方式进行网络通信的方式,运行fedora虚拟机时无法采用classid对网络包进行分类管理。下面给出了一个简单的利用classid进行网络流量限制的配置脚本,使用的cgroup过滤器,根据网络包进程上下文中得到的classid对网络包进行分类。
Shell代码
#!/bin/bash
dev=eth0
tc qdisc del dev $dev root
# set qdisc as htb
tc qdisc add dev $dev parent root handle 10: htb
# create some claess for root qdisc
tc class add dev $dev parent 10: classid 10:1 htb rate 1mbps ceil 1mbps
tc class add dev $dev parent 10:1 classid 10:2 htb rate 256kbps ceil 256kbps
tc class add dev $dev parent 10:1 classid 10:3 htb rate 256kbps ceil 256kbps
tc class add dev $dev parent 10:1 classid 10:4 htb rate 512kbps ceil 1mbps
# add sfq qdisc for every leaf class
tc qdisc add dev $dev parent 10:2 handle 2:0 pfifo
tc qdisc add dev $dev parent 10:3 handle 3:0 pfifo
tc qdisc add dev $dev parent 10:4 handle 4:0 pfifo
# add filter for root qdisc
tc filter add dev $dev parent 10: protocol ip prio 1 handle 10: cgroup
该命令用于建立、维护和检查Ethernet网桥在Linux内核中的配置,如下是该命令的简要使用:
brctl addbr <name>:添加一个名称为name的网桥。
brctl delbr <name>:删除名称为name的网桥。
brctl addif <name> <device>:将接口device连接到网桥name上。
brctl delif <name> <device>:将接口device从网桥name上移除。
brctl setfd <name> <time>:设定网桥name的转送延时。
更多信息可参考 http://linux.die.net/man/8/brctl。
该命令用于linux内核的网络流量控制,在本文档中使用有类型的队列规则(classful qdisc)。下面给出一个配置实例,更多信息可参考http://linux.die.net/man/8/tc。
1)假设由另个客户A和B通过接口eth0连接到网络,我们系统分配给用户B的带宽为60kbps,分配给用户A的带宽为40kbps。此外,希望将A用户的30kbps的带宽按照如下划分:www占用其中的30kbps,剩余的10kbps用于其他应用。系统中任何未使用的带宽均可允许A或者B使用。
a)在接口eth0上创建一个htb qdisc,其句柄为1:0,未分类数据包发送给类1:12
tc qdisc add dev eth0 root handle 1: htb default 12
b)为qdisc创建htb类以及子类
tc class add dev eth0 parent 1: classid 1:1 htb rate 100kbps ceil 100kbps
tc class add dev eth0 parent 1:1 classid 1:10 htb rate 30kbps ceil 100kbps
tc class add dev eth0 parent 1:1 classid 1:11 htb rate 10kbps ceil 100kbps
tc class add dev eth0 parent 1:1 classid 1:12 htb rate 60kbps ceil 100kbps
c) 为qdisc添加filter,假设A用户的IP地址为1.2.3.4
tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32 match ip src 1.2.3.4 ip dprot 80 0xFFFF flowid 1:10
tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32 match ip src 1.2.3.4 flowid 1:11
上面第一行指定A的www服务的包发到类1:10,第二行指定其他包发给类1:11
d) 为每个leaf class添加队列(可选)
tc qdisc add dev eth0 parent 1:10 handle 20: pfifo limit 5
tc qdisc add dev eth0 parent 1:11 handle 30: pfifo limit 5
tc qdisc add dev eth0 parent 1:12 handle 40: pfifo limit 10
在linux2.2内核开始将超级用户的权限分为若干独立的子权限,每个子权限可独立的禁止或者打开,注意,一旦剥夺了根用户的某一权限,那么除非重启系统,否则无法恢复该权限。下面对这些权限进行简单的介绍:
权限 | 说明 |
---|---|
CAP_CHOWN | 允许改变文件的所有权 |
CAP_DAC_OVERRIDE | 忽略对文件的所有DAC访问限制 |
CAP_DAC_READ_SEARCH | 忽略所有对读、搜索操作的限制 |
CAP_FOWNER | 如果文件属于进程的UID,就取消对文件的限制 |
CAP_FSETID | 允许设置setuid位 |
CAP_KILL | 允许对不属于自己的进程发送信号 |
CAP_SETGID | 允许改变组ID |
CAP_SETUID | 允许改变用户ID |
CAP_SETPCAP | 允许向其它进程转移能力以及删除其它进程的任意能力 |
CAP_LINUX_IMMUTABLE | 允许修改文件的不可修改(IMMUTABLE)和只添加(APPEND-ONLY)属性 |
CAP_NET_BIND_SERVICE | 允许绑定到小于1024的端口 |
CAP_NET_BROADCAST | 允许网络广播和多播访问 |
CAP_NET_ADMIN | 允许执行网络管理任务:接口、防火墙和路由等。 |
CAP_NET_RAW | 允许使用原始(raw)套接字 |
CAP_IPC_LOCK | 允许锁定共享内存片段 |
CAP_IPC_OWNER | 忽略IPC所有权检查 |
CAP_SYS_MODULE | 插入和删除内核模块 |
CAP_SYS_RAWIO | 允许对ioperm/iopl的访问 |
CAP_SYS_CHROOT | 允许使用chroot()系统调用 |
CAP_SYS_PTRACE | 允许跟踪任何进程 |
CAP_SYS_PACCT | 允许配置进程记帐(process accounting) |
CAP_SYS_ADMIN | 允许执行系统管理任务:加载/卸载文件系统、设置磁盘配额、开/关交换设备和文件等。 |
CAP_SYS_BOOT | 允许重新启动系统 |
CAP_SYS_NICE | 允许提升优先级,设置其它进程的优先级 |
CAP_SYS_RESOURCE | 忽略资源限制 |
CAP_SYS_TIME | 允许改变系统时钟 |
CAP_SYS_TTY_CONFIG | 允许配置TTY设备 |
CAP_MKNOD | 允许使用mknod()系统调用 |
CAP_LEASE | Allow taking of leases on files |
lxc建立在cgroup的基础上,在2.6.35以上内核中支持将控制组子系统通过模块的形式加入到内核中,本节演示了如何编写一个控制组子系统模块。在当前的内核中支持的子系统的最大个数为unsigned long类型的bit位数,当前的子系统个数为8个。编写简单过程如下:
struct cgroup_subsys sample = {
.create = sample_create,
.destroy = sample_destroy,
.populate = sample_populate,
.module = THIS_MODULE,
};
struct cgroup_subsys结构定义了控制组子系统结构,其中主要包含了一些控制组子系统接口和一些属性信息,其中create和destory接口必须定义,这两个接口实现了创建和销毁控制组子系统状态对象。
struct cgroup_hello_state {
struct cgroup_subsys_state css;
int helloid;
/*其他相关信息*/
};
int hello_subsys_id ;
struct cftype cft[]={
{
.name = “hello”,
.read_u64 = sample_read_u64,
.write_u64 = sample_write_u64,
},
}
struct cftype结构定义了控制文件的处理句柄以及相关名称和属性信息,在这里仅仅实现文件的读写句柄.
完整的代码如下:
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/cgroup.h>
MODULE_LICENSE("Dual BSD/GPL");
/*控制组子系统结构*/
struct cgroup_hello_state{
struct cgroup_subsys_state css;
int helloid;
/*其他状态信息*/
};
int hello_subsys_id;
static struct cgroup_subsys_state *cgrp_create(struct cgroup_subsys *ss,struct cgroup *cgrp);
static void cgrp_destroy(struct cgroup_subsys *ss,struct cgroup * cgrp);
static int cgrp_populate(struct cgroup_subsys *ss,struct cgroup * cgrp);
static void cgrp_attach(struct cgroup_subsys *ss,struct cgroup * cgrp,struct cgroup *old_cgrp,struct task_struct *task);
/*定义控制组子系统结构*/
struct cgroup_subsys cgroup_hello_subsys ={
.name = "hello",
.create = cgrp_create,
.destroy = cgrp_destroy,
.populate = cgrp_populate,
.attach = cgrp_attach,
.module = THIS_MODULE,
};
static void cgrp_attach(struct cgroup_subsys *ss,struct cgroup * cgrp,struct cgroup *old_cgrp,struct task_struct *task){
printk(KERN_ALERT "%s:%d\n",__func__,task->pid);
}
static inline struct cgroup_hello_state *cgrp_hello_state(struct cgroup *cgrp){
return container_of(cgroup_subsys_state(cgrp,hello_subsys_id),struct cgroup_hello_state,css);
}
static struct cgroup_subsys_state *cgrp_create(struct cgroup_subsys *ss,struct cgroup *cgrp){
struct cgroup_hello_state *cs;
cs = kmalloc(sizeof(*cs),GFP_KERNEL);
if(!cs)
return ERR_PTR(-ENOMEM);
printk(KERN_ALERT "%s\n",__func__);
return &cs->css;
}
static void cgrp_destroy(struct cgroup_subsys *ss,struct cgroup * cgrp){
kfree(cgrp_hello_state(cgrp));
}
static u64 read_helloid(struct cgroup *cgrp,struct cftype *cft);
static int write_helloid(struct cgroup *cgrp,struct cftype *cft, u64 val);
/*控制文件操作对象结构*/
struct cftype ss_files[]={
{
.name = "hello",
.read_u64 = read_helloid,
.write_u64 = write_helloid,
},
};
/*创建本子系统的控制文件*/
static int cgrp_populate(struct cgroup_subsys *ss,struct cgroup *cgrp){
return cgroup_add_files(cgrp,ss,ss_files,ARRAY_SIZE(ss_files));
}
static u64 read_helloid(struct cgroup *cgrp, struct cftype *cft){
printk(KERN_ALERT "%s:%s\n",__func__,cft->name);
return cgrp_hello_state(cgrp)->helloid;
}
static int write_helloid(struct cgroup *cgrp,struct cftype *cft,u64 val){
printk(KERN_ALERT "%s:%s\n",__func__,cft->name);
cgrp_hello_state(cgrp)->helloid = (int)val;
return 0;
}
static int hello_init(void){
int ret;
printk(KERN_ALERT "Hello,world\n");
ret = cgroup_load_subsys(&cgroup_hello_subsys);
if(ret)
goto out;
hello_subsys_id = cgroup_hello_subsys.subsys_id;
printk(KERN_ALERT "subsys id:%d\n",hello_subsys_id);
out:
return ret;
}
static void hello_exit(void){
cgroup_unload_subsys(&cgroup_hello_subsys);
printk(KERN_ALERT "Goodbye, cruel world\n");
}
module_init(hello_init);
module_exit(hello_exit);
上述文档可能存在疏漏错误的地方,还望大家指正~~~~