騰訊會議,一款聯合國都Pick的線上會議解決方案,提供完美會議品質和靈活協作空間,廣泛應用在政府、醫療、教育、企業等各個行業,大家從文章8天擴容100萬核,騰訊會議是如何做到的?都知道騰訊會議背后的計算資源已過百萬核,如此體量的業務,如何通過云原生技術提升研發和運維效率,是一個非常有價值的課題,這里我將為大家揭秘騰訊自研上云容器平臺TKEx在支持騰訊會議全量云原生化上云背后的技術,
TKEx平臺是以騰訊云容器服務(Tencent Kubernetes Engine, TKE)為底座,服務于騰訊自研業務的容器平臺,騰訊自研業務型別眾多、規模超大,云原生上云面臨的挑戰可想而知,TKEx平臺在騰訊自研業務上云的程序中沉淀的最佳實踐和解決方案,我們將會在TKE中提供給客戶,
騰訊會議業務特性
在Kubernetes中,我們習慣把應用分為無狀態和有狀態兩類,有狀態應用主要指實體標識、網路、存盤的有狀態,騰訊會議的一些服務有如下特性:
- 使用IPC共享記憶體,里面存放的有狀態資料從MB到GB大小不等,
- 升級時IPC資料不能丟失;
- 升級時只能允許ms級的抖動,用戶無感知;
- 部分服務最多的實體數過萬,要求高效完成一次版本升級;
- 全球多地域部署,要求部署高效;
- 部分服務要求每個實體都分配EIP;
這對Kubernetes管理這種有狀態服務提出了更高能力和性能要求,TKEx平臺抽象出業務特性背后的產品需求,在灰度發布、多集群作業負載管理、計算資源管理運營、Node穩定性等方面進行了增強和優化,沉淀出了通用的音視頻業務容器編排能力,
StatefulSetPlus強大的灰度發布能力
StatefulSetPlus是我們2018年研發并投入生產的首批Operator之一,核心特性包括:
- 兼容StatefulSet所有特性,比如按序滾動更新,
- 支持分批灰度更新和回滾,單批次內的Pods可并發更新、可串行更新,
- 支持各個批次手動待升級勾選Pods,
- 支持用戶配置各個批次待升級Pods的比例進行灰度,
- 支持分批回滾和一鍵失敗回滾,
- 發布程序可暫停,
- 支持單個StatefulSetPlus物件管理上萬個Pods,
- 支持ConfigMap的分批灰度發布,
- 對接了TKE IPAMD,實作了Pod固定IP,
- 支持HPA和原地VPA,
- 升級程序中的擴容使用LastGoodVersion,
- 支持Node核心狀態自檢,Node例外時Pod能自動漂移,
- 支持容器原地升級,
- 支持升級失敗Pods的容忍率控制,大規模升級程序中升級失敗Pods占比小于x%時可繼續升級,

這里主要介紹為騰訊會議上TKE新增的兩個發布能力增強:大規模自動分批灰度發布和ConfigMap分批灰度發布,
支持單個StatefulSetPlus上萬Pods的自動分批發布能力
TKEx平臺在原來StatefulSetPlus手動分批發布能力基礎上,這次又開發了自動分批發布的特性,解決像騰訊會議這種大體量業務灰度發布的痛點,用戶只要在發布時配置各個批次更新副本的百分比,比如第一批40%,第二批60%,StatefulSetPlus-Operator會根據Readiness探針完成情況,自動進行下一批次的更新,其原理如下,

