k8s之docker


Docker介紹

最近聽聞 K8s 棄用dockershim,一個從事k8s開發的工作人員不懂這是什么意思是不行的,所以好好梳理梳理下。

一、docker原理
關於docker1.12.x,該版本的docker由docker-client,dockerd,containerd,docker-shim,runc組成
dockerd本身實屬是對容器相關操作的api的最上層封裝,直接面向操作用戶。http訪問)
containerd:dockerd實際真實調用的還是containerd的api接口(rpc方式實現),containerd是dockerd   

runc之間的一個中間交流組件。
docker-shim(注意不是dockershim):一個真實運行的容器的真實墊片載體,每啟動一個容器都會起一    

個新的docker-shim的一個進程。他直接通過指定的三個參數:容器id,boundle目錄

containerd的對應某個容器生成的目錄,一般位於:

/var/run/docker/libcontainerd/containerID),運行是二進制(默認為runc)來調用runc

api創建一個容器(比如創建容器:最后拼裝的命令如下:runc create 。。。。。)
runc一個命令行工具端,他根據oci(開放容器組織)的標准來創建和運行容器。

runtime是容器真正運行的地方。runtime 需要跟操作系統kernel緊密協作,為容器提供運

行環境,lxcrunc rkt 是目前主流的三種容器 runtime
他們之間的關系如下圖:

 

 這里應該是containerd-shim

 

 

二、k8s如何使用docker

 

本次改動主要內容是准備刪除 kubelet 中的 dockershim,當然這種做法也是符合預期的。在早期 rkt 和 docker 爭霸時,kubelet 中需要維護兩坨代碼分別來適配docker和rkt,這使得 kubelet 每次發布新功能都需要考慮對運行時組件的適配問題,嚴重拖慢了新版本發布速度。另外虛擬化已經是一個普遍的需求,如果出現了類型的運行時,SIG-Node 小組可能還需要把和新運行時適配的代碼添加到 kubelet 中。這種做法並不是長久之計,於是在 2016 年,SIG-Node提出了容器操作接口 CRI(Container Runtime Interface)。 CRI 是對容器操作的一組抽象,只要每種容器運行時都實現這組接口,kubelet 就能通過這組接口來適配所有的運行時。但 Docker 當時並沒有(也不打算)實現這組接口, kubelet 只能在內部維護一個稱之為“dockershim”組件,這個組件充當了 docker 的 CRI 轉接器,kubelet 在創建容器時通過 CRI 接口調用 dockershim ,而 dockershim 在通過 http 請求把請求交給 docker 。

在使用實現了 CRI 接口的組件作為容器運行時的情況下,kubelet 創建容器的調用鏈如圖中紅色箭頭所示,kubelet 中的 ContainerManager (其實我覺得這里是runtimeManager可以直接通過 CRI 調用到容器運行時,這過程中只需要一次 grpc 請求;而在使用docker時,runtimeManager會走圖中藍色的調用鏈,CRI 的請求通過 unix:///var/run/dockershim.sock 流向 dockershim,dockershim 做轉換后把請求轉發給 docker。這種做法讓調用鏈變長且不穩定性,不優雅,還給 kubelet 的維護添加了額外工作,把這部分內容從 kubelet 刪掉就是時間問題了。

containerd 才是 docker 被拋棄后的 CRI 運行時的最佳人選,cri-o適配工作量大。對於開發同學來說整個遷移過程應該是無感知的,只需要修改kubelet的配置--container-shim,將docker換成conntainerd.

 

三、containerd 的今生前世

前面知道了docker運行的原理,k8s通過docker-shim調用docker和直接調用containerd,為什么最開始不直接調用containerd呢?講一下歷史。

2016年,docker 把負責容器生命周期的模塊拆分出來,並將其捐贈給了社區,也就是現在的 containerd。docker拆分后結構如下圖所示(當然 docker 公司還在 docker 中添加了部分編排的代碼)

 

在我們調用docker命令創建容器后,docker daemon 會通過 Image 模塊下載鏡像並保存到 Graph Driver 模塊中,之后通過 client 調用containerd 創建並運行容器。我們在使用 docker 創建容器時可能需要使用--volume給容器添加持久化存儲;還有可能通過--network連接我們用 docker 命令創建的幾個容器,當然,這些功能是 docker 中的 Storage 模塊 Networking 模塊提供給我們的。但 K8s 提供了更強的卷掛載能力和集群級別的網絡能力,在集群中 kubelet 只會使用到 docker 提供的鏡像下載和容器管理功能,而編排、網絡、存儲等功能都不會用到。下圖中可以看出當前的模式下各模塊的調用鏈,同時圖中被紅框標注出的幾個模塊就是 kubelet 創建 Pod 時所依賴的幾個運行時的模塊。

 

containerd 被捐贈給CNCF社區后,社區給其添加了鏡像管理模塊和 CRI 模塊這樣 containerd 不只可以管理容器的生命周期,還可以直接作為 K8s 的運行時使用。於是 containerd 在 2019年2月從 CNCF 社區畢業,正式進入生產環境。下圖中能看出以 containerd 作為容器運行時,可以給 kubelet 帶來創建 Pod 所需的全部功能,同時還得到了更純粹的功能模塊以及更短的調用鏈。

 

從上面的對比可以看出從 containerd 被捐贈給社區開始,就一直以成為簡單、穩定且可靠的容器運行時為目標;而docker則是希望能成為一個完整的產品。官方文檔中也提到了這一點,docker為了給用戶更好的交互和使用體驗以及更多的功能,提供了很多開發人員所需要的特性,同時為了給 swarm 做基礎,提供了網絡和卷的功能。而這些功能其實都是是 K8s 用不上的;containerd 則相反,僅提供了 kubelet 創建 Pod 所需要的基礎功能,當然這換來的就是更高的魯棒性以及更好的性能。在一定程度上講,即使在 kubelet 1.23 版本之后 docker 提供了CRI接口,containerd仍然是更好的選擇。

 

參考:https://www.cnblogs.com/tencent-cloud-native/p/14134164.html 


免責聲明!

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



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