1. 程式人生 > 其它 >用go寫一個docker(6)-linux的cgroup

用go寫一個docker(6)-linux的cgroup

技術標籤:運維和開發dockergo

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))
}

編譯下執行:

[email protected]:~/docker# go build mem.go 
[email protected]:~/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掉了:

[email protected]:~/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。
謝謝閱讀。