(2)Cgroups

关于Cgroups

上一篇namespace主要是说环境隔离,此篇Cgroups主要是说对隔离环境做出限制,防止隔离出的空间相互抢夺资源。

Cgroups同样也是linux的内核技术,提供了对一组进程及其子进程的资源限制,控制,以及统计的功能。这些资源包括:
cpu、内存、存储、网络等。

Cgroups中的三个组件,cgroup、subsystem、hierarchy.首先cgroup是对进程分组管理的一种机制,一个Cgroup包含一组进程,
并可以对此cgroup增加各种subsystem参数,将一组进程和一组subsystem关联起来。其次subsystem是一组资源管理控制的模块。
(比如其中的blkio可以设置对块设备的IO控制,memory用于控制进程的内存占用...)最后hierarchy,它的功能是把一组Cgroup串
成一个树状的结构,通过这种结构Cgroups可以做到继承。

手动调用kernel接口感受下Cgroups

1创建并挂载一个hierarchy(Cgroup树)

[root@iZ2zebynirz2ac5eron661Z ~]# mkdir cgroup-test  #创建一个hierarchy挂载点
[root@iZ2zebynirz2ac5eron661Z ~]# mount -t cgroup -o none,name=cgroup-test cgroup-test ./cgroup-test #挂载一个hierarchy
[root@iZ2zebynirz2ac5eron661Z ~]# ls ./cgroup-test/ #挂载后发现多了些默认配置文件
cgroup.event_control  cgroup.procs  notify_on_release  release_agent  tasks

2在根节点中扩展出两个子Cgroup

[root@iZ2zebynirz2ac5eron661Z cgroup-test]# mkdir cgroup-1
[root@iZ2zebynirz2ac5eron661Z cgroup-test]# mkdir cgroup-2
[root@iZ2zebynirz2ac5eron661Z cgroup-test]# tree
.
├── cgroup-1
│   ├── cgroup.event_control
│   ├── cgroup.procs
│   ├── notify_on_release
│   └── tasks
├── cgroup-2
│   ├── cgroup.event_control
│   ├── cgroup.procs
│   ├── notify_on_release
│   └── tasks
├── cgroup.event_control
├── cgroup.procs
├── notify_on_release
├── release_agent
└── tasks

我们可以发现,在一个Cgroup的目录下创建文件时,kernel会把文件标记为这个Cgroup的子Cgroup,他们会继承Cgroup
的属性。

3在Cgroup中添加移动进程
一个进程在一个Cgroups的hierarchy中,只能在一个Cgroup节点上存在,系统的所有进程都会默认在根节点上存在,
将进程ID写到移动到的Cgroup节点的tasks文件中即可将该进程移动到该Cgroup节点。

[root@iZ2zebynirz2ac5eron661Z cgroup-1]# echo $$
18091
[root@iZ2zebynirz2ac5eron661Z cgroup-1]# cat /proc/18091/cgroup 
1:name=cgroup-test:/
[root@iZ2zebynirz2ac5eron661Z cgroup-1]#  sh -c "echo $$ >>tasks"
[root@iZ2zebynirz2ac5eron661Z cgroup-1]# cat /proc/18091/cgroup 
1:name=cgroup-test:/cgroup-1
[root@iZ2zebynirz2ac5eron661Z cgroup-1]# 

可以看到,当前的进程移动到了cgroup-1中了

4在通过subsystem限制Cgroup中进程的资源

PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND                                                                                                      
 7644 bozhon    20   0  211980 205620    748 R 100.0  2.6   1:55.63 stress                                                                                                       
bozhon@bozhon:~$ mkdir test-limit-memory && cd test-limit-memory
bozhon@bozhon:~/test-limit-memory$ cd /sys/fs/cgroup/memory
bozhon@bozhon:/sys/fs/cgroup/memory$ sudo mkdir test-limit-memory && cd test-limit-memory
[sudo] password for bozhon: 
bozhon@bozhon:/sys/fs/cgroup/memory/test-limit-memory$ sudo sh -c "echo "100m">memory.limit_in_bytes"
bozhon@bozhon:/sys/fs/cgroup/memory/test-limit-memory$ sudo sh -c "echo $$ >tasks"
bozhon@bozhon:/sys/fs/cgroup/memory/test-limit-memory$ stress --vm-bytes 200m --vm-keep -m 1
stress: info: [7674] dispatching hogs: 0 cpu, 0 io, 1 vm, 0 hdd
已杀死
bozhon@bozhon:/sys/fs/cgroup/memory/test-limit-memory$ stress --vm-bytes 200m --vm-keep -m 1
stress: info: [7676] dispatching hogs: 0 cpu, 0 io, 1 vm, 0 hdd
已杀死
bozhon@bozhon:/sys/fs/cgroup/memory/test-limit-memory$ stress --vm-bytes 100m --vm-keep -m 1
stress: info: [7678] dispatching hogs: 0 cpu, 0 io, 1 vm, 0 hdd
已杀死
bozhon@bozhon:/sys/fs/cgroup/memory/test-limit-memory$ stress --vm-bytes 10m --vm-keep -m 1
stress: info: [7680] dispatching hogs: 0 cpu, 0 io, 1 vm, 0 hdd

