前言
上節(jié)[mydocker]---構(gòu)造容器02-實(shí)現(xiàn)資源限制01中已經(jīng)加入了對(duì)
memory的限制. 本節(jié)將會(huì)梳理一下上節(jié)的代碼使其更清晰, 為了方便擴(kuò)展加入其它的subsystem的限制.
代碼: 代碼下載
效果
最終要達(dá)到的效果會(huì)如下所示:
--------------------------terminal 01---------------------------------
root@nicktming:/sys/fs/cgroup/memory# pwd
/sys/fs/cgroup/memory
root@nicktming:/sys/fs/cgroup/memory# ls | grep mydocker
--------------------------terminal 02---------------------------------
root@nicktming:~/go/src/github.com/nicktming# pwd
/root/go/src/github.com/nicktming
root@nicktming:~/go/src/github.com/nicktming# git clone https://github.com/nicktming/mydocker.git
root@nicktming:~/go/src/github.com/nicktming# cd mydocker
root@nicktming:~/go/src/github.com/nicktming/mydocker# git checkout code-3.2.2
root@nicktming:~/go/src/github.com/nicktming/mydocker# go build .
root@nicktming:~/go/src/github.com/nicktming/mydocker# ./mydocker run -it -m 12M /bin/sh
2019/04/02 23:53:26 Apply absolutePath:/sys/fs/cgroup/memory/mydocker, taskPath:/sys/fs/cgroup/memory/mydocker/tasks
2019/04/02 23:53:26 err : <nil>
#
// 查看是否生成cgroup 并且對(duì)此進(jìn)程加入限制
--------------------------terminal 01---------------------------------
root@nicktming:/sys/fs/cgroup/memory# ls | grep mydocker
mydocker
root@nicktming:/sys/fs/cgroup/memory# cat mydocker/tasks
29478
root@nicktming:/sys/fs/cgroup/memory# cat mydocker/memory.limit_in_bytes
12582912
--------------------------terminal 02---------------------------------
// 運(yùn)行測(cè)試程序后退出
# ./memory
1M memory allocated
2M memory allocated
3M memory allocated
4M memory allocated
5M memory allocated
6M memory allocated
7M memory allocated
8M memory allocated
9M memory allocated
10M memory allocated
11M memory allocated
Killed
# exit
--------------------------terminal 01---------------------------------
// 查看mydocker是否被刪除
root@nicktming:/sys/fs/cgroup/memory# ls | grep mydocker
root@nicktming:/sys/fs/cgroup/memory#
實(shí)現(xiàn)
在上個(gè)版本
code-3.2.1的基礎(chǔ)上進(jìn)行改動(dòng), 會(huì)做出下面幾點(diǎn)改動(dòng).
1. cgroups/cgroup-manager.go
在此處改動(dòng)如下:
import "github.com/nicktming/mydocker/cgroups/subsystems"
type CroupManger struct {
// 限制的值
Resource *subsystems.ResourceConfig
// 用于在當(dāng)前容器中標(biāo)識(shí)有哪些subsystem需要做限制
SubsystemsIns []subsystems.Subsystem
// 用于啟動(dòng)多個(gè)container的containerId 比如memory則是:/sys/fs/cgroup/memory/mydocker/[containerId]
//path string
}
func (c *CroupManger) Set() {
for _, sub := range c.SubsystemsIns {
sub.Set(c.Resource)
}
}
func (c *CroupManger) Apply(pid string) {
for _, sub := range c.SubsystemsIns {
sub.Apply(pid)
}
}
func (c *CroupManger) Destroy() {
for _, sub := range c.SubsystemsIns {
sub.Remove()
}
}
這里的CroupManger是暴露給外部調(diào)用程序, 統(tǒng)一進(jìn)行管理包括加入或者去除某種
subsystem類型的限制如Set()和Destroy(), 加入pid(Apply()方法)等等.
至于需要對(duì)某種
subsystem進(jìn)行加入限制,則由屬性SubsystemsIns來(lái)獲得, 該屬性是個(gè)數(shù)組, 包括所有需要加限制的subsystem. 所以subsystems.Subsystem是一個(gè)接口, 所有的subsystem包括(memory,cpuset等等)都需要實(shí)現(xiàn)該接口的方法.
加限制總得需要加多少, 比如需要對(duì)內(nèi)存最大限制多少, 這些變量會(huì)保存到屬性
Resource中.
2. 增加cgroups/subsystems/ResourceConfig.go
package subsystems
type ResourceConfig struct {
MemoryLimit string
}
type Subsystem interface {
Name() string
Set(res *ResourceConfig) error
Apply(pid string) error
Remove() error
}
const (
ResourceName = "mydocker"
)
這里只是定義了所有
subsystem需要實(shí)現(xiàn)的接口Subsystem和資源變量ResourceConfig.
3. 修改cgroups/subsystems/memory.go
因?yàn)樾枰獙?shí)現(xiàn)
Subsystem接口, 對(duì)于Set方法只需要在原來(lái)的基礎(chǔ)上把參數(shù)加以修改即可, 對(duì)于Apply, Remove方法不需要做改變, 增加了MemorySubsystem定義和Name()方法.
type MemorySubsystem struct {
}
func (s *MemorySubsystem) Set(res *ResourceConfig) error {
if res.MemoryLimit != "" {
content := res.MemoryLimit
absolutePath := ""
if absolutePath = FindAbsolutePath(s.Name()); absolutePath == "" {
log.Printf("ERROR: absoutePath is empty!\n")
return fmt.Errorf("ERROR: absoutePath is empty!\n")
}
if err := ioutil.WriteFile(path.Join(absolutePath, "memory.limit_in_bytes"), []byte(content),0644); err != nil {
log.Printf("ERROR write content:%s.\n", content)
return fmt.Errorf("ERROR write content:%s.\n", content)
}
}
return nil
}
func (s *MemorySubsystem) Name() string {
return "memory"
}
修改command/command.go
修改
RunCommand, 因?yàn)閺拿钚兄械玫较拗苾?nèi)存的值memory, 如果用戶設(shè)置了該參數(shù), 此時(shí)需要把該限制對(duì)應(yīng)的subsystem加入到CroupManager中的屬性SubsystemsIns數(shù)組中對(duì)其限制, 并把memory值放到ResourceConfig中的MemoryLimit屬性.
var RunCommand = cli.Command{
Name: "run",
Flags: []cli.Flag {
cli.BoolFlag{
Name: "it",
Usage: "enable tty",
},
cli.StringFlag{
Name: "m",
Usage: "memory usage",
},
},
Action: func(c *cli.Context) error {
tty := c.Bool("it")
memory := c.String("m")
command := c.Args().Get(0)
res := subsystems.ResourceConfig{
MemoryLimit: memory,
}
cg := cgroups.CroupManger {
Resource: &res,
SubsystemsIns: make([]subsystems.Subsystem, 0),
}
if memory != "" {
cg.SubsystemsIns = append(cg.SubsystemsIns, &subsystems.MemorySubsystem{})
}
Run(command, tty, &cg)
return nil
},
}
修改command/run.go
因?yàn)?code>Run方法中上個(gè)版本是直接傳的內(nèi)存限制值
memory,這個(gè)版本已經(jīng)封裝了memory, 因此Run方法中也需要做一些相應(yīng)的變化.
func Run(command string, tty bool, cg *cgroups.CroupManger) {
//cmd := exec.Command(command)
cmd := exec.Command("/proc/self/exe", "init", command)
cmd.SysProcAttr = &syscall.SysProcAttr{
Cloneflags: syscall.CLONE_NEWUTS | syscall.CLONE_NEWPID | syscall.CLONE_NEWNS | syscall.CLONE_NEWNET | syscall.CLONE_NEWIPC,
}
if tty {
cmd.Stderr = os.Stderr
cmd.Stdout = os.Stdout
cmd.Stdin = os.Stdin
}
/**
* Start() will not block, so it needs to use Wait()
* Run() will block
*/
if err := cmd.Start(); err != nil {
log.Printf("Run Start err: %v.\n", err)
log.Fatal(err)
}
//log.Printf("222 before process pid:%d, memory:%s\n", cmd.Process.Pid, memory)
//subsystems.Set(memory)
//subsystems.Apply(strconv.Itoa(cmd.Process.Pid))
//defer subsystems.Remove()
// 變動(dòng)在此
cg.Set()
defer cg.Destroy()
cg.Apply(strconv.Itoa(cmd.Process.Pid))
cmd.Wait()
}
所有改動(dòng)已經(jīng)做完, 運(yùn)行結(jié)果會(huì)如上面的效果一致.
參考
1. 自己動(dòng)手寫docker.(基本參考此書,加入一些自己的理解,加深對(duì)
docker的理解)
全部?jī)?nèi)容
mydocker.png
1. [mydocker]---環(huán)境說(shuō)明
2. [mydocker]---urfave cli 理解
3. [mydocker]---Linux Namespace
4. [mydocker]---Linux Cgroup
5. [mydocker]---構(gòu)造容器01-實(shí)現(xiàn)run命令
6. [mydocker]---構(gòu)造容器02-實(shí)現(xiàn)資源限制01
7. [mydocker]---構(gòu)造容器02-實(shí)現(xiàn)資源限制02
8. [mydocker]---構(gòu)造容器03-實(shí)現(xiàn)增加管道
9. [mydocker]---通過(guò)例子理解存儲(chǔ)驅(qū)動(dòng)AUFS
10. [mydocker]---通過(guò)例子理解chroot 和 pivot_root
11. [mydocker]---一步步實(shí)現(xiàn)使用busybox創(chuàng)建容器
12. [mydocker]---一步步實(shí)現(xiàn)使用AUFS包裝busybox
13. [mydocker]---一步步實(shí)現(xiàn)volume操作
14. [mydocker]---實(shí)現(xiàn)保存鏡像
15. [mydocker]---實(shí)現(xiàn)容器的后臺(tái)運(yùn)行
16. [mydocker]---實(shí)現(xiàn)查看運(yùn)行中容器
17. [mydocker]---實(shí)現(xiàn)查看容器日志
18. [mydocker]---實(shí)現(xiàn)進(jìn)入容器Namespace
19. [mydocker]---實(shí)現(xiàn)停止容器
20. [mydocker]---實(shí)現(xiàn)刪除容器
21. [mydocker]---實(shí)現(xiàn)容器層隔離
22. [mydocker]---實(shí)現(xiàn)通過(guò)容器制作鏡像
23. [mydocker]---實(shí)現(xiàn)cp操作
24. [mydocker]---實(shí)現(xiàn)容器指定環(huán)境變量
25. [mydocker]---網(wǎng)際協(xié)議IP
26. [mydocker]---網(wǎng)絡(luò)虛擬設(shè)備veth bridge iptables
27. [mydocker]---docker的四種網(wǎng)絡(luò)模型與原理實(shí)現(xiàn)(1)
28. [mydocker]---docker的四種網(wǎng)絡(luò)模型與原理實(shí)現(xiàn)(2)
29. [mydocker]---容器地址分配
30. [mydocker]---網(wǎng)絡(luò)net/netlink api 使用解析
31. [mydocker]---網(wǎng)絡(luò)實(shí)現(xiàn)
32. [mydocker]---網(wǎng)絡(luò)實(shí)現(xiàn)測(cè)試
