简介
继上篇的Run命令容器的实现,本章节中将实现增加容器资源限制,已内存限制为例,展示如果现在容器的内存使用
源码说明
同时放到了Gitee和Github上,都可进行获取
本章节对应的版本标签是:3.2,防止后面代码过多,不好查看,可切换到标签版本进行查看
本次只实现了内存的限制,CPU的实现同理
结果演示
进程号 USER PR NI VIRT RES SHR %CPU %MEM TIME+ COMMAND
46805 lw 20 0 208668 204988 336 R 100.0 0.6 2:20.89 stress
48004 root 20 0 208668 99520 272 D 37.9 0.3 0:04.68 stress
如上所示,第一个是没有使用资源限制100M的stress命令: stress --vm-bytes 200m --vm-keep -m 1
第二个是使用自己的docker限制了100M内存的stress命令:./main run -ti -mem 100m stress --vm-bytes 200m --vm-keep -m 1
后者是前者的一半,可以看出了资源限制起到了作用
编码实现
这边的Cgroup卡了很久才解决,照抄代码有一定的风险,还是理解原理后,自己一步一步的实现最终才完成了
参数接收改造
我们需要使用docker运行stress命令:
上面的参数比较多,原本的是不支持的,我们需要进行改造,代码如下:
var RunCommand = cli.Command{
Name: "run",
Usage: `Create a container with namespace and cgroups limit mydocker run -ti [command]`,
Flags: []cli.Flag{
cli.BoolFlag{
Name: "ti",
Usage: "enable tty",
},
// 增加内存等限制参数
cli.StringFlag{
Name: "mem",
Usage: "memory limit",
},
cli.StringFlag{
Name: "cpuset",
Usage: "cpuset limit",
},
cli.StringFlag{
Name: "cpushare",
Usage: "cpushare limit",
},
},
/*
这里是run命令执行的真正函数
1.判断参数是否包含command
2.获取用户指定的command
3.调用Run function 去准备启动容器
*/
Action: func(context *cli.Context) error {
if len(context.Args()) < 1 {
return fmt.Errorf("missing container command")
}
// 这个是获取启动容器时的命令
// 如果本次中的 stress --vm-bytes 200m --vm-keep -m 1,空格分隔后会存储在下面的cmdArray中
var cmdArray []string
for _, arg := range context.Args() {
cmdArray = append(cmdArray, arg)
}
tty := context.Bool("ti")
resConfig := &subsystem.ResourceConfig{
MemoryLimit: context.String("mem"),
CpuShare: context.String("cpuShare"),
CpuSet: context.String("cpuSet"),
}
run.Run(tty, cmdArray, resConfig)
return nil
},
}
在init的时候也需要支持,在init命令执行的时候需要传入对应的参数
func NewParentProcess(tty bool, cmdArray []string) *exec.Cmd {
commands := strings.Join(cmdArray, " ")
log.Infof("conmand all is %s", commands)
// 传入,cmdArray[0]是启动的程序,比如本篇中的是stress,command是完整的命令:stress --vm-bytes 200m --vm-keep -m 1
cmd := exec.Command("/proc/self/exe", "init", cmdArray[0], commands)
cmd.SysProcAttr = &syscall.SysProcAttr{
<