(4)構(gòu)造容器之實(shí)現(xiàn)run命令版的容器

linux proc

linux 下的/proc 文件系統(tǒng)是又內(nèi)核提供的,包含了系統(tǒng)運(yùn)行時(shí)信息(系統(tǒng)內(nèi)存瞬场、mount 設(shè)備信息野瘦,硬件配置等),為訪問(wèn)內(nèi)核數(shù)據(jù)提供接口查剖。

實(shí)現(xiàn)runC

項(xiàng)目結(jié)構(gòu)
項(xiàng)目結(jié)構(gòu).png

https://github.com/justinmjc/mymoby

tag:3.1節(jié)

代碼解析

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 初始化日志配置笋庄。

接下來(lái)開(kāi)下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命令執(zhí)行的真正函數(shù)。
    1判斷參數(shù)是否包含command
    2獲取用戶指定的command
    3調(diào)用Run function去準(zhǔn)備啟動(dòng)容器
     */
    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獲取傳遞過(guò)來(lái)的command參數(shù)
    2執(zhí)行容器初始化操作
     */
    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 調(diào)用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”指的是當(dāng)前運(yùn)行進(jìn)程自己的環(huán)境菌仁,exec其實(shí)是自己調(diào)用自己,通過(guò)這種方式對(duì)創(chuàng)建出來(lái)的進(jìn)程進(jìn)行初始化静暂。

args的第一個(gè)參數(shù)"init"济丘,實(shí)際上就是會(huì)去調(diào)用initCommand進(jìn)行初始化操作

下面的clone參數(shù)就是去fork出來(lái)一個(gè)新進(jìn)程,使用namespace隔離環(huán)境

Run執(zhí)行完在NewParentProcess()后執(zhí)行parent.Start()洽蛀,Start方法是真正前面創(chuàng)建好的command的調(diào)用摹迷,它首先clone出一個(gè)Namespace隔離的進(jìn)程,然后在子進(jìn)程中調(diào)用/proc/self/exe,發(fā)送init,初始化容器的一些資源郊供。

最后峡碉,運(yùn)行



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 中調(diào)用的syscall.Exec方法,最終調(diào)用了Kernel的execve 這個(gè)系統(tǒng)函數(shù)驮审。它的作用是執(zhí)行當(dāng)前filename對(duì)應(yīng)的程序鲫寄。他會(huì)覆蓋當(dāng)前進(jìn)行的鏡像、數(shù)據(jù)和堆棧信息疯淫,PID地来,這些都會(huì)被將要運(yùn)行的程序覆蓋。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末熙掺,一起剝皮案震驚了整個(gè)濱河市未斑,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌适掰,老刑警劉巖颂碧,帶你破解...
    沈念sama閱讀 218,941評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件荠列,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡载城,警方通過(guò)查閱死者的電腦和手機(jī)肌似,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)诉瓦,“玉大人川队,你說(shuō)我怎么就攤上這事〔窃瑁” “怎么了固额?”我有些...
    開(kāi)封第一講書人閱讀 165,345評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)煞聪。 經(jīng)常有香客問(wèn)我斗躏,道長(zhǎng),這世上最難降的妖魔是什么昔脯? 我笑而不...
    開(kāi)封第一講書人閱讀 58,851評(píng)論 1 295
  • 正文 為了忘掉前任啄糙,我火速辦了婚禮,結(jié)果婚禮上云稚,老公的妹妹穿的比我還像新娘隧饼。我一直安慰自己,他們只是感情好静陈,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布燕雁。 她就那樣靜靜地躺著,像睡著了一般鲸拥。 火紅的嫁衣襯著肌膚如雪拐格。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 51,688評(píng)論 1 305
  • 那天崩泡,我揣著相機(jī)與錄音禁荒,去河邊找鬼猬膨。 笑死角撞,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的勃痴。 我是一名探鬼主播谒所,決...
    沈念sama閱讀 40,414評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼沛申!你這毒婦竟也來(lái)了劣领?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 39,319評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤铁材,失蹤者是張志新(化名)和其女友劉穎尖淘,沒(méi)想到半個(gè)月后奕锌,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,775評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡村生,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年惊暴,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片趁桃。...
    茶點(diǎn)故事閱讀 40,096評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡辽话,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出卫病,到底是詐尸還是另有隱情油啤,我是刑警寧澤,帶...
    沈念sama閱讀 35,789評(píng)論 5 346
  • 正文 年R本政府宣布蟀苛,位于F島的核電站益咬,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏帜平。R本人自食惡果不足惜础废,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望罕模。 院中可真熱鬧评腺,春花似錦、人聲如沸淑掌。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,993評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)抛腕。三九已至芋绸,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間担敌,已是汗流浹背摔敛。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,107評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留全封,地道東北人马昙。 一個(gè)月前我還...
    沈念sama閱讀 48,308評(píng)論 3 372
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像刹悴,于是被迫代替她去往敵國(guó)和親行楞。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 1:InputChannel提供函數(shù)創(chuàng)建底層的Pipe對(duì)象 2: 1)客戶端需要新建窗口 2)new ViewRo...
    自由人是工程師閱讀 5,313評(píng)論 0 18
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理土匀,服務(wù)發(fā)現(xiàn)子房,斷路器,智...
    卡卡羅2017閱讀 134,660評(píng)論 18 139
  • 寫這個(gè)系列文章主要是對(duì)之前做項(xiàng)目用到的docker相關(guān)技術(shù)做一些總結(jié),包括docker基礎(chǔ)技術(shù)Linux命名空間证杭,...
    __七把刀__閱讀 5,807評(píng)論 0 16
  • 01今天去參加一親戚孩子婚禮解愤∶勘遥婚宴設(shè)在一家大賓館。我們剛到那兒琢歇,還沒(méi)有幾分鐘兰怠,就看到一對(duì)乞丐夫婦,年齡相當(dāng)大了李茫,看...
    向日葵3閱讀 274評(píng)論 0 0
  • 四月大概是我最喜歡的月份了魄宏,空氣中充滿了花香秸侣,讓人感覺(jué)到蓬勃的生命氣息。天氣也足夠好宠互,溫度也足夠好味榛,一切都是剛剛好...
    不晚sir閱讀 466評(píng)論 4 4