docker修改command_七天用Go写个docker(第二天)

1. Cgroup概念

Linux Cgroup提供了对一组进程及子进程的资源限制,控制和统计的能力,这些资源包括CPU,内存,存储,网络等。通过Cgroup,可以方便的吸纳之某个进程的资源占用,并且可以实时监控进程和统计信息。

Cgroup完成资源限制主要通过下面三个组件

  • cgroup: 是对进程分组管理的一种机制
  • subsystem: 是一组资源控制的模块
  • hierarchy: 把一组cgroup串成一个树状结构(可让其实现继承)

2. Cgroup使用

说半天概念,估计大家也是云里雾里,我直接在Liunx命令行中演示怎么使用Cgroup,这样大家也会对Cgroup有一个更清晰的认识。

  1. 创建一个用来存放挂载点的文件夹
mkdir cgroup-demo
  1. 挂载hierarchy
mount -t cgroup -o none,name=cgroup-demo cgroup-demo ./cgroup-demo

3f09b01c1e4632a03635e03b218000ec.png3. 查看生成的默认文件

一旦我们挂载了hierarchy,那么就会在这个文件夹中生成一些默认文件

ls cgroup-demo

0e456165cd3e8cb8dbdb696a85dcd273.png大致解释下这几个文件的作用,主要是这个task文件

  • cgroup.clone_children:cpuset的subsystem会读取该文件,如果该文件里面的值为1的话,那么子cgroup将会继承父cgroup的cpuset配置
  • cgroup.procs:记录了树中当前节点cgroup中的进程组ID
  • task: 标识该cgroup下的进程ID,如果将某个进程的ID写到该文件中,那么便会将该进程加入到当前的cgroup中。
  1. 新建子cgroup

只要在挂载了hierarchy的文件夹下,新建一个新的文件夹,那么该新的文件夹会被kernel 自动标记为该cgroup的子group

cd cgroup-demo
mkdir cgroup1
f6bf6b86f5862738db2120f2b62a97ca.png

可以看到,我们新建文件夹之后,文件夹里面会自动生成一些默认的文件,这个cgroup1就是cgroup-demo的子cgroup,默认情况下,他会继承父cgroup的配置。

  1. 通过subsystem限制cgroup中进程的资源

上面创建的hierarchy并没有关联到任何的subsystem,所以没办法通过上面的hierarchy中的cgroup节点来限制进程的资源占用,其实系统默认已经为每个subsystem创建了一个默认的hierarchy,它在Linux的/sys/fs/cgroup 路径下

ls /sys/fs/cgroup
829b883fc91d1cbd9534eb1fac222903.png

如果我们想限制某个进程ID的内存,那么就在/sys/fs/cgroup/memory 文件夹下创建一个限制 mermory的cgroup,创建方式和上面一样,只要创建一个文件夹即可,kernel 自动把该文件夹标记为一个cgroup,我们来尝试一下

cd /sys/fs/cgroup/memory
mkdir cgroup-demo-memory
8c4f04474d0e72a514d64ed715d8db3a.png

可以看到该文件下,自动给我们创建出来了很多限制资源文件,我们只要将进程ID写到该文件夹下的task文件中,然后修改其meory.limit_in_bytes的文件,就能达到限制该进程的内存使用。

3. Go语言中使用Cgroup

package main

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

const (
// 挂载了 memory subsystem的hierarchy的根目录位置
cgroupMemoryHierarchyMount = "/sys/fs/cgroup/memory"
)

func main() {

if os.Args[0] == "/proc/self/exe" {
//容器进程
fmt.Printf("current pid %d \n", syscall.Getpid())

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 {
panic(err)
}
}

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
err := cmd.Start()
if err != nil {
panic(err)
}
// 得到 fork出来进程映射在外部命名空间的pid
fmt.Printf("%+v", cmd.Process.Pid)

// 创建子cgroup
newCgroup := path.Join(cgroupMemoryHierarchyMount, "cgroup-demo-memory")
if err := os.Mkdir(newCgroup, 0755); err != nil {
panic(err)
}
// 将容器进程放到子cgroup中
if err := ioutil.WriteFile(path.Join(newCgroup, "tasks"), []byte(strconv.Itoa(cmd.Process.Pid)), 0644); err != nil {
panic(err)
}
// 限制cgroup的内存使用
if err := ioutil.WriteFile(path.Join(newCgroup, "memory.limit_in_bytes"), []byte("100m"), 0644); err != nil {
panic(err)
}
cmd.Process.Wait()
}

这两节带大家了解了docker的原理,那么下一节我将带领大家用go把docker容器的框架搭建起来,开始真正编写docker了。

fca9749f2136aa82826cd97c618263bc.gif 

 如果对你有所帮助,请帮忙点击在看转发

901a418d1b8c4eef6be731b4489ea0b2.png扫码关注 b9a783dc09e82440240b418dca0ecfe5.png更多精彩 3b2cc72fef7a5907f0e814acc79c68c1.png 3b2cc72fef7a5907f0e814acc79c68c1.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值