docker containerd 中的create 容器操作


containerd的create container的API如下所示:

type CreateContainerRequest struct {

  Id       string
  BundlePath  string
  Checkpoint   string
  Stdin     string
  Stdout     string
  Stderr     string
  Labels    []string
  NoPivotRoot  bool
  Runtime    string
  RuntimeArgs []string
  CheckpointDir  string
}

  

StartTask結構如下所示:

type StartTask struct {

  baseTask

  ID      string
  BundlePath  string
  Stdout     string
  Stderr      string
  Stdin     string
  StartResponse   chan StartResponse
  Labels      []string
  NoPivotRoot  bool
  Checkpoint    *runtime.Checkpoint
  CheckpointDir   string
  Runtime     string
  RuntimeArgs   []string
}

  

 

1、containerd/api/grpc/server/server.go

func (s *apiServer) CreateContainer(ctx context.Context, c *types.CreateContainerRequest) (*types.CreateContainerResponse, error)

(1)、根據c填充獲得e := &supervisor.StartTask{},並調用s.sv.SendTask(e)

(2)、調用 r := <-e.StartResponse,再調用apiC ,err := createAPIContainer(r.Container, false)獲取創建的容器實例

(3)、return &types.CreateContainerResponse{Container: apiC,}

 

2、containerd/supervisor/create.go

func (s *Supervisor) start(t *StartTask) error

(1)、根據t的內容創建容器,runtime.New主要根據ContainerOpts填充結構container獲得容器實例,再將創建state並寫入狀態文件中。

container, err := runtime.New(runtime.ContainerOpts{

  Root:    s.stateDir,
  ID:     t.ID,
  Bundle:   t.BundlePath,
  Runtime:   rt,
  RuntimeArgs: rtArgs,

  Shim:    s.shim,

  Labels:    t.Labels,
  NoPivotRoot:  t.NoPivotRoot,
  Timeout:   s.timeout
})

  

(2)、注冊新增加的容器,調用s.containers[t.ID] = &containerInfo{container: container,}

(3)、根據新獲得的container實例和t的內容,填充獲得startTask,再調用s.startTask <- task 交由worker處理

task := &startTask{

  Err:      t.ErrorCh(),
  Container:   container,
  StartResponse: t.StartResponse,
  Stdin:       t.Stdin,
  Stdout:     t.Stdout,
  Stderr:     t.Stderr
}

  

3、containerd/supervisor/worker.go

// Start runs a loop in charge of starting new containers

func (w *Worker) Start()

containerd在剛創建時,就啟動了10個goroutine,用於處理startTasks,這里的Start函數就是從startTasks這個channel中獲取任務,並處理

(1)、調用process, err := t.Container.Start(t.checkpointPath, runtime.NewStdio(t.Stdin, t.Stdout, t.Stderr))啟動容器,NewStdio()僅僅只是將參數封裝到一個統一的Stdio結構中

(2)、分別調用w.s.monitor.MonitorOOM(t.Container),w.s.monitorProcess(process)對容器進行監控,調用t.StartResponse <- StartResponse{Container: t.Container}返回創建成功的容器實例

 

4、containerd/runtime/container.go

func (c *container) Start(checkpointPath string, s Stdio) (Process, error)

(1)、創建processRoot := filepath.Join(c.root, c.id, InitProcessID)目錄

(2)、容器創建命令 cmd := exec.Command(c.shim, c.id, c.bundle, c.runtime),配置cmd目錄為processRoot,spec, err := c.readSpec()

(3)、生成config如下:

config := &processConfig {

  checkpoint:    checkpointPath,
  root:       processRoot,
  id:        InitProcessID,
  c:         c,
  stdio:        s,
  spec:        spec,
  processSpec:   specs.ProcessSpec(spec.Process),

}

  

(4)、根據config,調用p, err := newProcess(config),生成process實例

(5)、最后調用c.createCmd(InitProcessID, cmd, p),並返回 return p, nil

 

5、containerd/runtime/process.go

func newProcess(config *processConfig) (*process, error)

(1)、根據config生成process實例,p := &process{root: config.root, id: config.id, container: config.c, ....., cmdDoneCh: make(chan struct{}), state: Running,}

(2)、創建狀態文件os.Create(filepath.Join(config.root, "process.config")),生成ps := ProcessState{...},並將ps的內容寫入狀態文件中

(3)、調用exit, err := getExitPipe(filepath.Join(config.root, ExitFile))和control ,err := getControlPipe(filepath.Join(config.root, ControlFile))生成兩個pipe文件,並分別將exit和control賦值給p.exitPipe和p.controlPipe,最后 return p

 

6、containerd/runtime/process.go

getExitPipe和getControlPipe生成兩個FIFO文件,其中Exit函數中的FIFO是只讀的,而Control函數中的FIFO是讀寫的

 

7、containerd/runtime/container.go

func (c *container) createCmd(pid string, cmd *exec.Cmd, p *process)

(1)、p.cmd = cmd, 再調用 cmd.Start()

(2)、構建defer函數,其中生成一個goroutine,其中調用p.cmd.Wait(),再調用same, err := p.isSameProcess(),如果same為true並且p.pid > 0則再進行一些處理

(3)、調用c.waitForCreate(p, cmd),c.processes[pid] = p

 

8、containerd/runtime/container.go

func (c *container) waitForCreate(p *process, cmd *exec.Cmd) error

(1)、該函數先啟動一個goroutine用於從pidfile中讀取pid

(2)、select,從(1)中的goroutine接收結果,或者超時,當超時時,調用cmd.Process.Kill()和cmd.Wait()


免責聲明!

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



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