4

容器实现-cgroup

 2 years ago
source link: https://staight.github.io/2019/10/03/%E5%AE%B9%E5%99%A8%E5%AE%9E%E7%8E%B0-cgroup/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

容器实现-cgroup

发表于

2019-10-03 更新于 2019-10-04

cgroup是实现容器的除了namespace以外的另一种技术,namespace的用途是隔离环境,而cgroup则用来限制进程使用的资源。

对于cgroup的概述之前已写过一篇文章,这是链接:linux资源管理器–cgroups理解

简单来说,使用cgroup限制进程的资源有如下几步:

  1. 规划需要限制的资源,比如说限制内存资源为100M。
  2. 创建需限制的进程。
  3. /sys/fs/cgroup/memory/目录下创建文件夹,并进入该文件夹。
  4. 100M写入memory.max_usage_in_bytes文件,将进程pid追加写入tasks文件。

这样,该进程如果使用超过100M的内存,则将无法申请更多的内存,或直接被kill掉。

那么,尝试写一个程序测试一下吧。

示例程序:

package main

import (
"fmt"
"io/ioutil"
"log"
"os"
"os/exec"
"path"
"strconv"
"syscall"
)

const cgroupMemoryHierarchyMount = "/sys/fs/cgroup/memory"
const memoryLimit = "memory.limit_in_bytes"

func main() {
cmd := exec.Command("sh")
cmd.SysProcAttr = &syscall.SysProcAttr{}
cmd.Stdin = os.Stdin
cmd.Stderr = os.Stderr
cmd.Stdout = os.Stdout

// 运行子进程,且主进程不阻塞等待
var p string
if err := cmd.Start(); err != nil {
log.Fatal(err)
} else {
// 打印子进程pid
fmt.Printf("subprocess pid: %v\n", cmd.Process.Pid)
// 创建子文件夹
p = path.Join(cgroupMemoryHierarchyMount, strconv.Itoa(cmd.Process.Pid))
os.Mkdir(p, 0755)
fmt.Printf("mkdir: %v\n", p)

// 限制内存使用
ioutil.WriteFile(path.Join(p, memoryLimit), []byte("10m"), 0644)
fmt.Printf("writefile: %v content: %v\n", path.Join(p, memoryLimit), "10")

// 将子进程加入至该cgroup中
ioutil.WriteFile(path.Join(p, "tasks"), []byte(strconv.Itoa(cmd.Process.Pid)), 0644)
fmt.Printf("writefile: %v content: %v\n", path.Join(p, "tasks"), cmd.Process.Pid)

}

// 等待子进程运行结束
cmd.Process.Wait()

fmt.Println("subprocess ended.")
os.Remove(p)
fmt.Printf("rmdir: %v\n", p)
}

运行该程序:

[root@staight chmdocker]# go build
[root@staight chmdocker]# ./chmdocker
sh-4.2# subprocess pid: 30560
mkdir: /sys/fs/cgroup/memory/30560
writefile: /sys/fs/cgroup/memory/30560/memory.limit_in_bytes content: 10
writefile: /sys/fs/cgroup/memory/30560/tasks content: 30560

sh-4.2#

尝试在新的shell中运行stress程序:

sh-4.2# stress --vm 1 --vm-bytes 100M --vm-keep
stress: info: [30842] dispatching hogs: 0 cpu, 0 io, 1 vm, 0 hdd
stress: FAIL: [30842] (415) <-- worker 30843 got signal 9
stress: WARN: [30842] (417) now reaping child worker processes
stress: FAIL: [30842] (451) failed run completed in 0s

如上,stress进程想要申请100M的内存,因超过cgroup的内存限制而被9信号强制kill,试验成功。

最后,关闭新的shell:

sh-4.2# exit
exit
subprocess ended.
rmdir: /sys/fs/cgroup/memory/30560

在实验的过程中,有个问题需要说一下:

首先,默认情况下,将一个进程添加至cgroup中,那么它以后创建的所有子进程也都将自动添加至该cgroup。可是在如上程序中,将sh进程添加至cgroup的时间是已经在该进程运行一段时间之后的,如果sh进程在被添加至cgroup之前已经创建了子进程,那么它的子进程将不在cgroup中,也就是说sh进程的子进程将不被cgroup管控。这种情况该如何解决呢?

待解决。。。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK