docker containerd中的容器操作


containerd的中的各種操作都是通過Task來進行的,因此對於容器的create, start, delete等等操作其實都是一個個的Task而已。

Task的數據結構如下所示:

type Task interface {

  Errorch() chan error

}



type baseTask struct {

  errCh    chan error
  mu      sync.Mutex
}

  

container的數據結構如下所示,而container對外暴露的interface是Container,其中包含了對container的各種操作,包括ID(), Delete()等等。

type container struct {

  // path to store runtime state information

  root    string
  id     string
  bundle   string
  runtime    string
  runtimeArgs []string
  shim    string
  processes  map[string]*process
  labels    []string
  oomFds   []int
  noPivotRoot bool
  timeout   time.Duration
}

  

 

容器的delete操作

DeleteTask的數據結構如下所示:

// DeleteTask holds needed paramaters to remove a container

type DeleteTask struct {

  baseTask

  ID    string
  Status  uint32
  PID    string
  NoEvent  bool
  Process  runtime.Process
}

  

-2、containerd/supervisor/monitor_linux.go

func (m *Monitor) start()對獲取到的syscall.EpollEvent進行處理,當獲取的event的id指向的是一個runtime.Process並且event的Events類型為syscall.EPOLLHUP時,先對該process從events中刪除,進行epoll相關的清理操作,最后調用m.exits <- t

 

-1、containerd/supervisor/supervisor.go

func (s *Supervisor) exitHandler()

(1)、在啟動daemon的時候,啟動過一個exitHandler的goroutine,該函數主要的作用就是從s.monitor.exits這個runtime.Process類型的channel中獲取退出的process。

(2)、對於每個退出的process,創建 e := &ExitTask{Process: p,},最后s.SendTask(e),最終經過taskHandler的調度,最終會在exit()函數進行處理

 

0、containerd/supervisor/exit.go

func (s *Supervisor) exit(t *ExitTask) 

(1)、調用`proc := t.Process `, `status, err := proc.ExitStatus()`獲取進程的退出碼

(2)、如果proc.ID()不是runtime.InitProcessID,則說明只是一個exec的進程退出,則創建一個ne := &ExecExitTask{},再調用s.execExit()進行處理

(3)、若為退出的是init進程,則創建一個ne := &DeleteTask{},再調用s.delete(ne)進行處理

 

1、containerd/supervisor/delete.go

func (s *Supervisor) delete(t *DeleteTask) error

(1)、調用i, ok := s.containers[t.ID]獲取容器實例,再調用s.deleteContainer(i.container)

(2)、當t.Process 不為nil 時,調用t.Process.Wait()

(3)、當t.NoEvent為false時,則調用s.notifySubscribers(Event{Type: StateExit, Timestamp: time.Now(), ID: t.ID, Status: t.status, PID: t.PID,})

(4)、更新supervisor的container信息,調用ContainersCounter.Dec(1)和ContainerDeleteTimer.UpdateSince(start)

 

2、containerd/supervisor/delete.go

func (s *Supervisor) deleteContainer(container runtime.Container) error

該函數很簡單,先調用delete(s.containers, container.ID()),再調用return container.Delete()

 

3、containerd/runtime/container.go

首先調用os.RemoveAll(filepath.Join(c.root, c.id)),刪除目錄/var/run/docker/libcontainerd/containerd/container-id,接着利用exec.Command直接調用調用命令行`docker-runc delete contain-id。

 

容器的kill操作

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

func (s *apiServer) Signal(ctx context.Context, r *types.SignalRequest) (*types.SignalResponse)

這個函數就是根據r中的內容對supervisor.SignalTask進行填充,最后調用s.sv.SendTask(e),再返回return &types.SignalResponse{}, nil

 

2、containerd/supervisor/signal.go

func (s *Supervisor) signal(t *SignalTask) error

(1)、首先調用i, ok := s.containers[t.ID]獲取container實例

(2)、再調用processes, err := i.container.Processes()獲取容器中所有的process實例

(3)、最后遍歷processes,找到t.PID對應的process,調用return p.Signal(t.Signal)

 

3、containerd/runtime/process.go

func (p *process) Signal(s os.Signal) error

該函數只是簡單地調用return syscall.Kill(p.pid, s.(syscall.Signal)),給相應的進程發送信號。

 


免責聲明!

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



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