StatefulSetPlus核心Field說明如下:
- batchDeployConfig:
- batchNum:分幾批升級
- batchAuto:是否自動分批發布,true表示自動分批發布
- batchIntervalMinutes:兩次分批發布之間的間隔分鐘數
- podsNumToUpdate:各批次發布的pod數量,如果不設定則將pod平均到每批次發布
StatefulSetPlus對發布程序進行了精細化的監控,提供staus.batchDeployStatus查詢發布詳細狀態,這使得通過CI Pipeline發布變得更顯示和可控,
- batchDeployStatus:
- action:當前操作,
Next表示進行下一批發布,WaitToConfirm表示等待確認該批次發布是否成功,Completed表示所有批次均已確認發布成功, - batchDeadlineTime:本批次發布的Deadline,如果超過該時間,本批次的Pod仍然未Running & Ready,那么本批次發布失敗,進入自動回滾流
- batchOrder:當前批次
- batchOrdinal:本批次發布pod的Index的起點
- batchReplicas:本批次發布的pod的數量
- currentDeployComplete:本批次發布是否完成
- currentOrderSuccessPer:成功升級的pod所占百分比
- currentOrderProgress:本批次發布是否成功
- currentRollbackProgress:本批次回滾是否成功
- generalStatus:本次發布全域狀態
- action:當前操作,
可在annotations加上platform.tkex/pause-auto-batchDeploy: "true"來暫停自動分批發布和失敗自動回滾,
在TKEx平臺上,通過如下操作流程即可輕松完成自動分批發布,



騰訊會議最大的模塊需要支持上萬個Pods的灰度發布,這是前所未有的挑戰,這一次,我們對StatefulSetPlus-Operator進行了優化,性能得到大幅提升,對于一萬個pod的StatefulSetPlus,分5批自動升級,單批次2000個pod,不掛載cbs盤的場景,表現如下:
- 非原地升級方式:單批次升級處理耗時40-45秒,單批次升級從發起升級到升級完成耗時三分半鐘,升級程序中單次同步StatefulSetPlus status耗時10秒左右,
- 原地升級方式:單批次升級處理耗時30秒左右,單批次升級從發起升級到升級完成耗時一分十秒左右,升級程序中單次同步StatefulSetPlus status耗時10秒左右,
- 正常情況下(非升級程序),同步StatefulSetPlus status毫秒級,
支持ConfigMap的分批灰度發布和版本管理
Kubernetes原生的ConfigMap更新是一次性全量更新到容器內的對應的組態檔,所以通過原生的方式更新組態檔是極其危險的事情,Kubernetes 1.18支持了Immutable ConfigMap/Secret,可以保護關鍵配置被誤改導致業務受影響,業務對容器環境下組態檔的發布同樣有著分批灰度發布的極高訴求,
于是我們給StatefulSetPlus賦予了分批發布組態檔的能力,提升了云原生場景下組態檔發布的安全性,原理如下:

方案概述:
- 用戶修改ConfigMap后提交,后臺自動創建一個新的ConfigMap,其中ConfigMap Name后綴是data內容的hash值,防止同樣的data內容創建出多個ConfigMap,然后在Lable中添加沒有data hash值的真正的ConfigMap名字,另外在lable中添加version,或者允許業務自定義一些lable以便標識ConfigMap的版本,
- Kubernetes對Pod的修改只支持更新欄位
spec.containers[*].image, spec.containers[*].resources(if inplace resources update feature enabled),spec.initContainers[*].image, spec.activeDeadlineSeconds or spec.tolerations(only additions to existing tolerations),因此需要修改kube-apiserver代碼,使得允許update/patch volumes, - 通過StatefulSetPlus的分批灰度發布能力,逐個批次的對Pods參考的ConfigMap進行修改,由kubelet volumemanager自動reload configmap,因此ConfigMap的更新不需要重建Pods,
為防止ConfigMap累積過多,影響etcd集群的性能,我們在自研組件
TKEx-GC-Controller增加ConfigMap的回收邏輯,只保留最近10個版本的ConfigMap,
用戶只要在更新Workload頁面,選擇手動分批或者自動分批更新,在資料卷選項重新選擇新版本的ConfigMap即可,可以在更新業務鏡像的同時也更新ConfigMap組態檔,或者只更新ConfigMap組態檔,
ConfigMap組態檔更新,需要容器內業務行程能watch到組態檔的變更進行重啟加載或者熱加載,然而有些業務當前并沒有這個能力,因此TKEx在ConfigMap發布的入口提供組態檔更新后的ProUpdate Hook,比如業務行程的冷/熱重啟命令,
如何保證有狀態服務的升級只有ms級抖動
拒絕胖容器模式(把容器當虛擬機用)是TKEx平臺的原則,如何使用鏡像發布并且提供像行程重啟一樣的ms級業務抖動,這是騰訊會議容器化上云最有挑戰性的需求之一,TKEx平臺在灰度發布能力上已經做了長期的技術沉淀,上萬個業務模塊在使用,但當前能力仍無法滿足這一需求,鏡像預加載+容器原地升級的方案,仍與這目標差距甚遠,
經過多個方案的設計、分析、測驗對比,考慮通用性、云原生、發布效率多個因素,最終使用如下方案:

