用go写一个docker(6)-linux的cgroup

namespace可以帮我们把资源隔离,但不能对资源的使用做限制。比如我想限制某个进程用多少CPU,多少内存话,怎么办呢?答案就是用cgroup

什么是cgroup

cgroup是Linux内核提供的一种可以限制、记录、隔离进程组(process groups)所使用的物理资源(如:cpu,memory,IO等等)的机制。

体验下cgroup

我们直接体验下cgroup的内存和CPU限制。

一.cgroup的内存限制

示例代码mem.go:

package main
​
import (
    "fmt"
    "time"
)
​
func main() {
    for i := 0; i < 1000; i++ {
    b := make([]byte, 1e7 * i)
        fmt.Println(len(b))
        time.Sleep(time.Second * time.Duration(1))
    }
    time.Sleep(time.Second * time.Duration(1000))
}

编译下运行:

root@xxg-txy:~/docker# go build mem.go 
root@xxg-txy:~/docker# ./mem 
0
10000000
20000000
30000000
40000000

通过htop命令可以看到mem占用的内存越来越多。

接下来我们给mem程序配置一个cgroup限制。

1. 创建一个限制内存的cgroup
mkdir /sys/fs/cgroup/memory/test
2.关闭交换分区
swapoff -a
3.限制内存为300M
echo $((300*1024*1024)) > /sys/fs/cgroup/memory/test/memory.limit_in_bytes
4.使用cgroup配置再次运行脚本:
cgexec -g memory:test ./mem

会发现随着占用的内存越来越多,当超过cgroup的限制时,程序被系统kill掉了:

root@xxg-txy:~/docker# cgexec -g memory:test ./mem
0
10000000
20000000
30000000
40000000
50000000
60000000
70000000
80000000
90000000
100000000
110000000
120000000
130000000
140000000
150000000
160000000
170000000
180000000
190000000
200000000
210000000
220000000
230000000
240000000
250000000
260000000
270000000
280000000
290000000
300000000
Killed

二.cgroup的CPU限制

示例代码cpu.go:

package main
​
func main() {
    for{}
}

编译下运行,会看到程序占用的CPU接近90%

接下来我们配置下cgroup,把它限制到50

1.创建一个cpu的cgroup
mkdir /sys/fs/cgroup/cpu/test
2.限制为50%
echo 50000 > /sys/fs/cgroup/cpu/test/cpu.cfs_quota_us
3.使用cgroup配置再次运行脚本:
cgexec -g cpu:test ./cpu

可以看到CPU被限制在了50%左右

在go中使用cgroup

通过go封装的标准库,我们可以在go中配置并使用cgroup。
为了方便我们演示和查看,这里使用stress命令直接获取内存验证。比如我想直接从系统里拿500M内存,可运行如下命令:

stress --vm-bytes 500m --vm-keep -m 1

测试代码如下:

package main
​
import (
  "os/exec"
  "syscall"
  "os"
  "log"
  "io/ioutil"
  "strconv"
  "path"
)
​
const procSelf = "/proc/self/exe"
const cgroup = "docker"
const cgroupMemoryHierarchyMount = "/sys/fs/cgroup/memory"
​
func main() {
  if os.Args[0] == procSelf {
    // cmd进程在cgroup规则下运行
    cmd := exec.Command("/usr/bin/stress","--vm-bytes","500m","--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 {
      log.Fatal(err)
      os.Exit(-1)
    }
  }
​
  cmd := exec.Command(procSelf)
  cmd.SysProcAttr = &syscall.SysProcAttr{}
  cmd.Stdin = os.Stdin
  cmd.Stdout = os.Stdout
  cmd.Stderr = os.Stderr
  if err := cmd.Start(); err != nil {
    log.Fatal(err)
    os.Exit(-1)
  }else{
    // 创建cgourp规则
    os.Mkdir(path.Join(cgroupMemoryHierarchyMount, cgroup), 0755)
    ioutil.WriteFile(path.Join(cgroupMemoryHierarchyMount, cgroup, "tasks"),[]byte(strconv.Itoa(cmd.Process.Pid)), 0644)
    ioutil.WriteFile(path.Join(cgroupMemoryHierarchyMount, cgroup, "memory.limit_in_bytes"),[]byte("200m"), 0644)
  }
​
  cmd.Process.Wait()
}

运行该脚本,会发现内存被限制在了200M。
谢谢阅读。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值