騰訊云:K8s終將廢棄docker,TKE早已支持containerd

來源: 騰訊云原生
作者:李志宇 洪志國
時間:2020-12-14
17102
本文會做詳細解讀,并介紹docker與containerd的關系,以及為什么containerd是更好的選擇。

近日K8s官方稱最早將在1.23版本棄用docker作為容器運行時,并在博客中強調(diào)可以使用如containerd等CRI運行時來代替docker。

本文會做詳細解讀,并介紹docker與containerd的關系,以及為什么containerd是更好的選擇。

這里先回答下TKE用戶關心的問題:我們的集群該怎么辦?

TKE集群該怎么辦

·TKE早在2019年5月就已經(jīng)支持選擇containerd作為容器運行時。如果新建集群,推薦選擇containerd作為容器運行時

·已有集群在升級到K8s 1.23(假定TKE第一個不支持dockershim的K8s版本,也可能是1.24)之前,仍然可以繼續(xù)使用docker作為容器運行時

·已有集群通過TKE集群升級功能升級到1.23時,TKE會提供切換運行時為containerd的選項。當然,這種情況下沒辦法做到Pod不受影響,只能采用重裝節(jié)點的方式來升級

·已有集群也可以將運行時切換為containerd,新增節(jié)點會使用containerd,存量節(jié)點不受影響仍然使用docker(注意:這會造成同一集群中docker節(jié)點與containerd節(jié)點共存,如果·有使用Docker in Docker,或者其他依賴節(jié)點上docker daemon與docker.sock的業(yè)務,需要提前采取措施來避免產(chǎn)生問題,例如通過按節(jié)點標簽調(diào)度,保證這類業(yè)務調(diào)度到docker節(jié)點;或者采用如前文所述在containerd集群運行Docker in Docker的方案)

·當然,在未來docker也有可能在內(nèi)部實現(xiàn)CRI或者添加一個dockershim進程,如果docker做了相應適配,TKE這邊在未來也會進行支持。

解讀K8s棄用dockershim