Pod里面有3個關鍵容器,它們的職責分別如下:
- biz-sidecar: Sidercar容器職責很簡單,檢測Pod是否在升級中,通過Readyness Probe比較EmptyDir Volume中的業務發布版本檔案version1和version2的內容是否相等,相等則Ready,否則notReady,
- biz-container:容器啟動腳本會將環境變數(預注入)里的一個版本號寫到versionX檔案中,然后開始回圈等檔案鎖,如果成功獲取檔案鎖則啟動業務行程,檔案鎖是防止Pod內同時運行多個版本的業務Container的關鍵,用檔案鎖來做不同版本容器的互斥,
- biz-pause:啟動腳本會將環境變數里的一個版本號寫到versionX檔案里,然后就進入無限sleep狀態,這個容器是備用容器,當業務升級時,它就會通過原地升級的方式切換到biz-container的角色,
升級流程概述
以業務容器鏡像從版本V1升級到版本V2為例,升級流程描述如下:
- 用戶第一次部署業務,如上最左邊的Pod, 一共有3個容器,biz-sidecar,biz-container(配置環境變數版本號為1)以及biz-pause(配置環境變數版本號為1),所有2個容器啟動之后會分別將version1, version2檔案的內容更新為1,biz-sidecar此時為Ready,
- 更新Pod之前的biz-pause容器為業務V2版本的鏡像同時環境變數版本號為2,等該容器原地升級之后把version2檔案的內容更新為2之后開始等檔案鎖,此時biz-sidecar探針轉為notReady狀態,
- StatefulSet-Operator Watch到biz-sidecar為notReady之后再將之前的v1版本的業務鏡像替換成biz-pause鏡像同時環境變數版本號為2,等pause鏡像容器原地重啟之后會將之前v1業務鏡像占的檔案鎖釋放,同時version1內容更新為2,此時sidecar探針為Ready, 整個升級結束,
需要說明以下兩點:
- 原生Kubernetes apiserver只允許修改Pod的image等field,不支持修改resource以及環境變數等,所以該方案需要改K8s apiserver的相關代碼,
- 另外為了保證Pod Level Resource以及Pod QoS不變,StatefulSetPlus-Operator在升級時需要對容器狀態變更程序中進行Container Resource調整,
多地域部署和升級,變得更簡單
在多地域服務管理上,我們主要解決兩個訴求:
- 同一個服務需要部署在很多的地域,提供就近訪問或者多地容災,如何進行服務在多個集群的快速復制;
- 部署在多個地域的同一個服務,如何進行快速的同步升級;
TKEx提供了便捷的多地域多集群業務部署和業務同步升級能力,
- 支持一次性部署到多個地域多個集群,

- 支持部署在多個集群的Workload同步升級,


