(4)构造容器之实现run命令版的容器

linux proc

linux 下的/proc 文件系统是又内核提供的,包含了系统运行时信息(系统内存、mount 设备信息,硬件配置等),为访问内核数据提供接口。

实现runC

项目结构
项目结构.png

https://github.com/justinmjc/mymoby

tag:3.1节

代码解析

main.go

package main

import (
    "github.com/urfave/cli"
    "github.com/Sirupsen/logrus"
    "log"
    "os"
)

const usage  = `my moby is a simple contaniner runtime implementation.`
func main() {
    app :=cli.NewApp()
    app.Name = "mymoby"
    app.Usage=usage

    app.Commands = []cli.Command{
        initCommand,
        runCommand,
    }

    app.Before = func(context *cli.Context) error {
        logrus.SetFormatter(&logrus.JSONFormatter{})

        log.SetOutput(os.Stdout)
        return nil
    }

    if err := app.Run(os.Args); err!=nil{
        log.Fatal(err)
    }
}


使用github.com/urfave/cli提供的命令行工具,定义了mymoby的基本命令initCommand和runCommand,然后在app.Before 初始化日志配置。

接下来开下initCommand和runCommand的定义,在main_command.go文件中

main_command.go

package main

import (
    "github.com/urfave/cli"
    "fmt"
    log "github.com/Sirupsen/logrus"
    "./container"
)

var runCommand = cli.Command{
    Name:"run",
    Usage:`Create a container with namespace and cgroups limit mymoby run -ti [command]`,
    Flags:[]cli.Flag{
        cli.BoolFlag{
        Name:"ti",
        Usage:"enable tty",
        },

    },
    /*
    这里是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")
        }
        cmd := context.Args().Get(0)
        tty := context.Bool("ti")
        Run(tty,cmd)
        return nil
    },

}

var initCommand = cli.Command{
    Name: "init",
    Usage: "Init container process run user's process in container.Do not call it outside",
    /*
    1获取传递过来的command参数
    2执行容器初始化操作
     */
    Action: func(context *cli.Context)  error {
        log.Infof("init come on")
        cmd := context.Args().Get(0)
        err :=container.RunContainerInitProcess(cmd, nil)
        return err
    },
}


runCommand中的Run在run.go中定义

package main

import (
    log "github.com/Sirupsen/logrus"
    "./container"
    "os"
)
func Run(tty bool,command string)  {
    parent := container.NewParentProcess(tty,command)
    if err :=parent.Start(); err!=nil{
        log.Error(err)
    }
    parent.Wait()
    os.Exit(1)
}

Run 调用NewParentProcess(),在container_process.go中定义

package container

import (
    "os/exec"
    "syscall"
    "os"
)

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
}


在NewParentProcess()中“/proc/self”指的是当前运行进程自己的环境,exec其实是自己调用自己,通过这种方式对创建出来的进程进行初始化。

args的第一个参数"init",实际上就是会去调用initCommand进行初始化操作

下面的clone参数就是去fork出来一个新进程,使用namespace隔离环境

Run执行完在NewParentProcess()后执行parent.Start(),Start方法是真正前面创建好的command的调用,它首先clone出一个Namespace隔离的进程,然后在子进程中调用/proc/self/exe,发送init,初始化容器的一些资源。

最后,运行



maojiancai@bogon:~/mygo/mymoby$ go build .
maojiancai@bogon:~/mygo/mymoby$ ls
container  main_command.go  main.go  mymoby  README.md  run.go  src
maojiancai@bogon:~/mygo/mymoby$ ./mymoby run -ti /bin/sh
{"level":"error","msg":"fork/exec /proc/self/exe: operation not permitted","time":"2018-01-02T06:56:12-08:00"}
maojiancai@bogon:~/mygo/mymoby$ sudo ./mymoby run -ti /bin/sh
[sudo] password for maojiancai:
{"level":"info","msg":"init come on","time":"2018-01-02T06:56:44-08:00"}
{"level":"info","msg":"command %s/bin/sh","time":"2018-01-02T06:56:44-08:00"}
# ps -ef
UID         PID   PPID  C STIME TTY          TIME CMD
root          1      0  0 06:56 pts/0    00:00:00 /bin/sh
root          4      1  0 06:56 pts/0    00:00:00 ps -ef
#

在init.go 中调用的syscall.Exec方法,最终调用了Kernel的execve 这个系统函数。它的作用是执行当前filename对应的程序。他会覆盖当前进行的镜像、数据和堆栈信息,PID,这些都会被将要运行的程序覆盖。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容

  • 1:InputChannel提供函数创建底层的Pipe对象 2: 1)客户端需要新建窗口 2)new ViewRo...
    自由人是工程师阅读 5,235评论 0 18
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,580评论 18 139
  • 写这个系列文章主要是对之前做项目用到的docker相关技术做一些总结,包括docker基础技术Linux命名空间,...
    __七把刀__阅读 5,772评论 0 16
  • 01今天去参加一亲戚孩子婚礼。婚宴设在一家大宾馆。我们刚到那儿,还没有几分钟,就看到一对乞丐夫妇,年龄相当大了,看...
    向日葵3阅读 266评论 0 0
  • 四月大概是我最喜欢的月份了,空气中充满了花香,让人感觉到蓬勃的生命气息。天气也足够好,温度也足够好,一切都是刚刚好...
    不晚sir阅读 450评论 4 4