微博K8S實(shí)戰(zhàn):如何應(yīng)對(duì)春晚等突發(fā)峰值流量?
本文通過圍繞微博業(yè)務(wù)需求和大家分享如何使用 Kubernetes 來解決具體的業(yè)務(wù)問題和相應(yīng)的解決方案。
文中分享了基于 Kubernetes 的 PaaS 層彈性混合部署方案,其中有 Kubernetes 的優(yōu)點(diǎn),也有部分 Kubernetes 在企業(yè)落地的缺陷,希望本文對(duì)大家有一定的借鑒意義。
微博容器平臺(tái)簡(jiǎn)介
2016 年微博平臺(tái)實(shí)現(xiàn)基于混合云的彈性平臺(tái) DCP,提升了 Feed、手機(jī)微博、廣告、搜索、話題、視頻、直播等多個(gè)核心業(yè)務(wù)熱點(diǎn)應(yīng)對(duì)能力。
2017 年微博平臺(tái)率先探索基于 Kubernetes 的 PaaS 層彈性混合部署解決方案,并且積極的和社區(qū)保持同步。
2018 年實(shí)現(xiàn) CI/CD 與生產(chǎn)環(huán)境混合部署,2019 年春晚實(shí)現(xiàn)部分核心業(yè)務(wù)混合部署與彈性伸縮。
本文主要介紹微博平臺(tái)落地 Kubernetes 過程中的一些經(jīng)驗(yàn)教訓(xùn)。
為什么選擇 Kubernetes
因?yàn)闅v史原因,微博 Docker 容器治理是采用獨(dú)占物理機(jī)(虛擬機(jī))模式,直接使用物理機(jī)的網(wǎng)絡(luò)協(xié)議棧,服務(wù)治理采用服務(wù)池方式。
隨著設(shè)備計(jì)算能力的提升,這種治理方式有幾個(gè)問題急需解決:
- 利用率問題:一個(gè)服務(wù)池內(nèi)新、老設(shè)備共存,因?yàn)闃I(yè)務(wù)容器需要兼容老設(shè)備規(guī)格,導(dǎo)致服務(wù)無法充分發(fā)揮出新設(shè)備應(yīng)有的計(jì)算能力。
- 容器網(wǎng)絡(luò)問題:因?yàn)橹苯硬捎梦锢頇C(jī)網(wǎng)絡(luò)棧,導(dǎo)致業(yè)務(wù)混合部署只能采用調(diào)整業(yè)務(wù)監(jiān)聽端口的方式,造成接入成本、管理成本高。
- 調(diào)度治理問題:因?yàn)槟J(rèn)采用獨(dú)占策略,服務(wù)池之間資源相互隔離,不同類型的業(yè)務(wù)類型無法共享資源,導(dǎo)致資源總是相對(duì)緊缺。
Kubernetes 提供標(biāo)準(zhǔn)化的容器管理,CNI 網(wǎng)絡(luò)虛擬化,自定義彈性調(diào)度策略,能夠很好的解決上述問題。
但是 Kubernetes 面向公有 PaaS 的實(shí)現(xiàn)方案在內(nèi)網(wǎng)環(huán)境下有些方面不適用,主要有如下幾個(gè)方面:
- 網(wǎng)絡(luò)虛擬化:在 BGP 的虛擬網(wǎng)絡(luò)方案和隧道的虛擬網(wǎng)絡(luò)方案中都會(huì)引入 iptables 來完成流量牽引,和防火墻的相關(guān)功能。
在企業(yè)內(nèi)網(wǎng)使用的過程中并沒有很強(qiáng)烈的防火墻需求,引入 iptables 往往會(huì)造成性能下降(nf_conntrack 表被打滿,NAT 性能太低)。
所以微博平臺(tái)現(xiàn)階段沒有使用 BGP 虛擬化網(wǎng)絡(luò)方案和隧道虛擬化網(wǎng)絡(luò)方案。
- 滾動(dòng)發(fā)布:目前的 Kubernetes 的滾動(dòng)發(fā)布(Deployment)不支持 In-place rolling updates ,每次一個(gè) Pod 都有可能被分配不同的 IP 地址。
在企業(yè)內(nèi)部使用容器的時(shí)候,固定 IP 的需求往往很強(qiáng)烈,所以我們拋棄了 Kubernetes 而選擇了整合了公司內(nèi)部的滾動(dòng)發(fā)布系統(tǒng)。
- 資源隔離:原生的內(nèi)存隔離策略中不支持 Swap 的限制,容器會(huì)占用物理機(jī)的 Swap,我們修改了內(nèi)存隔離限制。
- 負(fù)載均衡:原生的 Service 模式會(huì)引入 iptables 來做 NAT,同時(shí) Service 的負(fù)載是硬負(fù)載,沒法調(diào)整流量權(quán)重。
我們基于 Kubernetes 搭建了一套 PaaS 平臺(tái),對(duì) Kubernetes 進(jìn)行了改進(jìn),提供了以下功能:
- 網(wǎng)絡(luò)虛擬化:基于 CNI,提供了隔離內(nèi)網(wǎng)和公有云網(wǎng)絡(luò)差異的虛擬化網(wǎng)絡(luò)方案。
- 調(diào)度管理:基于 kube-scheduler,提供了鎖定 IP 的調(diào)度系統(tǒng),該系統(tǒng)支持帶寬初篩,硬盤初篩,機(jī)房就近調(diào)度,返回庫存狀態(tài),提前鎖定 IP 功能等功能。
- CI/CD:一鍵發(fā)布代碼,替代 Kubernetes 的 Deployment 進(jìn)行滾動(dòng)發(fā)布。
- 資源隔離:在原有的隔離策略上,擴(kuò)展出計(jì)算資源隔離,網(wǎng)絡(luò)資源隔離,存儲(chǔ)資源隔離。
- 負(fù)載均衡:整合已有的調(diào)度系統(tǒng),利用微服務(wù)快速部署+彈性調(diào)度提前鎖定 IP,減少服務(wù)抖動(dòng)耗時(shí)。
- 模塊化運(yùn)維:把已有的物理機(jī)運(yùn)維工具整合到容器中,在 Pod 里面共享存儲(chǔ),共享網(wǎng)絡(luò)。
- 彈性擴(kuò)縮容:通過對(duì) DCP 的整合,使其具有了容器彈性擴(kuò)縮容的功能。
- 監(jiān)控:通過模塊化的運(yùn)維體系,整合了監(jiān)控所需日志,無縫連接已有功能。
圖一
整體方案如圖一,微博容器平臺(tái)劃分出如下幾層:
- 服務(wù)層:平臺(tái)的主要入口提供容器擴(kuò)縮容、上下線、維護(hù)服務(wù)池、負(fù)載均衡,監(jiān)控管理等功能。
- PaaS 層:提供容器管理和調(diào)度管理等相關(guān)功能,負(fù)責(zé)將服務(wù)層的請(qǐng)求轉(zhuǎn)化成對(duì)應(yīng)容器的操作。
- IaaS 層:提高機(jī)器資源、網(wǎng)絡(luò)資源、存儲(chǔ)資源供 PaaS 生成的容器使用,負(fù)責(zé)對(duì)容器使用資源進(jìn)行管理。
容器彈性化擴(kuò)縮容平臺(tái)建設(shè)
微博容器彈性擴(kuò)縮容平臺(tái),是在 Kubernetes 基礎(chǔ)上進(jìn)行了改進(jìn),充分利用了微博平臺(tái)已有的資源,避免重復(fù)造輪子。具體的工作如下:
基礎(chǔ)建設(shè)之網(wǎng)絡(luò)虛擬化
之前已經(jīng)說過了,微博的容器會(huì)獨(dú)占物理機(jī)的網(wǎng)絡(luò)協(xié)議棧,雖然能夠大幅度提升網(wǎng)絡(luò)效率,但是會(huì)導(dǎo)致多容器部署時(shí)出現(xiàn)端口沖突。
為了解決端口沖突需要使用虛擬化網(wǎng)絡(luò)技術(shù)提供容器獨(dú)立的 IP 地址。多個(gè)容器獨(dú)立 IP 需要解決以下的三個(gè)問題:
- 容器的 IP 地址分配問題。
- 容器的 IP 路由問題。
- 虛擬化網(wǎng)絡(luò)對(duì)網(wǎng)絡(luò)的性能損失要最小化。
因?yàn)椴捎?Kubernetes IP 分配都是通過記錄在 etcd 中,所以不會(huì)出現(xiàn)分配重復(fù)或者分配錯(cuò)誤的問題,而第二個(gè)問題社區(qū)里面通常會(huì)采用隧道類型方案和 BGP 方案。
以下是隧道模式和 BGP 模式的優(yōu)缺點(diǎn)對(duì)比如表一, 性能測(cè)試如表二(BGP 主要工作是路由交換,轉(zhuǎn)發(fā)等不受影響,等同于物理機(jī)性能。)
表一
表二
在測(cè)試結(jié)果中顯示 vxlan 因?yàn)樾枰庋b和解封隧道導(dǎo)致帶寬損耗過 5%,所以隧道方案不適用于內(nèi)網(wǎng)的網(wǎng)絡(luò)環(huán)境。
而 BGP 的方案 Calico 會(huì)引入 Iptables 去做 ACL,不僅在業(yè)務(wù)峰值流量的情況下會(huì)觸發(fā) nf_conntrack 表被打滿丟包的風(fēng)險(xiǎn)。
而且 BGP 方案在公有云和內(nèi)網(wǎng)落地的時(shí)候也存在問題:
- 公有云方面:從公有云虛擬機(jī)發(fā)出的報(bào)文必須是 Mac 地址和 IP 地址匹配的,所以導(dǎo)致在公有云機(jī)器上 BGP 虛擬網(wǎng)絡(luò)的容器根本無法通信。
- 內(nèi)網(wǎng)方面:內(nèi)網(wǎng)機(jī)器的上聯(lián)交換機(jī)上做了 Vlan 和 IP 的綁定,如果在內(nèi)網(wǎng)機(jī)器上起了一個(gè)其他網(wǎng)段的 IP 地址,報(bào)文發(fā)送不出本機(jī)。
接下來先來看看在網(wǎng)絡(luò)方案上我們做的一些工作,見圖二:
圖二
微博虛擬網(wǎng)絡(luò)主要是四方面內(nèi)容:
- 對(duì)機(jī)房網(wǎng)絡(luò)進(jìn)行改造,修改機(jī)器的上聯(lián)交換機(jī)為 trunk 模式,支持多 Vlantag 的網(wǎng)絡(luò)通信。
- 在物理機(jī)層面通過創(chuàng)建網(wǎng)卡子接口(如圖一左側(cè)),通過對(duì)網(wǎng)卡子接口做 MacVlan 虛擬網(wǎng)卡插入 Kubernetes 的 Pause 容器中,把容器網(wǎng)絡(luò)與物理網(wǎng)絡(luò)打通。
- 公有云方面通過創(chuàng)建彈性網(wǎng)卡,讓一個(gè)機(jī)器上有多個(gè)網(wǎng)卡,且每塊網(wǎng)卡帶獨(dú)立 IP 地址,然后對(duì)新加的網(wǎng)卡做 host-device,將網(wǎng)卡的所屬 network namespace 修改為 Kubernetes 的 Pause 容器,把容器和物理網(wǎng)絡(luò)打通。
- 對(duì) CNI 插件進(jìn)行修改,能夠給容器分配指定 IP 地址 。
圖二左側(cè)是簡(jiǎn)化后的內(nèi)網(wǎng)網(wǎng)絡(luò)拓?fù)洌萜鞯奶摂M網(wǎng)卡通過 MacVlan 與物理網(wǎng)卡的網(wǎng)卡子接口相連,發(fā)出的報(bào)文會(huì)帶上網(wǎng)卡子接口的 Vlantag。
而這部分的流量上到上聯(lián)交換機(jī)之后就和物理機(jī)發(fā)出的沒有任何區(qū)別,之后的都是交換機(jī)和網(wǎng)關(guān)去解決掉路由的問題。
這個(gè)方案的設(shè)計(jì)對(duì)現(xiàn)有的環(huán)境依賴最小,同時(shí)改動(dòng)量少。實(shí)現(xiàn)機(jī)房物理網(wǎng)絡(luò)與容器網(wǎng)絡(luò)的扁平化,解決了容器網(wǎng)絡(luò)和物理網(wǎng)絡(luò)互聯(lián)互通的問題。
由于沒有隧道解封性能問題,性能基本上持平物理機(jī)性能。本質(zhì)上這是一個(gè)私有云的網(wǎng)絡(luò)解決方案,但是很好的解決了問題。
圖二右側(cè)是簡(jiǎn)化后的公有云網(wǎng)絡(luò)拓?fù)洌ㄟ^把物理機(jī)上的網(wǎng)卡遷移到容器里面來間接的實(shí)現(xiàn)多 IP。由于是虛擬機(jī)的彈性網(wǎng)卡,等同于虛擬機(jī)上的物理網(wǎng)卡,性能沒有問題。
虛擬網(wǎng)絡(luò)后續(xù)的演近:對(duì) Calico 進(jìn)行改進(jìn)取消 Iptables 依賴。利用 Calico 去解決內(nèi)網(wǎng)網(wǎng)絡(luò)方案中 IP 浪費(fèi)的問題。同時(shí)可以對(duì) Calico 做進(jìn)一步的研究,如動(dòng)態(tài)遷移容器如何保持 IP 漂移。
基礎(chǔ)建設(shè)之調(diào)度管理
容器調(diào)度,其實(shí)是為了提高資源利用率,同時(shí)減少資源碎片化。
Kubernetes 的調(diào)度策略做的相對(duì)靈活,對(duì) Pod 的調(diào)度通過三個(gè)階段來實(shí)現(xiàn),初篩階段用于篩選出符合基本要求的物理機(jī)節(jié)點(diǎn),優(yōu)選階段用于得到在初篩的節(jié)點(diǎn)里面根據(jù)策略來完成選擇最優(yōu)節(jié)點(diǎn)。
在優(yōu)選完畢之后,還有一個(gè)綁定過程,用于把 Pod 和物理機(jī)進(jìn)行綁定,鎖定機(jī)器上的資源。這三步完成之后,位于節(jié)點(diǎn)上的 kubelet 才能開始真正的創(chuàng)建 Pod。
在實(shí)際的接入過程中,Kubernetes 的基礎(chǔ)調(diào)度策略不能滿足平臺(tái)的業(yè)務(wù)需求,主要有如下兩點(diǎn):
- 因?yàn)闆]有規(guī)格的概念,所以無法給出庫存狀態(tài)。
- 初篩的緯度太少,目前只支持 CPU,內(nèi)存的初篩,優(yōu)選不支持同機(jī)房就近調(diào)度。
整體方案
圖三
整體的調(diào)度管理分成如下幾層:
- 接口層:用于接收請(qǐng)求返回特定規(guī)格,特定調(diào)度需求下的庫存數(shù)量,同時(shí)返回鎖定好的虛擬 IP 地址。也用于接收請(qǐng)求釋放虛擬 IP 地址。
- 初篩層:對(duì)緩存中的節(jié)點(diǎn)信息進(jìn)行初篩,返回能部署規(guī)格的全部物理機(jī)節(jié)點(diǎn)信息。
- 優(yōu)選層:根據(jù)優(yōu)選結(jié)果,模擬部署 Pod,統(tǒng)計(jì)整體庫存。
- 部署策略層:按照部署策略挑選物理機(jī),并且鎖定物理機(jī)上的虛擬 IP 地址,返回庫存信息。
調(diào)度管理之接口層
鎖定庫存接口層的邏輯:
- 把請(qǐng)求參數(shù)轉(zhuǎn)化為 Kubernetes 的 Pod 對(duì)象 -> v1.Pod。
- 把 Scheduler 的 Cache 進(jìn)行一次深拷貝,后續(xù)的動(dòng)作都會(huì)在這個(gè)深拷貝的 Cache 中完成。
- 請(qǐng)求監(jiān)控返回物理機(jī)的實(shí)時(shí)硬盤信息,實(shí)時(shí)帶寬信息。整合到深拷貝 Cache 中。
- 連同請(qǐng)求參數(shù)都傳遞給初篩層。
釋放庫存接口層的邏輯:
- 調(diào)用 Kubernetes 接口,把物理機(jī)節(jié)點(diǎn)上虛擬 IP 的 label 改成 unusing。
調(diào)度管理
圖四
初篩層:對(duì)上述的 Cache 部分里面的 Node 節(jié)點(diǎn)進(jìn)行 CPU,內(nèi)存,硬盤和帶寬的初步篩選,返回通過篩選的所有物理機(jī)節(jié)點(diǎn)。
優(yōu)選層:對(duì)上述的物理機(jī)節(jié)點(diǎn)信息進(jìn)行打分,對(duì)節(jié)點(diǎn)進(jìn)行排序。然后根據(jù)請(qǐng)求所需部署的容器數(shù)量,按照物理機(jī)節(jié)點(diǎn)的進(jìn)行模擬部署(挑選物理機(jī)按照分?jǐn)?shù)從高到低排列),直到全部節(jié)點(diǎn)上可部署容器數(shù)量為 0,統(tǒng)計(jì)每個(gè)節(jié)點(diǎn)能部署的容器個(gè)數(shù)。
部署策略層:根據(jù)請(qǐng)求參數(shù)的不同(目前只支持集中/平鋪),鎖定物理機(jī)上的 IP 地址(調(diào)用 Kubernetes 的 API 把物理機(jī)上虛擬 IP 的 Label 置為 Using 狀態(tài)),并且返回這些 IP 地址。
整體流程圖
圖五
后續(xù)演進(jìn):支持調(diào)度優(yōu)先級(jí),且能根據(jù)實(shí)際的資源使用情況進(jìn)行調(diào)度而不是 Kubernetes 預(yù)分配的資源進(jìn)行調(diào)度。
基礎(chǔ)建設(shè)之資源隔離
Kubernetes 支持 CPU、內(nèi)存的隔離。在宿主機(jī)層面支持驅(qū)逐模式。通過虛擬化網(wǎng)絡(luò)的方案,主容器網(wǎng)絡(luò)和混部容器的網(wǎng)絡(luò)分割開來。整體的資源隔離目標(biāo)是為了隔離開主容器和混部容器對(duì)資源的使用。
以下是我們做的一些改進(jìn):
- 計(jì)算資源隔離:K8S 提供了內(nèi)存的限制能力,是通過 OOM 來限制內(nèi)存的使用。在此基礎(chǔ)上,我們還增加了限制容器使用物理機(jī)的 Swap。
- 存儲(chǔ)資源隔離:K8S 沒有提供基于物理機(jī)的存儲(chǔ)資源配額方案,但是提供了相關(guān)的框架接口。在此基礎(chǔ)上,開發(fā)了有配額大小限制的物理機(jī)靜態(tài)存儲(chǔ)解決方案。
- 網(wǎng)絡(luò)資源隔離:針對(duì)容器的網(wǎng)絡(luò)限速方案,已經(jīng)在內(nèi)部測(cè)試通過,同時(shí)幫助社區(qū)完善了相關(guān)的限速代碼。
后續(xù)的演進(jìn):資源隔離的后續(xù)方向很多,首先要解決的是 Kubernetes 如何能動(dòng)態(tài)設(shè)置資源閾值。其后需要能夠設(shè)置內(nèi)存 OOM 優(yōu)先級(jí),以及滿足資源超賣的需求。
基礎(chǔ)建設(shè)之 CI/CD
平臺(tái)于 2018 年基于 Gitlab 開發(fā)了 CI/CD,通過 CI/CD 和 Kubernetes 的配合來完成從代碼提交到上線的完整流程。
其中使用 Kubernetes 的上線流程(如 Deployment)的滾動(dòng)發(fā)布存在著容器 IP 不固定,動(dòng)態(tài)化的問題是因?yàn)?Kubernetes 的設(shè)計(jì)原則中對(duì)集群的管理尤其是服務(wù)升級(jí)過程中需要保持“無損”升級(jí)(升級(jí)過程中提供服務(wù)的副本數(shù)一直符合預(yù)期)。
如果對(duì)一個(gè) Deployment 進(jìn)行滾動(dòng)升級(jí),那么這個(gè) Deployment 里面的 IP 地址和滾動(dòng)升級(jí)之前的 IP 地址是不會(huì)相同的。
而如果集群夠大,一次滾動(dòng)發(fā)布就會(huì)導(dǎo)致負(fù)載均衡變更 (集群副本數(shù)/滾動(dòng)發(fā)布步長)次。
對(duì)于微博服務(wù)來說,頻繁變更會(huì)導(dǎo)致這個(gè)負(fù)載均衡轄下,所以后端實(shí)例的接口不穩(wěn)定。
而平臺(tái)內(nèi)部的之前的上線系統(tǒng)是根據(jù)業(yè)務(wù)冗余度及業(yè)務(wù)實(shí)際需要來調(diào)整上線的步長,減少在上線過程中業(yè)務(wù)的抖動(dòng),也就是通常說的 In-place rolling updates。保證在上線過程中容器的 IP 不變。
整體流程的核心思路為:
- 切斷容器的流量
- 進(jìn)行流量檢測(cè),確保已經(jīng)沒有線上流量
- 清理舊容器
- 部署新容器
- 檢測(cè)服務(wù)是否正常啟動(dòng)(端口檢測(cè),接口驗(yàn)證)
- 接收線上流量,提供服務(wù)
針對(duì)該問題,容器平臺(tái)沒有使用 Kubernetes 的原生滾動(dòng)發(fā)布而是做了以下幾個(gè)改進(jìn)和適配:
- 首先不使用 DP,RC 的概念來完成滾動(dòng)發(fā)布,只使用 Pod 的概念。
- 集成已有的上線系統(tǒng),來完成滾動(dòng)發(fā)布,回滾功能。
- 流量引入/流量拒絕 利用 Kubernetes 容器生命周期管理的 lifecycle(修改了其中的 postStar 的原生實(shí)現(xiàn),因?yàn)樵锩嬷徽{(diào)用一次,不管成功與否都會(huì)殺掉容器。改進(jìn)成了如果不成功會(huì)按照指定的次數(shù)或時(shí)間進(jìn)行重試),服務(wù)檢查利用 liveness probe、readiness probe 來完成。
主要流程有:
- 提前給每個(gè)機(jī)器上劃分虛擬 IP 段,并給機(jī)器打上虛擬 IP 的 Label。
- 在原有的上線系統(tǒng)中增加對(duì) Kubernetes 管理容器的上線流程,上線過程中通過服務(wù)池中已有 IP 反查 Pod Name,然后刪掉舊 Pod,然后用新的鏡像 tag 生成 Pod 的 json 字符串(其中 nodeSelect=${IP}),然后提交 Kubernetes 去創(chuàng)建新 tag 版本的 Pod。
- Kubelet 接到創(chuàng)建請(qǐng)求之后,提取其中的 IP 地址發(fā)給 CNI,創(chuàng)建指定 IP 的新 tag 版本 Pod。
上線回滾的流程變成了刪除 Pod,創(chuàng)建 Pod 的固定化操作,見圖六:
圖六
由于給機(jī)器打好了虛擬 IP 標(biāo)簽,所以 Pod 的創(chuàng)建會(huì)被分配給固定的物理機(jī)去執(zhí)行,配合修改之后的 CNI 就能創(chuàng)建指定新 tag +固定 IP 的 Pod 來提供服務(wù)。滾動(dòng)發(fā)布和回滾變成了刪除 Pod,創(chuàng)建 Pod 的固定化操作。
基礎(chǔ)建設(shè)之模塊化運(yùn)維
由于之前的容器是獨(dú)占物理機(jī)的模式,所以對(duì)于容器的運(yùn)維也是在物理機(jī)上進(jìn)行的,一些功能如日志處理、域名解析、時(shí)鐘同步、運(yùn)維 Agent 管理以及定時(shí)任務(wù)等都是在物理機(jī)層面操作。
如果開始多容器混合部署,以上的功能都兼容改動(dòng)工作量大。再加上平臺(tái)面向的業(yè)務(wù)方眾多,需求各不相同。
例如日志推送的方式已經(jīng)出現(xiàn) scribe、flume、filebeat 等不同的方式,業(yè)務(wù)運(yùn)維需要根據(jù)自身去定制運(yùn)維容器,由此可見模塊化運(yùn)維的必要性。
圖七
我們基于 Kubernetes 的 Pod 概念做了如下的工作,整體架構(gòu)見圖七:
- 單獨(dú)做了運(yùn)維容器,把運(yùn)維相關(guān)的工具集成在容器里面。
- 運(yùn)維容器和業(yè)務(wù)容器共享網(wǎng)絡(luò)協(xié)議棧,共享日志存儲(chǔ)。
- 在容器里面共享存儲(chǔ)是帶配額的靜態(tài)存儲(chǔ)。
模塊化運(yùn)維之定時(shí)任務(wù)
物理機(jī)上的定時(shí)任務(wù)依賴于 Crontab,而 Crontab 會(huì)由 Systemd 來啟動(dòng)。
在容器中使用 Systemd 啟動(dòng)會(huì)涉及到提權(quán)問題,在實(shí)踐過程中發(fā)現(xiàn)用 Systemd 如果權(quán)限控制不當(dāng)會(huì)造成容器被 Kill 的情況。
所以單獨(dú)開發(fā)了兼容 Linux Crontab 語法的定時(shí)任務(wù)工具 -gorun,把這個(gè)工具集成在了運(yùn)維容器里面,替代了 Crontab 來完成定時(shí)任務(wù)。
模塊化運(yùn)維之日志處理
圖八
日志的處理主要包括監(jiān)控采集、日志推送、日志查詢、日志壓縮清理四方面:
- 日志推送:通過 scribe,flume 等方式接收業(yè)務(wù)日志,推送給信息系統(tǒng)部等數(shù)據(jù)處理部門,如圖八。
- 日志查詢:容器產(chǎn)生的日志需要能夠靜態(tài)存儲(chǔ)三天左右,方便故障定位。所以日志會(huì)存儲(chǔ)基于 Kubernetes 的 PVC 概念開發(fā)的本地帶配額的靜態(tài)存儲(chǔ)里面。
- 日志壓縮清理:磁盤空間有限,打印的日志需要定期的清理和壓縮。
- 監(jiān)控采集:通過監(jiān)聽文件變化或者監(jiān)聽端口來采集需要的監(jiān)控?cái)?shù)據(jù)。
通過上述手段,能夠利用現(xiàn)有的日志體系,同時(shí)開發(fā)的工作量最小,通過這樣的操作,以后的容器想要接入,只需要在 Pod 的配置文件里面多寫一個(gè) Container 的配置即可。
后續(xù)的演進(jìn):后續(xù)的運(yùn)維容器將會(huì)進(jìn)一步的拆分,做成標(biāo)準(zhǔn)化的服務(wù),例如域名解析容器,日志推送容器。讓業(yè)務(wù)的接入變得更加的容易。
基礎(chǔ)建設(shè)之彈性擴(kuò)縮容
彈性伸縮在微博的應(yīng)用很廣,作為支持了全公司春晚擴(kuò)容的 DCP 系統(tǒng)其主要能力就是進(jìn)行 IaaS 層虛擬機(jī)的彈性伸縮。它是對(duì)業(yè)務(wù)進(jìn)行保障的重要手段之一。
彈性擴(kuò)縮容保證在峰值流量來臨時(shí)通過擴(kuò)容提高接口的可用性,在業(yè)務(wù)量級(jí)下降后回收資源節(jié)省了成本,而 PaaS 層的擴(kuò)縮容比 IaaS 層的擴(kuò)縮容更具有優(yōu)勢(shì)。
一來是因?yàn)?PaaS 的啟動(dòng)更輕,沒有虛擬機(jī)的初始化階段,所以啟動(dòng)更快;二來是因?yàn)槲覀兊膹椥哉{(diào)度系統(tǒng)能提前鎖定 IP,可以做到業(yè)務(wù)容器和變更 Nginx 同步進(jìn)行。
所以在 PaaS 層的彈性擴(kuò)縮容,我們目前做到了如下幾點(diǎn)工作:
- 定時(shí)擴(kuò)縮容實(shí)現(xiàn)
- 自動(dòng)化擴(kuò)縮容的實(shí)現(xiàn)
定時(shí)擴(kuò)縮容是復(fù)用了 DCP 系統(tǒng)的定時(shí)擴(kuò)縮容功能,并做了一定的適配,目前可以選擇使用原生擴(kuò)容模式(IaaS 層)和 Kubernetes 擴(kuò)容模式。
選擇好了模式之后需要填的就是 Pod 的調(diào)度參數(shù)和本身 Pod 的標(biāo)準(zhǔn)化 Json 文件,之后就是常規(guī)功能。
自動(dòng)化擴(kuò)縮容的實(shí)現(xiàn),是基于 CI/CD 系統(tǒng)中的放量系統(tǒng)完成的,CI/CD 會(huì)在上線過程中有單機(jī)放量的步驟,其中會(huì)采集放量容器的監(jiān)控?cái)?shù)據(jù),業(yè)務(wù)數(shù)據(jù)和日志數(shù)據(jù)。
橫向?qū)Ρ犬?dāng)前服務(wù)池的整體接口耗時(shí)和縱向?qū)Ρ葰v史七天內(nèi)單機(jī)的接口耗時(shí)。
通過這套系統(tǒng),把相關(guān)的閾值指標(biāo)導(dǎo)出之后,集成到監(jiān)控系統(tǒng)中,如果判斷接口的 QPS 和耗時(shí)產(chǎn)生了惡化,會(huì)相應(yīng)的觸發(fā)擴(kuò)容操作,不同于 IaaS 層的擴(kuò)容,PaaS 的擴(kuò)容在存量機(jī)器上是免費(fèi)的。
例如前端某接口的 QPS 過高,處理不過來了可以在機(jī)器學(xué)習(xí)服務(wù)池的機(jī)器上進(jìn)行容器擴(kuò)縮容去先扛住量。
基礎(chǔ)建設(shè)之負(fù)載均衡
微博平臺(tái)的 7 層負(fù)載均衡方案是使用 Nginx。目前仍使用的是靜態(tài)文件的進(jìn)行路由信息管理。
Nginx 變更系統(tǒng)實(shí)現(xiàn)了一套動(dòng)態(tài)的解決方案,將 upstream 與對(duì)應(yīng)的服務(wù)池進(jìn)行關(guān)聯(lián),確保對(duì)應(yīng)的接口由對(duì)應(yīng)的服務(wù)池來提供服務(wù),當(dāng)服務(wù)池內(nèi)有節(jié)點(diǎn)變更時(shí),自動(dòng)觸發(fā)配置下發(fā)進(jìn)行 Nginx 的變更。
Kubernetes 從最開始的 Service 上就開始了負(fù)載均衡和服務(wù)發(fā)現(xiàn)的嘗試,例如在 Service 上利用 Iptables 進(jìn)行請(qǐng)求的隨機(jī)負(fù)載(問題在于后端某個(gè)實(shí)例的壓力已經(jīng)很高了,由于是 Iptables 的硬負(fù)載不能感知到,依然把請(qǐng)求傳遞過來)。
而且和網(wǎng)絡(luò)虛擬化一樣引入 Iptables 會(huì)有 nf_conntrack 打滿的風(fēng)險(xiǎn),考慮到公司內(nèi)部已經(jīng)有成熟的負(fù)載均衡系統(tǒng),這塊進(jìn)行了一個(gè)適配。
由于彈性調(diào)度的功能,我們會(huì)在創(chuàng)建 Pod 之前就可以鎖定 IP 地址。當(dāng) IP 地址鎖定后,我們可以同步的變更我們的負(fù)載均衡系統(tǒng)+啟動(dòng)我們的業(yè)務(wù)容器,能夠更快的響應(yīng)業(yè)務(wù)請(qǐng)求,見圖九:
圖九
基礎(chǔ)建設(shè)之監(jiān)控系統(tǒng)
監(jiān)控和日志都是平臺(tái)內(nèi)部成熟的組件,通過模塊化運(yùn)維中日志信息的采集推送,監(jiān)控?cái)?shù)據(jù)采集推送已經(jīng)兼容原有方式推送到監(jiān)控平臺(tái)。而物理機(jī)監(jiān)控已經(jīng)通過運(yùn)維物理機(jī)部署 Agent 來采集,不需要重新引入別的工具去完成。
整體的監(jiān)控總共有如下的幾個(gè)部分:
①物理機(jī)信息監(jiān)控:物理機(jī) CPU、內(nèi)存、IOPS、帶寬、負(fù)載、網(wǎng)絡(luò)等基礎(chǔ)監(jiān)控信息。
②業(yè)務(wù)容器的業(yè)務(wù)監(jiān)控:包括接口 QPS、耗時(shí)、返回狀態(tài)碼占比、err/warn 日志記數(shù)、鏈接資源耗時(shí)等,見圖十:
圖十
③容器使用物理資源監(jiān)控:CPU、內(nèi)存、IOPS、帶寬、負(fù)載、網(wǎng)絡(luò)等基礎(chǔ)監(jiān)控信息,由于已有一套監(jiān)控體系,修改了的實(shí)現(xiàn)把原先需要集中處理的部分落在了計(jì)算節(jié)點(diǎn)本地,然后通過已有的物理機(jī)監(jiān)控?cái)?shù)據(jù)推送到遠(yuǎn)端監(jiān)控上。
一來避免了之前 Heapster 結(jié)構(gòu)中的單點(diǎn)問題;二來可以復(fù)用現(xiàn)有的日志推送架構(gòu),見圖十一:
圖十一
④Kubernetes 組件監(jiān)控:包括單機(jī)的 Kubelet 接口耗時(shí)、成功率監(jiān)控、日志中 err、warn 監(jiān)控,同樣包括 Master 節(jié)點(diǎn)的同類數(shù)據(jù)監(jiān)控。
基礎(chǔ)平臺(tái)的建設(shè)不限于上述的部分,還做了鑒權(quán),DNS 優(yōu)化等相關(guān)服務(wù)。限于篇幅不便展開,于此同時(shí)微博平臺(tái) Kubernetes 也在積極的與社區(qū)保持迭代,爭(zhēng)取做到能回饋社區(qū)。
春晚紅包飛業(yè)務(wù)落地
2019 年春晚期間,后端服務(wù)支持紅包飛業(yè)務(wù),如果按照傳統(tǒng)方式需要近百臺(tái)的公有云設(shè)備按需成本。
我們通過把垂直業(yè)務(wù)從大容器中抽離形成微服務(wù),利用 Kubernetes PaaS 整合能力,在未增加資源成本的情況下完成春晚紅包飛保障。
目前有 6 大服務(wù)池接入 Kubernetes PaaS,共管理數(shù)千核 CPU,數(shù) TB 內(nèi)存的計(jì)算資源。
通過 Kubernetes 整合閑散資源與合理的混合部署,可提供近整體的 30% 的彈性伸縮能力。
綜上,是微博平臺(tái)在 Kubernetes 與業(yè)務(wù)更好結(jié)合道路上的一些體會(huì),實(shí)際業(yè)務(wù)接入過程中依然會(huì)有很多的挑戰(zhàn)。
但是在團(tuán)隊(duì)成員的努力下,最終實(shí)現(xiàn)了方案的落地并保障了春晚的線上業(yè)務(wù)的穩(wěn)定。
通過這次的平臺(tái)建設(shè)充分體會(huì)到只有和業(yè)務(wù)結(jié)合,并且服務(wù)好業(yè)務(wù)才能更好的促進(jìn)自身架構(gòu)的成長,很多時(shí)候看似很理想的方案,面對(duì)真實(shí)的業(yè)務(wù)需求還是會(huì)出現(xiàn)紕漏。
我們會(huì)吸取歷史的教訓(xùn),總結(jié)經(jīng)驗(yàn)。爭(zhēng)取利用先進(jìn)的技術(shù)來為公司創(chuàng)造更大的價(jià)值。
展望未來
未來我們將長期運(yùn)行混合部署的微服務(wù)架構(gòu),優(yōu)化調(diào)度系統(tǒng),對(duì)接更多的 IaasS 層提供商。
更進(jìn)一步提高接口可用性和資源利用率,也會(huì)對(duì)服務(wù)的穩(wěn)定性和資源的利用率做進(jìn)一步探索,利用技術(shù)提升研發(fā)效率也是我們后續(xù)的方向。
在探索的同時(shí)我們也會(huì)對(duì) ServiceMesh、Serverless 持續(xù)關(guān)注,結(jié)合著業(yè)務(wù)需求,更進(jìn)一步優(yōu)化容器基礎(chǔ)平臺(tái)。
作者:彭濤、王琨
簡(jiǎn)介:彭濤,主要負(fù)責(zé)微博容器平臺(tái)的開發(fā)工作。Kubernetes 代碼貢獻(xiàn)者。曾就職于百度基礎(chǔ)架構(gòu)部,百度公有云事業(yè)部。長期從事云計(jì)算行業(yè)。熟悉網(wǎng)絡(luò)虛擬化,SDN,OpenStack,Kubernetes。致力于推動(dòng) Kubernetes 在微博的應(yīng)用落地,構(gòu)建高效的 PaaS 平臺(tái)。
王琨,微博平臺(tái)高級(jí)產(chǎn)品運(yùn)維工程師,主要負(fù)責(zé)微博 Feed、用戶關(guān)系、架構(gòu)業(yè)務(wù)的運(yùn)維支撐及改造工作。擅長大規(guī)模分布式系統(tǒng)集群的管理與運(yùn)維,疑難問題分析,故障定位與處理。致力于推進(jìn)運(yùn)維自動(dòng)化,構(gòu)建微博平臺(tái)高效的運(yùn)維平臺(tái)。