Docker support in the kubelet is now deprecated and will be removed in a future release.The kubelet uses a module called"dockershim"which implements CRI support for Docker and it has seen maintenance issues in the Kubernetes community.We encourage you to evaluate moving to a container runtime that is a full-fledged implementation of CRI(v1alpha1 or v1 compliant)as they become available.(#94624[1],dims[2])[SIG Node]

K8s在1.20的change log中提到K8s將于1.20版本開始逐步放棄對Docker的支持。在K8s的官方博客中也提到具體的聲明和一些FAQ。

·Don't Panic:Kubernetes and Docker[3]

·Dockershim FAQ[4]

在博客中提到K8s將在1.20版本中添加不推薦使用docker的信息,且最早將于1.23版本中把dockershim從kubelet中移除,屆時用戶將無法使用docker作為K8s集群的運行時,不過通過docker構建的鏡像在沒有docker的K8s集群中依然可以使用。

“寄生”在kubelet中的dockershim

本次改動主要內(nèi)容是準備刪除kubelet中的dockershim,當然這種做法也是符合預期的。

在早期rkt和docker爭霸時,kubelet中需要維護兩坨代碼分別來適配docker和rkt,這使得kubelet每次發(fā)布新功能都需要考慮對運行時組件的適配問題,嚴重拖慢了新版本發(fā)布速度。

另外虛擬化已經(jīng)是一個普遍的需求,如果出現(xiàn)了類型的運行時,SIG-Node小組可能還需要把和新運行時適配的代碼添加到kubelet中。這種做法并不是長久之計,于是在2016年,SIG-Node提出了容器操作接口CRI(Container Runtime Interface)。

CRI是對容器操作的一組抽象,只要每種容器運行時都實現(xiàn)這組接口,kubelet就能通過這組接口來適配所有的運行時。但Docker當時并沒有(也不打算)實現(xiàn)這組接口,kubelet只能在內(nèi)部維護一個稱之為“dockershim”組件,這個組件充當了docker的CRI轉接器,kubelet在創(chuàng)建容器時通過CRI接口調(diào)用dockershim,而dockershim在通過http請求把請求交給docker。

于是kubelet的架構變成下圖這樣:

640.png

在使用實現(xiàn)了CRI接口的組件作為容器運行時的情況下,kubelet創(chuàng)建容器的調(diào)用鏈如圖中紅色箭頭所示,kubelet中的ContainerManager可以直接通過CRI調(diào)用到容器運行時,這過程中只需要一次grpc請求;

而在使用docker時,ContainerManager會走圖中藍色的調(diào)用鏈,CRI的請求通過unix:///var/run/dockershim.sock流向dockershim,dockershim做轉換后把請求轉發(fā)給docker,至于為什么docker后面還有個containerd稍后會講到。

在kubelet中實現(xiàn)docker的轉接器本來就是一種不優(yōu)雅的實現(xiàn),這種做法讓調(diào)用鏈變長且不穩(wěn)定性,還給kubelet的維護添加了額外工作,把這部分內(nèi)容從kubelet刪掉就是時間問題了。

棄用Docker后會有什么不同?

If you’re an end-user of Kubernetes,not a whole lot will be changing for you.This doesn’t mean the death of Docker,and it doesn’t mean you can’t,or shouldn’t,use Docker as a development tool anymore.Docker is still a useful tool for building containers,and the images that result from running docker build can still run in your Kubernetes cluster.

消息一出,大家最關心的事情應該就是棄用docker后到底會產(chǎn)生什么影響?

官方的答復是:Don't Panic!隨后又重點解釋了幾個大家最關心的問題,我們來分析下官方提到的這些方面:

·正常的K8s用戶不會有任何影響

是的,生產(chǎn)環(huán)境中高版本的集群只需要把運行時從docker切換到其他的runtime(如containerd)即可。containerd是docker中的一個底層組件,主要負責維護容器的生命周期,跟隨docker經(jīng)歷了長期考驗。同時2019年初就從CNCF畢業(yè),可以單獨作為容器運行時用在集群中。TKE也早在2019年就已經(jīng)提供了containerd作為運行時選項,因此把runtime從docker轉換到containerd是一個基本無痛的過程。CRI-O是另一個常被提及的運行時組件,由redhat提供,比containerd更加輕量級,不過和docker的區(qū)別較大,可能轉換時會有一些不同之處。

·開發(fā)環(huán)境中通過docker build構建出來的鏡像依然可以在集群中使用

鏡像一直是容器生態(tài)的一大優(yōu)勢,雖然人們總是把鏡像稱之為“docker鏡像”,但鏡像早就成為了一種規(guī)范了。具體規(guī)范可以參考image-spec[5]。在任何地方只要構建出符合Image Spec的鏡像,就可以拿到其他符合Image Spec的容器運行時上運行。

·在Pod中使用DinD(Docker in Docker)的用戶會受到影響

有些使用者會把docker的socket(/run/docker.sock)掛載到Pod中,并在Pod中調(diào)用docker的api構建鏡像或創(chuàng)建編譯容器等,官方在這里的建議是使用Kaniko、Img或Buildah。我們可以通過把docker daemon作為DaemonSet或者給想要使用docker的Pod添加一個docker daemon的sidecar的方式在任意運行時中使用DinD的方案。TKE也專門為在containerd集群中使用DinD提供了方案,詳見在containerd中使用DinD[6]。

containerd的今生前世

所以containerd到底是個啥?和docker又是什么關系?可能有些同學看到博客后會發(fā)出這樣的疑問,接下來就給同學們講解下containerd和docker的淵源。

docker與containerd

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

640.png

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

640 (1).png

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

640 (2).png

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

在Kubernetes集群中使用containerd

當然現(xiàn)在有諸多的CRI實現(xiàn)者,比較主要的除了containerd還有CRI-O。CRI-O是主要由Red Hat員工開發(fā)的CRI運行時,完全和docker沒有關系,因此從docker遷移過來可能會比較困難。無疑containerd才是docker被拋棄后的CRI運行時的最佳人選,對于開發(fā)同學來說整個遷移過程應該是無感知的,不過對于部分運維同學可能會比較在意部署和運行中細節(jié)上的差異。接下來我們重點介紹下在K8s中使用containerd和docker的幾處區(qū)別。

·容器日志對比項

640 (3).png

cni配置方式的區(qū)別在使用docker時,kubelet中的dockershim負責調(diào)用cni插件,而containerd的場景中containerd中內(nèi)置的containerd-cri插件負責調(diào)用cni,因此關于cni的配置文件需要放在containerd的配置文件中(/etc/containerd/containerd.toml):

 [plugins.cri.cni]

      bin_dir = "/opt/cni/bin"

      conf_dir = "/etc/cni/net.d"

·stream服務的區(qū)別

說明:

Kubectl exec/logs等命令需要在apiserver跟容器運行時之間建立流轉發(fā)通道。

如何在containerd中使用并配置Stream服務?

Docker API本身提供stream服務,kubelet內(nèi)部的docker-shim會通過docker API做流轉發(fā)。而containerd的stream服務需要單獨配置:

[plugins.cri]

stream_server_address="127.0.0.1"

stream_server_port="0"

enable_tls_streaming=false[plugins.cri]stream_server_address="127.0.0.1"stream_server_port="0"enable_tls_streaming=false

K8s 1.11前后版本配置區(qū)別是什么?

containerd的stream服務在K8s不同版本運行時場景下配置不同。

·在K8s 1.11之前:kubelet不會做stream proxy,只會做重定向。即kubelet會將containerd暴露的stream server地址發(fā)送給apiserver,并讓apiserver直接訪問containerd的stream服務。此時,您需要給stream服務轉發(fā)器認證,用于安全防護。

·在K8s 1.11之后:K8s1.11引入了kubelet stream proxy[7],使containerd stream服務只需要監(jiān)聽本地地址即可。

在TKE集群中使用containerd

從2019年5月份開始,TKE就開始支持把containerd作為容器運行時選項之一。隨著TKE逐步在containerd集群中支持日志收集服務和GPU能力,2020年9月份containerd在TKE也摘掉了Beta版本的標簽,可以正式用于生產(chǎn)環(huán)境中了。在長期使用中,我們也發(fā)現(xiàn)了一些containerd的問題并且及時進行了修復,如:

·由于錯誤處理問題導致的Pod Terminating

·由于內(nèi)核版本問題導致鏡像文件丟失

想要在TKE集群中使用containerd作為運行時有三種方式:

1.在創(chuàng)建集群時,選擇1.12.4及以上版本的K8s后,選擇containerd為運行時組件即可

640 (4).png

2.在已有docker集群中,通過創(chuàng)建運行時為containerd的節(jié)點池來創(chuàng)建一部分containerd節(jié)點(新建節(jié)點池>更多設置>運行時組件)

640 (5).png

3.在已有docker集群中,修改集群或者節(jié)點池的"運行時組件"屬性為"containerd"

640 (6).png

注意:后兩種方式會造成同一集群中docker節(jié)點與containerd節(jié)點共存,如果有使用Docker in Docker,或者其他依賴節(jié)點上docker daemon與docker.sock的業(yè)務,需要提前采取措施來避免產(chǎn)生問題,例如通過按節(jié)點標簽調(diào)度,保證這類業(yè)務調(diào)度到docker節(jié)點;或者采用如前文所述在containerd集群運行Docker in Docker的方案。

現(xiàn)階段關于containerd和docker選擇問題可以查看文檔如何選擇Containerd和Docker[8]。

參考資料

[1]#94624:https://github.com/kubernetes/kubernetes/pull/94624

[2]dims:https://github.com/dims

[3]Don't Panic:Kubernetes and Docker:https://kubernetes.io/blog/2020/12/02/dont-panic-kubernetes-and-docker/

[4]Dockershim FAQ:https://kubernetes.io/blog/2020/12/02/dockershim-faq/

[5]image-spec:https://github.com/opencontainers/image-spec

[6]在containerd中使用DinD:https://tencentcloudcontainerteam.github.io/2020/12/08/dind-in-containerd/

[7]kubelet stream proxy:https://github.com/kubernetes/kubernetes/pull/64006

[8]如何選擇Containerd和Docker:https://cloud.tencent.com/document/product/457/35747

[9]Dockershim Removal Kubernetes Enhancement Proposal:https://github.com/kubernetes/enhancements/tree/master/keps/sig-node/1985-remove-dockershim

[10]kubernetes CHANGELOG-1.20:https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.20.md#deprecation

立即登錄,閱讀全文
版權說明:
本文內(nèi)容來自于騰訊云原生,本站不擁有所有權,不承擔相關法律責任。文章內(nèi)容系作者個人觀點,不代表快出海對觀點贊同或支持。如有侵權,請聯(lián)系管理員(zzx@kchuhai.com)刪除!
掃碼登錄
打開掃一掃, 關注公眾號后即可登錄/注冊
加載中
二維碼已失效 請重試
刷新
賬號登錄/注冊
個人VIP
小程序
快出海小程序
公眾號
快出海公眾號
商務合作
商務合作
投稿采訪
投稿采訪
出海管家
出海管家