我们可以看到当使用限制100M后,大于等于100M的进程会杀死

Cgroups在docker中的运用

02613ec46397ee46a6a9bd7e62f78b1bd89f15f07b898f3c8553db4243b5346f
为某个容器ID

bozhon@bozhon:~$ cd /sys/fs/cgroup/memory/docker/02613ec46397ee46a6a9bd7e62f78b1bd89f15f07b898f3c8553db4243b5346f/
bozhon@bozhon:/sys/fs/cgroup/memory/docker/02613ec46397ee46a6a9bd7e62f78b1bd89f15f07b898f3c8553db4243b5346f$ ls
cgroup.clone_children  memory.kmem.failcnt             memory.kmem.tcp.limit_in_bytes      memory.max_usage_in_bytes        memory.soft_limit_in_bytes  notify_on_release
cgroup.event_control   memory.kmem.limit_in_bytes      memory.kmem.tcp.max_usage_in_bytes  memory.move_charge_at_immigrate  memory.stat                 tasks
cgroup.procs           memory.kmem.max_usage_in_bytes  memory.kmem.tcp.usage_in_bytes      memory.numa_stat                 memory.swappiness
memory.failcnt         memory.kmem.slabinfo            memory.kmem.usage_in_bytes          memory.oom_control               memory.usage_in_bytes
memory.force_empty     memory.kmem.tcp.failcnt         memory.limit_in_bytes               memory.pressure_level            memory.use_hierarchy
bozhon@bozhon:/sys/fs/cgroup/memory/docker/02613ec46397ee46a6a9bd7e62f78b1bd89f15f07b898f3c8553db4243b5346f$ cat memory.limit_in_bytes 
9223372036854771712

用go语言实现通过Cgroups限制容器资源

package main

import (
    "os"
    "fmt"
    "syscall"
    "os/exec"
    "path"
    "io/ioutil"
    "strconv"
)
//挂载了memory subsystem 的hierarchy的根目录的位置
const cgroupMemoryHierarchyMount  ="/sys/fs/cgroup/memory"
func main() {
    if os.Args[0] == "/proc/self/exe"{
        //容器进程
        fmt.Printf("current pid %d",syscall.Getpid())
        fmt.Println()
        cmd := exec.Command("sh","-c",`stress --vm-bytes 200m --vm-keep -m  1` )
        cmd.SysProcAttr = &syscall.SysProcAttr{}

        cmd.Stdin = os.Stdin
        cmd.Stdout = os.Stdout
        cmd.Stderr = os.Stderr

        if err:= cmd.Run(); err!=nil{
            fmt.Println(err)
            os.Exit(1)
        }
    }

    cmd := exec.Command("/proc/self/exe")
    cmd.SysProcAttr = &syscall.SysProcAttr{
        Cloneflags: syscall.CLONE_NEWUTS |syscall.CLONE_NEWPID|syscall.CLONE_NEWNS,
    }
    cmd.Stdin = os.Stdin
    cmd.Stdout = os.Stdout
    cmd.Stderr = os.Stderr

    if err:= cmd.Run(); err!=nil{
        fmt.Println(err)
        os.Exit(1)
    }else{
        //得到fork处理进程映射在外部命名空间的pid
        fmt.Printf("%v",cmd.Process.Pid)
        //在系统默认创建挂载了memory subsystem的Hierachy上创建cgroup
        os.Mkdir(path.Join(cgroupMemoryHierarchyMount,"testmemorylimit"),0755)
        //将容器进程加入到这个cgroup中
        ioutil.WriteFile(path.Join(cgroupMemoryHierarchyMount,"testmemorylimit","memory.limit_in_bytes"),
            []byte(strconv.Itoa(cmd.Process.Pid)),0644)
        //限制cgroup进程使用
        ioutil.WriteFile(path.Join(cgroupMemoryHierarchyMount,"testmemorylimit","memory.limit_in_bytes"),
            []byte("100m"),0644)
    }
    cmd.Process.Wait()


}

我们可以看到占用了20%内存(1G*20%=100M),说明限制成功

 34192 maojian+  20   0   41820   3764   3120 R  4.3  0.4   0:00.40 top
     1 root      20   0  119744   5844   4012 S  0.0  0.6   0:02.73 systemd
     2 root      20   0       0      0      0 S  0.0  0.0   0:00.00 kthreadd
     3 root      20   0       0      0      0 S  0.0  0.0   0:01.80 ksoftirqd/0
     5 root       0 -20       0      0      0 S  0.0  0.0   0:00.00 kworker/0:0H
     7 root      20   0       0      0      0 S  0.0  0.0   0:00.70 rcu_sched
     8 root      20   0       0      0      0 S  0.0  0.0   0:00.00 rcu_bh
     9 root      rt   0       0      0      0 S  0.0  0.0   0:00.00 migration/0
    10 root      rt   0       0      0      0 S  0.0  0.0   0:00.03 watchdog/0
    11 root      20   0       0      0      0 S  0.0  0.0   0:00.00 kdevtmpfs

你可能感兴趣的:((2)Cgroups)