// containerd-shim is a small shim that sits in front of a runtime implementation that allows it to be reparented to init and handle reattach from the caller.docker
// the cwd of the shim should be the path to the state directory where the shim can locate fifos and other information\json
// Arg0: id of the containerbash
// Arg1: bundle pathapp
// Arg2: runtime binaryide
在啓動容器時,containerd-shim的命令行格式以下所示:函數
docker-containerd-shim 9decb150527a3b64a86b85cfc6faeb09f786dcb2f4e668611418280c75755539
/var/run/docker/libcontainerd/9decb150527a3b64a86b85cfc6faeb09f786dcb2f4e668611418280c75755539 docker-runc
一、containerd/containerd-shim/main.goui
func main()spa
(1)、建立log文件,f, err := os.OpenFile(filepath.Join(cwd, "shim-log.json") ...)命令行
(2)、調用err := start(f)函數,若err不爲nil,當err爲errRuntime的時候,直接關閉f並返回,不然將錯誤記錄到shim-log.json中orm
二、containerd/containerd-shim/main.go
// start handling signals as soon as possible so that things are properly reaped
// or if runtime exits before we hit the handler
func start(log *os.File) error
(1)、set the shim as the subreaper for all orphaned processes created by the container,err := osutils.SetSubreaper(1)
(2)、打開exit pipe和control pipe
(3)、調用p, err := newProcess(flag.Arg(0), flag.Arg(1), flag.Arg(2)),加載process實例,再調用p.create()
(4)、msgC := make(chan controlMesage, 32),建立一個goroutine,從control pipe中不斷讀取controlMessage
(5)、最後,一個無限for循環,對來自signal的信號和controlMessage進行處理
(6)、當從signal中得到的信號爲SIGCHLD時,當退出的進程爲runtime時,退出shim
(7)、對來此control pipe的controlMessage進行處理,當msg的Type爲0時,關閉stdin,當Type爲1時,且p.console不爲nil,則調整tty的窗口大小
三、containerd/containerd-shim/process.go
func newProcess(id, bundle, runtimeName string)
(1)、p := &process{id: id, bundle: bundle, runtime: runtimeName}
(2)、調用s, err := loadProcess(),從process.json文件中加載state,p.state = s
(3)、調用p.openIO(),最後,返回p
四、containerd/containerd-shim/process.go
// openIO opens the pre-created fifo's for use with the container in RDWR so that they remain open if the other side stops listening
func (p *process) openIO() error
(1)、先建立一個goroutine,打開p.state.Stdin, p.stdinCloser = os.openFile(p.state.Stdin, syscall.O_WRONLY)
// NewConsole returns an initialized console that can be used within a container by copying bytes from the master side to the slave that is attached as the tty for the container's init process
(2)、若是p.state.Terminal爲true,調用master, console, err := newConsole(uid, gid),p.console = master, p.consolePath = console,再打開p.state.Stdin和p.state.Stdout,最後調用io.Copy將stdin/stdout與master相連
(3)、對於非tty的狀況,調用i, err := p.initializeIO(uid),p.shimIO = i,再打開p.state.Stdout和p.state.Stderr(方式爲可讀寫)分別與i.Stdou和i.Stderr相連。接着打開p.state.Stdin爲只讀模式,再將i.Stdin和p.state.Stdin相連
五、containerd/containerd-shim/process.go
func (p *process) initializeIO(rootuid int)
該函數生成三個os.Pipe()並分別將一端賦給i = &IO{},再將另外一端賦給p.stdio
六、containerd/containerd-shim/process.go
func (p *process) create() error
(1)、獲取當前目錄,建立logPath := filepath.Join(cwd, "log.json"),再擴展args := append([]string{"--log", logPath, "--log-format", "json"}, p.state.RuntimeArgs...)
(2)、對exec,checkpoint,create進行不一樣的處理,這裏只討論create的狀況,繼續擴展args = append(args, "create", "--bundle", p.bundle, "--console", p.consolepath)
(3)、擴展參數--pid-file,cmd := exec.Command(p.runtime, args...),而且將cmd的stdio設置爲p.stdio
(4)、調用cmd.Start(),再調用p.stdio.stdout.Close()和p.stdio.stderr.Close()(why????)
(5)、cmd.Wait(),從pid文件中讀出pid,而且將p.containerPid 設置爲pid