平臺資源管理能力增強
TKEx平臺的集群資源是所有服務共享的,各種服務混部在集群和節點中,各個產品都有自己的資源預算,平臺接受各個產品的預算,然后根據自動生成對應的資源配額,以此控制各個產品在整個平臺上的Quota,產品部署后,涉及到成本核算,平臺會根據真實使用的資源量,以小時為時間計量粒度,跟蹤統計每個業務產品下面各個Workload的資源使用情況,
DynamicQuota-Operator
Kubernetes原生用ResourceQuota來做資源限制,但是它與我們的期望相比存在如下問題:
- ResourceQuota是基于Namespace的,無法做到產品基本的限制,
- ResourceQuota是基于集群內的限制,無法做到平臺級的,無法進行多集群聯動Balance,
- 只有限制能力,無法保障業務有足夠的資源可以使用,
基于我們對于業務產品的管理需求及期望,TKEx的配額管理系統須滿足如下特性:
- 使用簡單,用戶無需關心底層細節,比如配額如何在各個集群間分布及調配都由系統來自動完成,
- 分配給產品的配額,必須保障產品始終有這么多資源可以使用,
- 滿足平臺在離線混合部署場景訴求,配額要有限制離線任務配額的能力,
- 為了避免某一個產品占用配額而不使用導致平臺資源浪費,要有在產品間配額借和還的能力,
我們設計了一個DynamicQuota CRD,用來管理集群中各個業務產品的Quota,實作以上能力,

- Quota Rebalance Worker: 該Worker會定期根據產品在各集群的配額使用情況,動態的將產品配額在各集群間調配,比如有個產品的服務因為配置了彈性擴縮容,當產品在某個集群因為擴容導致配額用完但是在其他的集群還有比較多的配額,這時Worker就會將配額從空閑集群調配到該集群,
- DynamicQuota Operator: 負責維護自定義CRD DynamicQuota的狀態,同時會收集各產品在集群中的使用情況暴露給Prometheus,
- DynamicQuota ValidatingWebhook: 截獲集群中所有向kube-apiserver的pod創建請求,并阻止那些超配額的產品Pod創建請求,
- OfflineTask QueueManager: 負責從離線作業佇列(ActiveQ)中根據作業優先級進行消費,并判斷各個集群的離線作頁澩占比是否超過水位線,以達到控制所有離線作頁澩占比的目的,防止離線作業消耗過多的集群資源,
- pod-resource-compressor和VPA組件,根據集群和節點實際負載、資源分配情況,對離線作業進行資源壓縮和原地升降配,以保護在線任務的資源使用,在離線混部時,我們還在內核層面對Cpu調度進行了優化,以達到離線任務快速避讓,以保證在線任務的服務質量,
預算轉移自動生成產品Quota
產品完成預算歸屬到TKEx平臺后,平臺將自動為產品增加對應的產品配額,自動修改DynamicQuota,用戶可以在TKEx監控面板中查看歸屬產品的資源配額,

業務核算自動化和可視化
TKEx會以核*時為業務使用資源的計量粒度進行成本核算,用戶可以在TKEx監控面板中查看具體的各個Kubernetes Workload的詳細資源使用情況,

