很多人在實(shí)際工作中都使用過Kubernetes,騰訊云的容器服務(wù)在2016年年底開始提供全托管的Kubernetes服務(wù),主要提供了四個(gè)方面的功能。首先是提供了一鍵部署的Kubernetes,與其他容器服務(wù)的提供商不一樣,騰訊云的Kubernetes是完全隔離的,每個(gè)用戶都會(huì)獨(dú)享所有的計(jì)算節(jié)點(diǎn)和控制節(jié)點(diǎn),集群網(wǎng)絡(luò)也在用戶自己的VPC中。騰訊云在這個(gè)基礎(chǔ)上提供了集群的全生命周期管理,包括集群的創(chuàng)建、銷毀,還有計(jì)算節(jié)點(diǎn)的添加、刪除,還有一些類似Kubernetes原有組件的初始化以及證書的初始化工作。為了大家更方便地使用Kubernetes,騰訊云在控制臺(tái)包裝了一些界面,使大家可以通過可視化的方式創(chuàng)建一些負(fù)載來暴露自己的服務(wù),避免了大家手工編碼的煩瑣。第三,騰訊云提供了周邊的監(jiān)控能力,包括集群本身pod內(nèi)存的使用率以及一些Kubernetes事件。這些能力都與騰訊云的云監(jiān)控產(chǎn)品進(jìn)行了打通,大家可以直接在云監(jiān)控產(chǎn)品界面使用這些能力。為了方便大家將自己的一些比較傳統(tǒng)的應(yīng)用部署到云上,騰訊云在Kubernetes集群之外還提供了Docker鏡像倉庫、TencentHub、CICD的功能,為大家提供了一站式應(yīng)用的云解決方案。
今天所提到的內(nèi)容,一方面是介紹Kubernetes相關(guān)的知識(shí),另一方面是介紹如何將Kubernetes和騰訊云進(jìn)行集成。首先帶大家了解一下Kubernetes集群需要哪些組件,將Kubernetes部署好之后還要做什么工作使它正常運(yùn)行。之后會(huì)介紹云上Kubernetes上的網(wǎng)絡(luò)存儲(chǔ)和日志與監(jiān)控,這是將Kubernetes和騰訊云集成時(shí)進(jìn)行的工作。最后介紹Kubernetes的兩種部署方案,一種是容器服務(wù)產(chǎn)品發(fā)展早期所采用的一種基于CVM的方案,另一種是最近逐漸部署的使用Kubernetes集群來管理Kubernetes集群組件的方案。隨著容器服務(wù)產(chǎn)品以及Kubernetes社區(qū)的發(fā)展,在騰訊云提供托管的CCS服務(wù)通過了CNCF的K8s一致性驗(yàn)證之后,為了大家更好地認(rèn)知騰訊的容器服務(wù)產(chǎn)品,產(chǎn)品的名字從之前的CCS正式改名為TKE。
Kubernetes 組件
接下來看一下想要讓Kubernetes集群運(yùn)行起來我們要做哪些工作。如果對(duì)Kubernetes有了解的同學(xué),可能知道使Kubernetes跑起來,無非是初始化一些Master組件和Node組件。首先給大家介紹Master組件,一個(gè)最簡單的部署要包括Kube-apiserver、Kube-controller-mannager 、kube-scheduler這些組件。Kube-apiserver可以理解為整個(gè)集群的大腦或者是集中存儲(chǔ),所有組件與k8s的交互都是通過Kube-apiserver來完成的。其中存儲(chǔ)著我們定義的一些工作負(fù)載以及我們對(duì)于存儲(chǔ)的一些需求,這些數(shù)據(jù)都存儲(chǔ)在Kube-apiserver中。
第二個(gè)組件Kube-controller-mannager主要負(fù)責(zé)將聲明的一些工作負(fù)載在實(shí)際的集群中運(yùn)行起來,舉個(gè)最簡單的例子,當(dāng)我們在Kubernetes上創(chuàng)建了一個(gè)deployment之后,Kube-controller-mannager就會(huì)去創(chuàng)建相應(yīng)的replicaset、pod這些。根據(jù)需求將pod創(chuàng)建出來,在創(chuàng)建pod后,Kube-scheduler負(fù)責(zé)對(duì)這些pod進(jìn)行調(diào)度,比如這個(gè)pod實(shí)際應(yīng)該被運(yùn)行在哪臺(tái)機(jī)器,比如GPU的結(jié)點(diǎn)做這樣的調(diào)度工作。當(dāng)一個(gè)集群的Master組件被完全部署好之后,我們會(huì)部署一些Node。在它的上面部署兩個(gè)組件,一個(gè)是kubelet,負(fù)責(zé)在這些Node上創(chuàng)建出來我們需要的pod。另一個(gè)是kube-proxy,它在集群中負(fù)責(zé)的工作是:當(dāng)一個(gè)deployment需要以服務(wù)的形式對(duì)外暴露的時(shí)候,Kude-proxy會(huì)負(fù)責(zé)配置這些iptables規(guī)則,讓集群內(nèi)不管是宿主機(jī)上的程序還是容器里的程序,都能夠按照service的名字去做一個(gè)自動(dòng)的發(fā)現(xiàn)和訪問。
在Kubernetes這些標(biāo)準(zhǔn)化的組件之外,騰訊云還提供了額外的組件。主要給大家介紹一下以下三個(gè),一個(gè)是hpa-metrics-server,它是騰訊云為了使用Kubernetes提供本身的pod橫向擴(kuò)展控制器而去自研的一個(gè)組件,這個(gè)組件相比于Kubernetes社區(qū)方案的優(yōu)點(diǎn),是Kubernetes社區(qū)方案只提供了基于CPU和內(nèi)存的擴(kuò)展,而騰訊云在這個(gè)基礎(chǔ)上更加拓展了Pod的入帶寬和出帶寬的指標(biāo),方便大家去適應(yīng)更多的擴(kuò)縮容場景。第二個(gè)組件是cbs-provisioner,這個(gè)組件提供了去讓Kubernetes里面的pod去消費(fèi)騰訊云一個(gè)叫做Cbs塊存儲(chǔ)服務(wù),我們后面會(huì)詳細(xì)講到。第三是Ccs-log-collector,這個(gè)組件主要是負(fù)責(zé)收集容器里pod運(yùn)行的日志,后面也會(huì)講到。
容器網(wǎng)絡(luò)
當(dāng)我們把Kubernetes和騰訊云進(jìn)行集成的時(shí)候,網(wǎng)絡(luò)方案是怎么做的呢?在你將一些控制組件搭建起來之后,Kubernetes對(duì)于網(wǎng)絡(luò)提出了三點(diǎn)的要求。第一是在不使用NAT的情況下,集群內(nèi)所有容器都可以和其他的容器進(jìn)行通訊。第二是所有的節(jié)點(diǎn)都可以和所有的容器進(jìn)行通信,反向也可以通信,同樣要求不能使用NAT。第三是容器看到的自己的IP與其他人看到的IP是一樣的。
總的來說,它實(shí)現(xiàn)了Node和container之間的扁平化網(wǎng)絡(luò)。同時(shí)為了應(yīng)對(duì)服務(wù)發(fā)現(xiàn)的需求,降低網(wǎng)絡(luò)復(fù)雜度,還要求不能使用NAT。Kubernetes并沒有內(nèi)置的網(wǎng)絡(luò)解決方案,所以在社區(qū)其實(shí)有很多不同的解決方案,例如flannel,它是通過Tun/tap設(shè)備,再通過內(nèi)核用戶態(tài)的轉(zhuǎn)化程序,實(shí)現(xiàn)一個(gè)類似于overlay的網(wǎng)絡(luò)能力。Callco不需要進(jìn)行overlay封裝,直接通過路由的方案可以完成Kubernetes的網(wǎng)絡(luò)需求。
接下來為大家介紹一下騰訊云Kubernetes使用的方案,騰訊云的網(wǎng)絡(luò)方案主要是直接使用了VPC提供的路由能力,叫做global route。簡單介紹一下Kubernetes結(jié)點(diǎn)加入到一個(gè)集群中配置網(wǎng)絡(luò)的過程,當(dāng)我們將一個(gè)結(jié)點(diǎn)加到集群中的時(shí)候,K8s的Kube-controller-manager會(huì)為這個(gè)結(jié)點(diǎn)分配一個(gè)網(wǎng)端。例如,集群網(wǎng)絡(luò)是172.16.1.0/16掩碼,這時(shí)加進(jìn)去一個(gè)結(jié)點(diǎn)。按照我們的邏輯,我們會(huì)給它賦172.16.1.0/24位掩碼的CIDR。也就是所有在這個(gè)主機(jī)上創(chuàng)建的pod,它的ID都在這個(gè)CIDR的范圍內(nèi)。然后我們會(huì)去VPC那里做一個(gè)動(dòng)作,將172.16.1.0/24掩碼到目的地址的流量去注冊一條路由規(guī)則,使所有的包都發(fā)往被賦予這個(gè)pod CIDR的主機(jī)。這樣我們就可以完成之前提到的pod和Node之間的扁平化網(wǎng)絡(luò)。具體過程如下:假設(shè)現(xiàn)在有一個(gè)位于172.16.1.0/24網(wǎng)端機(jī)上的pod,向另一個(gè)機(jī)器的pod發(fā)送了這樣一個(gè)包,這個(gè)包首先從容器出來,到cbr0 bridge然后出了主機(jī)。這時(shí)就會(huì)進(jìn)入VPC的路由表進(jìn)行匹配,當(dāng)它發(fā)現(xiàn)這個(gè)pod的目的IP在172.16.2.0/24時(shí),這個(gè)包就會(huì)被VPC轉(zhuǎn)發(fā)到10.1.1.3,這樣我們就可以完成一個(gè)pod的跨主機(jī)通信。pod在本地的通信比較簡單,這里就不多講了。通過這種方式,我們實(shí)現(xiàn)了一個(gè)pod和Node之間的扁平化網(wǎng)絡(luò),這里Docker的網(wǎng)絡(luò)模式是用的bridge模式,pod IP直接由cni插件進(jìn)行分配。
容器存儲(chǔ)
接下來給大家介紹騰訊云的K8s和騰訊云容器集成的實(shí)現(xiàn)。K8s集群集成了騰訊云的CBS和CFS兩個(gè)能力,一個(gè)是塊存儲(chǔ),一個(gè)是基于NFS的文件系統(tǒng)存儲(chǔ)。當(dāng)我們在一個(gè)pod中聲明需要一個(gè)volume時(shí),K8s如何將volume最終掛載到pod里面?其實(shí)是這樣一個(gè)過程:首先,Kube-controller-manager會(huì)去provisnon這樣一個(gè)volume。也就是說,實(shí)際去創(chuàng)建一個(gè)云盤,當(dāng)云盤創(chuàng)建好之后會(huì)做一個(gè)Attach的動(dòng)作,相當(dāng)于把剛剛創(chuàng)建好的云盤插到對(duì)應(yīng)主機(jī)上,這時(shí),主機(jī)上的Kubelet會(huì)做一個(gè)mount動(dòng)作,也就是將插進(jìn)來的這個(gè)設(shè)備去mount到一個(gè)Kubernetes指定的目錄,Kubelet在創(chuàng)建這個(gè)pod的時(shí)候,通過mount的形式把mount到的目錄實(shí)際掛載到容器的namespace里面。然后當(dāng)我們這個(gè)pod銷毀,這個(gè)volume不再被需要的時(shí)候,它就反向去執(zhí)行,先從主機(jī)上把對(duì)應(yīng)的塊設(shè)備先mount掉,再將它detach掉,相當(dāng)于把這塊磁盤從主機(jī)上拔下來,然后會(huì)由Kube-controller-manager根據(jù)對(duì)應(yīng)的plugin設(shè)置銷毀或者是保留。
K8s目前通過與cloud provider進(jìn)行volume集成的方面主要是三種。一種是比較早期,所有要和kubernetes進(jìn)行集成的Volume代碼都需要寫在kubernetes自己的代碼倉庫中。這樣的缺點(diǎn)在于,假設(shè)我是一個(gè)存儲(chǔ)提供商,我寫的代碼有些bug,這樣不僅影響存儲(chǔ)功能的正常使用,可能也會(huì)影響整個(gè)集群的穩(wěn)定性。所以后來為了更好的擴(kuò)展性和穩(wěn)定性,Kubernetes提供了一種叫做Flex volume的形式。具體是將mount和umount這兩個(gè)形式由Flex volume實(shí)現(xiàn),F(xiàn)lex volume是一個(gè)實(shí)現(xiàn)了特定接口的二進(jìn)制文件,實(shí)際上在需要mount、amount的時(shí)候,Kubelet會(huì)執(zhí)行這個(gè)二進(jìn)制文件,做一個(gè)mount、umount的動(dòng)作。
這種方式其實(shí)也有一個(gè)問題,在kubernetes的部署環(huán)境中,如果要往主機(jī)上放一個(gè)二進(jìn)制的動(dòng)作,看起來不是那么的容器化。另外二進(jìn)制文件執(zhí)行的環(huán)境也有一定的要求,所以后來Kubernetes提供了第三種方式,也就是利用社區(qū)的CSI接口實(shí)現(xiàn)了基于CSI的插件。之前由Flex volume這個(gè)二進(jìn)制文件完成的工作全部放到了容器里面,然后通過unix socket的形式,使Kubelet和實(shí)現(xiàn)對(duì)應(yīng)功能的插件做一個(gè)通信,最后一個(gè)mount、umount的動(dòng)作。現(xiàn)在也與騰訊云的CBS塊存儲(chǔ)做了集成,使用第一種方式,這是因?yàn)轵v訊云在早期使用的就是這種方式。后期騰訊云也會(huì)將這部分獨(dú)立出來,計(jì)劃通過CSI的方式去提供存儲(chǔ)的能力。這部分代碼騰訊云將會(huì)開源,但目前這個(gè)工作還正在進(jìn)行中。
接下來為大家介紹一下日志和監(jiān)控的方案,首先介紹一下日志的方案。在K8s中沒有提供默認(rèn)的日志方案,Kubernetes社區(qū)提供的這種方式可以運(yùn)行一個(gè)sidecar容器,在你自己的容器中運(yùn)行一個(gè)這樣的進(jìn)程并將它輸出到標(biāo)準(zhǔn)輸出,然后再用你的sidecar容器做一個(gè)收集。這樣的問題在于,每跑一個(gè)pod,就要跑一個(gè)類似的sidecar容器,對(duì)于資源的消耗不太可以接受。騰訊容器服務(wù)基于Fluentd+Kubernetes custom resource definition,實(shí)現(xiàn)了日志收集的控制器。這個(gè)控制器可以支持收集容器的標(biāo)準(zhǔn)輸出,也可以支持收集我的pod所在的Node上主機(jī)上文件路徑的文件內(nèi)容。
主要的實(shí)現(xiàn)原理是:騰訊云會(huì)在kube-apiserver上注冊一個(gè)LogCollector的custom resource definition,里面聲明了自己要收集namespaces下面某一個(gè)deployment對(duì)應(yīng)的pod資源。還有另外一個(gè)進(jìn)程就是LogCollector,去監(jiān)聽Kubernetes apiserver資源,然后去生成對(duì)應(yīng)的Fluentd的配置文件,再通過sighup信號(hào)的形式去觸發(fā)Fluentd的重載,然后去收集我們想要的日志文件。因?yàn)镵ubernetes pod對(duì)應(yīng)的日志文件是存儲(chǔ)在主機(jī)的/var/log/containers的路徑規(guī)則下來,直接配置Fluentd去收集這個(gè)規(guī)則,再根據(jù)我們的實(shí)際需要做一個(gè)日志的路由。這樣就可以把不同的日志發(fā)往用戶指定的不同后端,比如Kafka或騰訊云的CIS的日志服務(wù)。這是騰訊云目前對(duì)于日志收集的方案實(shí)現(xiàn)。
在監(jiān)控方面,騰訊云將Kubernetes中pod的性能信息和云監(jiān)控做了對(duì)接,主要的實(shí)現(xiàn)方法是在用戶的每臺(tái)kubernete結(jié)點(diǎn)上運(yùn)行一個(gè)agent,這個(gè)agent在kubelet中內(nèi)置的cadvisor收集pod運(yùn)行的性能信息,然后再到apiserver獲取這些pod對(duì)應(yīng)的元數(shù)據(jù)。騰訊云將這些性能信息和元數(shù)據(jù)進(jìn)行打包,再將它上傳到監(jiān)控服務(wù)上。另外,基于騰訊云存儲(chǔ)的監(jiān)控指標(biāo),實(shí)現(xiàn)了hpa-metrics-server。Kubernetes提供的HPA能力,是它在kube-controller-manager里面實(shí)現(xiàn)了horizontal pod autoscaler,它會(huì)定期請(qǐng)求hpa metrics server去獲取這個(gè)pod目前的CPU Usage或者是入帶寬、出帶寬這些指標(biāo)的數(shù)量,根據(jù)騰訊云的定義,比如當(dāng)CPU使用率超過80%的時(shí)候,騰訊云要去進(jìn)行擴(kuò)容。它也會(huì)定期拉取數(shù)據(jù),比對(duì)當(dāng)前的pod負(fù)載,直接去修改deployment中的replica字段,實(shí)現(xiàn)自動(dòng)擴(kuò)縮容。目前日志和監(jiān)控的方案,是將Kubernetes和騰訊云的基礎(chǔ)設(shè)施進(jìn)行對(duì)接時(shí)候所需要做的一部分工作,也是騰訊云的主要工作。
下面介紹一下騰訊早期在騰訊云上的部署方案。當(dāng)時(shí)為了產(chǎn)品能夠快速上線,也為了滿足一個(gè)完全的隔離的全托管的Kubernetes服務(wù),騰訊云直接把Kubernetes的Master組件部署在了一臺(tái)CVM上面。同時(shí),為了實(shí)現(xiàn)隔離的方式,騰訊云將Master放到用戶的VPC中。在Master組件上運(yùn)行了一些標(biāo)準(zhǔn)化的Kubernetes組件,用戶的Node結(jié)點(diǎn)以用戶的身份直接在CVM那邊購買機(jī)器,騰訊云在這個(gè)基礎(chǔ)上做一些kubelet或者kube proxy參數(shù)數(shù)值化的工作。此外,騰訊云會(huì)做一些集群的證書配置、默認(rèn)拉取鏡像的憑證初始化工作。在這個(gè)方案中,騰訊云所有的節(jié)點(diǎn)都處于用戶的VPC里面,通過Agent初始化的方式將整個(gè)集群部署起來。缺點(diǎn)在于難以管理,因?yàn)轵v訊云早期是通過SSH直接登錄到客戶的Master結(jié)點(diǎn)上進(jìn)行一些運(yùn)維操作,對(duì)于客戶的Node結(jié)點(diǎn)是沒有辦法訪問的。當(dāng)然,現(xiàn)在也沒有辦法訪問。對(duì)于Master的一些運(yùn)維工作比較困難,因?yàn)樗鼪]有辦法去編程化。
雖然騰訊云自己提供的是Kubernetes的服務(wù),但對(duì)于整個(gè)容器的運(yùn)維好像和Kubernetes完全沒有關(guān)系。在Master上一些組件的監(jiān)控并不是用我們之前提到的方式來實(shí)現(xiàn)的,是通過內(nèi)部的監(jiān)控組件來收集。這與我們之前提到的用戶Node組件信息收集方式不太一樣,相當(dāng)于兩種方式并行在跑,人力消耗也比較大。之前騰訊云的ETCD是共享的,也就是每個(gè)集群都在ETCD中有一個(gè)自己的目錄,相當(dāng)于一個(gè)軟隔離,沒有一個(gè)硬隔離的措施。大家知道ETCD其實(shí)并不是為了海量數(shù)據(jù)存儲(chǔ)而服務(wù)的,而騰訊云在線上運(yùn)行了數(shù)萬個(gè)集群,導(dǎo)致遇到了很多和ETCD有關(guān)的問題。在這樣的大背景下,騰訊云推出了第二種方案,也就是將Kubernetes部署在Kubernetes里面,通過Kubernetes API去管理Master組件,包括我們剛才提到的apiserver、kube-controller-manager和一些自研的組件。這樣的好處在于,騰訊云不需要再通過SSH的方式,比如當(dāng)騰訊云需要做一個(gè)apiserver的升級(jí)或kube-controller-manager的bug修復(fù)的情況,不需要再通過SSH的方式去每臺(tái)機(jī)器上進(jìn)行操作,可以直接通過API Kubernetes提供的deployment的滾動(dòng)升級(jí)的能力來完成這一點(diǎn)。
也可以充分利用Kubernetes運(yùn)維的能力,包括健康檢查和就緒檢查的機(jī)制實(shí)現(xiàn)故障自愈。基于之前提到的hpa-metrics-server,可以實(shí)現(xiàn)apiserver的動(dòng)態(tài)擴(kuò)容,應(yīng)對(duì)用戶的集群結(jié)點(diǎn)有一個(gè)大規(guī)模的上升或者突然下降的情況,更好地滿足Kubernetes集群里面的結(jié)點(diǎn)對(duì)于apiserver性能的需求。在這個(gè)基礎(chǔ)上,還需要解決一個(gè)問題:之前基于CVM的部署方案是將所有的組件部署在用戶的VPC里面,如果將所有組件部署在kubernetes Master中又要怎么做呢?并不能給每個(gè)用戶部署一個(gè)Kubernetes集群,然后再跑它的Master,這樣聽起來好像和第一種方案沒有什么區(qū)別。所以又提供了一個(gè)專門的Kubernetes集群,在這個(gè)集群里面運(yùn)行著現(xiàn)在線網(wǎng)所有集群的Master,這個(gè)集群運(yùn)行在自己的VPC里面,它又要怎么和用戶的VPC結(jié)點(diǎn)進(jìn)行通信呢?騰訊云利用了VPC提供的彈性網(wǎng)卡能力,這個(gè)彈性網(wǎng)卡會(huì)被直接綁定到運(yùn)行apiserver的pod中。大家可以理解為這個(gè)pod既加入了用來運(yùn)行Master組件集群的VPC,又加入了用戶的VPC,也就是一個(gè)pod同時(shí)在兩個(gè)網(wǎng)絡(luò)中,這樣就可以很好的去實(shí)現(xiàn)和用戶Node相關(guān)的互通。另外在這個(gè)基礎(chǔ)上,也可以復(fù)用之前提到的一些監(jiān)控和日志設(shè)施,更好地去做信息的收集和運(yùn)維。
值得提到的一點(diǎn)是,這個(gè)方案中,可以利用一個(gè)叫做Etcd operator的組件,也就是coreos其中的一個(gè)組件來為每個(gè)集群提供獨(dú)立的Etcd的部署,這樣就可以解決在集群數(shù)量不斷上升的情況下Etcd性能吃緊的問題。通過在Kubernetes集群里面部署Kubernetes Master組件,降低了運(yùn)維的成本。同時(shí)也統(tǒng)一了做運(yùn)維工作的方式,騰訊云都是通過Kubernetes的方式進(jìn)行運(yùn)維的。有效降低了Master組件的資源消耗,因?yàn)橹癕aster組件是免費(fèi)提供給客戶的,但有些客戶的集群規(guī)模非常大,Master配置也非常高,這時(shí)集群的Master存在資源浪費(fèi)的情況。
掃一掃在手機(jī)上閱讀本文章