本文致力於梳理containerd的架構與執行原理。
參考文章:https://github.com/containerd/containerd/blob/main/core/runtime/v2/README.md
https://www.cnblogs.com/zhangmingcheng/p/17524721.html
核心執行思路
containerd
使用Runtime v2
並引入shim API
,使得containerd
可以和很多執行時整合。基於此,contaienrd
僅僅作為協調下發容器配置、容器資料的高階管理器,實際由低階執行時啟停管理容器。
舉例:kubernetes
呼叫containerd
建立容器,containerd
部署容器依賴的檔案系統與提供必要配置資訊,contained
通知低階執行時啟動pod
。
實現模式:
- 單個二進位制執行時,同時提供服務監聽、啟停等容器操作。
- 提供一個分離的、只負責服務監聽的shim墊片程式,其呼叫對應的單獨的執行時引擎以啟停容器等操作。
使用第二個模式可以做到更輕鬆的整合對各種容器執行時(僅需其符合OCI執行時規範),即可透過一個runtime shim
處理ttRPC協議請求,便於同時使用多個不同的容器執行時引擎(Runtime Class)。
所以第二個模式也是預設模式,即runc
作為預設執行時引擎,containerd
呼叫containerd-shim-runc-v2
墊片告知runc
引擎對容器的啟停等操作。
墊片與引擎
墊片由containerd
呼叫,主要為containerd
提供通訊埠和配置資訊,其在被啟動時可以指定極少的引數,且是作為守護程序。containerd-shim
啟動containerd-shim-runc-v2
後立即退出,containerd-shim-runc-v2
父程序就成為了systemd(1)
,這樣containerd-shim-runc-v2
就和containerd
脫離了關係,即便containerd
退出也不會影響到容器。
墊片在socket
監聽來自containerd
的ttRPC
命令,而後透過fork
/exec
呼叫引擎以啟停容器等操作。如shim
(io.containerd.runc.v2)呼叫runc
。
引擎如runc
負責啟停容器等操作,containerd
預設提供了containerd-shim-runc-v2
墊片以呼叫runc
,runc
再透過系統介面呼叫libcontainer
啟停容器等。
由於每個 shim 例項都作為守護程序與 containerd 進行通訊,同時透過呼叫獨立執行時來為容器建立父子關係,因此可以為多個容器和呼叫使用一個 shim。例如,您可以讓一個containerd-shim-runc-v2容器與一個容器進行通訊,並且它可以呼叫十個不同的容器。
墊片與容器可以是一對一或一對多的關係,常常Pod就是一對多。
流程:containerd
收到建立容器的請求,containerd
佈置容器的檔案系統,並建立必要的容器配置資訊,containerd
呼叫shim
,包括容器配置,它使用該資訊來決定是否啟動新的套接字偵聽器(1:1 shim 到容器)或使用現有的偵聽器(1:many).如果存在,則返回現有套接字的地址並退出;如果是新的,墊片建立一個新程序來在套接字上偵聽來自 containerd
的ttRPC
命令,返回該套接字的地址給containerd
後退出.containerd
向shim
傳送啟動容器的命令,shim
呼叫runc
來建立/啟動/停止容器。