提升自愈能力
隨著集群規模和節點部署密度越來越高,集群平均負載超過50%,高峰期很多節點的負載甚至80%以上,一些穩定性問題開始顯現,為此TKEx針對節點穩定性做了如下優化:
- 主動探測dockerd的可用性,例外時主動重啟dockerd,防止dockerd hung住導致Node上Pods自動銷毀重建,
- 主動監控kubelet的可用性,例外時主動重啟kubelet,防止kubelet hung住導致Pods大量漂移重建,
- 因為Kubernetes在pids.max, file-max等內核引數隔離機制不完善,在kubernetes 1.14中雖然支持了對Pods內Pids numbers的限制,但實際落地時很難為業務指定默認的pids limit,集群中仍會出現因為節點Pids和file-max耗盡導致同一節點上其他業務容器受影響的問題,對此,我們在
Node-Problem-Detector(簡稱NPD)組件中增加了節點pids,file-max的監控,達到相關資源使用水位線時,會自動檢測消耗pids和file-max最多的Container并上報,主動觸發告警并對Container進行原地重啟,
以上幾項能力都在NPD組件中實作,負責監控節點的作業狀態,包括內核死鎖、OOM頻率、系統執行緒數壓力、系統檔案描述符壓力等指標,位元組點驅逐、節點打Taint等動作,并通過Node Condition或者Event的形式上報給Apiserver,
當前NPD組件會在節點中增加如下特定的Conditions:
| Condition Type | 默認值 | 描述 |
|---|---|---|
| ReadonlyFilesystem | False | 檔案系統是否只讀 |
| FDPressure | False | 查看主機的檔案描述符數量是否達到最大值的80% |
| PIDPressure | False | 查看主機是否已經消耗了90%以上的pids |
| FrequentKubeletRestart | False | Kubelet是否在20Min內重啟超過5次 |
| CorruptDockerOverlay2 | False | DockerImage 是否存在問題 |
| KubeletProblem | False | Kubelet service是否Running |
| KernelDeadlock | False | 內核是否存在死鎖 |
| FrequentDockerRestart | False | Docker是否在20Min內重啟超過5次 |
| FrequentContainerdRestart | False | Containerd是否在20Min內重啟超過5次 |
| DockerdProblem | False | Docker service是否Running(若節點運行時為Containerd,則一直為False) |
| ContainerdProblem | False | Containerd service是否Running(若節點運行時為Docker,則一直為False |
| ThreadPressure | False | 系統目前執行緒數是否達到最大值的90% |
| NetworkUnavailable | False | NTP service是否Running |
有些事件是不適合在NDP DaemonSet做分布式檢測的,我們就放在TKEx Node Controller中去做中心式檢測,由其生成Event并發送到Apiserver,比如:
- 快速檢測Node網路問題,而不依賴于5min延時的NodeLost Condition,這個問題NDP檢測到也無法把事件發送到Apiserver,
- Node Cpu持續高負載導致業務服務質量下降,會有TKEx Node Controller做檢測,并將cpu負載Top N的Pods通過Event發送到Apiserver,由TKEx-descheduler來決定驅逐哪些Pods,做驅逐決策時,需要考慮Pods所屬Workload是否是單副本的,Pods是否能容忍Pods漂移重建等,
TKEx-descheduler則負責ListWatch NPD和TKEx Node Controller發送的Events,做出對應的行為決策,比如對Pod內某個問題Container進行原地重啟、問題Pod的驅逐等,

容器網路增強和調度能優化
容器網路支持EIP
TKEx之前提供的VPC+ENI的Underlay網路方案,使得容器網路和CVM網路、IDC網路在同一網路平面,并且支持容器固定IP,極大地方便自研業務上云,這次TEKx平臺的容器網路能力再升級,支持在使用HostNetwork和VPC+ENI容器網路方案上,再為Pod分配EIP(彈性公網IP)的能力,
調度優化
當后端集群資源池耗盡,會有大量的待調度的pending pods,此時使用任何型別的Workload進行鏡像更新時都會出現資源搶占導致升級失敗的情況,
為了解決這個問題,提升業務升級的穩定性,我們優化了Kubernetes Scheduler Cache的邏輯,給StatefulSet/StatefulSetPlus升級時提供了資源預搶占的調度能力,很好的保證了在不新增資源的情況下StatefulSet/StatefulSetPlus能正常升級成功,不會被調度佇列中的Pendnig Pod搶占資源,
后面團隊會單獨輸出一篇技術文章對此進行詳細分析,感興趣的同學請關注騰訊云原生公眾號,加小助手TKEplatform,拉你進騰訊云容器技術交流群,
總結
本文總結了騰訊會議在TKE容器化部署時用到的平臺相關特性,包括業務鏡像自動分批灰度發布、ConfigMap分批灰度發布、Pod內A/B容器ms級切換發布、多集群發布管理、基于DynamicQuota的產品配額管理、探測節點和集群穩定性問題以提升自愈能力等,騰訊自研業務在TKE上沉淀的優秀組件和方案,后面會在公網TKE產品中提供給公網客戶,也在計劃開源,敬請期待,
【騰訊云原生】云說新品、云研新術、云游新活、云賞資訊,掃碼關注同名公眾號,及時獲取更多干貨!!

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/684.html
標籤:其他
