博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
自己动手写docker-3
阅读量:5750 次
发布时间:2019-06-18

本文共 3154 字,大约阅读时间需要 10 分钟。

3.构造容器

3.1 构造实现run 命令版本的容器

类似这么启动./myDocker run -ti /bin/bash

大致流程

1. 调用自己创建新的namespace
func NewParentProcess(tty bool, command string) *exec.Cmd {	args := []string{
"init", command} cmd := exec.Command("/proc/self/exe", args...) cmd.SysProcAttr = &syscall.SysProcAttr{ Cloneflags: syscall.CLONE_NEWUTS | syscall.CLONE_NEWPID | syscall.CLONE_NEWNS | syscall.CLONE_NEWNET | syscall.CLONE_NEWIPC, } if tty { cmd.Stdin = os.Stdin cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr } return cmd}// 之后调用cmd.Start(), 调用自己传入了init,自身处理Init传参如下复制代码
2.在新的namespace中进行init操作并执行命令(例如/bin/bash)
func RunContainerInitProcess(command string, args []string) error {	logrus.Infof("command %s", command)	defaultMountFlags := syscall.MS_NOEXEC | syscall.MS_NOSUID | syscall.MS_NODEV	syscall.Mount("", "/", "", syscall.MS_PRIVATE | syscall.MS_REC, "")	// 需要加上上面一行,源码有误,或者见后面的坑的修改方法,同时这个方法会返回error最好捕捉下,MS_REC为目录子树递归的创建绑定挂载	syscall.Mount("proc", "/proc", "proc", uintptr(defaultMountFlags), "")	argv := []string{command}	if err := syscall.Exec(command, argv, os.Environ()); err != nil {		logrus.Errorf(err.Error())	}	return nil}复制代码
    • mount namespaces提供了过度的隔离,如果完全隔离,一个挂在可能需要在所有的namespace都挂载一遍
    • mount 时关于共享提供了4个参数MS_SHARED, MS_PRIVATE,MS_SLAVE,MS_UNBINDABLE
  • 有个坑,例如ubuntu18中,默认挂载时shared,可以通过/proc/$pid/mountinfo
  • 需要重新设置下sudo mount --make-rprivate / 不然namespace里面修改/proc会影响其他namespace里面的/proc(应该只对此行命令之后的子进程等适用)
  • 修改之后
  • 其他 使用unshare创建新的namespace shell:$unshare --user --mount --ipc --pid --net --uts -r --fork --propagation private bash

3.2 增加容器资源隔离

大致流程

主要逻辑就是捕获参数修改hierarchy文件系统:以下为控制cgroup的相关代码,以memory子系统为例,
package subsystemsimport(	"fmt"	"io/ioutil"	"os"	"path"	"strconv")type MemorySubSystem struct {}func (s *MemorySubSystem) Set(cgroupPath string, res *ResourceConfig) error {	if subsysCgroupPath, err := GetCgroupPath(s.Name(), cgroupPath, true); err == nil {		if res.MemoryLimit != "" {			if err := ioutil.WriteFile(path.Join(subsysCgroupPath, "memory.limit_in_bytes"), []byte(res.MemoryLimit), 0644); err != nil {				return fmt.Errorf("set cgroup memory fail %v", err)			}		}		return nil	} else {		return err	}}func (s *MemorySubSystem) Remove(cgroupPath string) error {	if subsysCgroupPath, err := GetCgroupPath(s.Name(), cgroupPath, false); err == nil {		return os.RemoveAll(subsysCgroupPath)	} else {		return err	}}func (s *MemorySubSystem) Apply(cgroupPath string, pid int) error {	if subsysCgroupPath, err := GetCgroupPath(s.Name(), cgroupPath, false); err == nil {		if err := ioutil.WriteFile(path.Join(subsysCgroupPath, "tasks"),  []byte(strconv.Itoa(pid)), 0644); err != nil {			return fmt.Errorf("set cgroup proc fail %v", err)		}		return nil	} else {		return fmt.Errorf("get cgroup %s error: %v", cgroupPath, err)	}}func (s *MemorySubSystem) Name() string {	return "memory"}复制代码

对于GetCgroupPath方法其实做了以下事情

  • 根据/proc/self/mountinfo 找出对应的hierarchy的虚拟文件系统
  • 此文件每行类似(此行为memory 挂载的hierarchy文件系统) :
    • 46 32 0:41 / /sys/fs/cgroup/memory rw,nosuid,nodev,noexec,relatime shared:24 - cgroup cgroup rw,memory, 根据最后的memory 找到/sys/fs/cgroup/memory,
  • 最终此文件夹下创建cgroup文件夹名就是传入的参数cgroupPath,然后在cgroup下修改限制(Set)或在tasks文件中增加pid(Apply)

3.3 增加管道和环境变量识别

  • 主要是修改成通过管道传输cmd,和加入了环境变量,略
  • 修改之后的流程

转载地址:http://grkkx.baihongyu.com/

你可能感兴趣的文章
工作中如何做好技术积累
查看>>
Spring Transactional
查看>>
shell脚本实例
查看>>
我的友情链接
查看>>
Windows Phone 7 隔离存储空间资源管理器
查看>>
apache安装报错undefined reference ssl
查看>>
关于爱情只有一句忠告
查看>>
CentOS 7下安装部署Oracle11g图文教程
查看>>
F#初学笔记06
查看>>
实战:将企业域名解析委派给企业DNS服务器
查看>>
在Lync 2013环境部署Office Web Apps
查看>>
微软大会Ignite,你准备好了么?
查看>>
读书笔记-高标管事 低调管人
查看>>
Master带给世界的思考:是“失控”还是进化
查看>>
用户和开发者不满苹果iCloud问题多多
查看>>
java.lang.UnsatisfiedLinkError:no dll in java.library.path终极解决之道
查看>>
我的工具:文本转音频文件
查看>>
【许晓笛】从零开始运行EOS系统
查看>>
【跃迁之路】【460天】程序员高效学习方法论探索系列(实验阶段217-2018.05.11)...
查看>>
C++入门读物推荐
查看>>