docker containerd shim分析


// 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.

// the cwd of the shim should be the path to the state directory where the shim can locate fifos and other information\

// Arg0: id of the container

// Arg1: bundle path

// Arg2: runtime binary

在啟動容器時,containerd-shim的命令行格式如下所示:

docker-containerd-shim 9decb150527a3b64a86b85cfc6faeb09f786dcb2f4e668611418280c75755539 
/var/run/docker/libcontainerd/9decb150527a3b64a86b85cfc6faeb09f786dcb2f4e668611418280c75755539 docker-runc

  

1、containerd/containerd-shim/main.go

func main()

(1)、創建log文件,f, err := os.OpenFile(filepath.Join(cwd, "shim-log.json") ...)

(2)、調用err := start(f)函數,若err不為nil,當err為errRuntime的時候,直接關閉f並返回,否則將錯誤記錄到shim-log.json中

 

2、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的窗口大小

 

3、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

 

4、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相連

 

5、containerd/containerd-shim/process.go

func (p *process) initializeIO(rootuid int) 

該函數生成三個os.Pipe()並分別將一端賦給i = &IO{},再將另一端賦給p.stdio

 

6、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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM