网易云容器服务基于Kubernetes的实践探索
Kubernetes的特點
近年來Docker容器作為一種輕量級虛擬化技術革新了整個IT領域軟件開發(fā)部署流程,如何高效自動管理容器和相關的計算、存儲等資源,將容器技術真正落地上線,則需要一套強大容器編排服務,當前大紅大紫的Kubernetes已經(jīng)被公認為這個領域的領導者。Google基于內(nèi)部Borg十多年大規(guī)模集群管理經(jīng)驗在2014年親自傾心打造了Kubernetes這個開源項目,欲倚之與AWS在云計算2.0時代一爭高下,即便如此,Kubernetes的定位主要是面向私有云市場,它最典型的部署模式是在GCE或AWS平臺上基于云主機、云網(wǎng)絡、云硬盤及負載均衡等技術給用戶單獨部署一整套Kubernetes容器管理集群,其本質(zhì)上是賣的IAAS服務,Kubernetes集群還是需要靠用戶自己維護,大家知道Kubernetes雖然功能強大但使用、管理、運維門檻也高,出問題了大多數(shù)用戶會束手無策。
這幾年國內(nèi)容器云領域也是群雄割據(jù),但多數(shù)還是以私有云為主,提供公有云容器服務的卻很少,主要是公有云要考慮的問題多、挑戰(zhàn)大。雖然如此,網(wǎng)易云的還是提供了公有云模式的容器服務。網(wǎng)易云從2015年開始做容器服務時也被Kubernetes強大的功能、插件化思想和背后強大的技術實力說吸引,至今已經(jīng)跟隨Kubernetes一起走過兩年多,積累了不少經(jīng)驗。因為我們特別希望以公有云的方式提供一種更易用容器服務,任何對容器感興趣的用戶都能快速上手,為此也遇到了很多私有云下不會出現(xiàn)的問題。
列舉幾個Kubernetes在公有云容器場景下的需要特別解決的關鍵問題。一是Kubernetes里沒有用戶(租戶)的概念,只有一個很弱的命名空間來做邏輯隔離。二是Kubernetes和Docker的安全問題很突出,API訪問控制較弱且沒有用戶流控機制,一些資源全局可見。而Docker容器與宿主機共享內(nèi)核的輕量級隔離從根本上沒法做到徹底安全。三是Kubernetes集群所需要IAAS資源(如Node,PV)都要預先準備足夠,否則容器隨時會創(chuàng)建失敗,公有云這樣的話會造成嚴重的資源浪費,產(chǎn)生巨大的成本問題。四是Kubernetes單個集群能支撐的節(jié)點總數(shù)有限,最大安全規(guī)模只有5千個Node,公有云下擴展性將會有問題。
網(wǎng)易云容器如何解決Kubernetes在公有云上的問題
先看下網(wǎng)易云容器服務的架構圖(如圖1),這里的Kubernetes處于底層IAAS服務和上層容器平臺的中間,因為我們的容器服務不僅僅提供Kubernetes本身容器編排管理功能,更是為提供一整套專業(yè)的容器解決方案,還包括容器鏡像服務,負載均衡服務,通過使用DevOps 工具鏈高效管理微服務架構。考慮到Kubernetes概念較多、普通用戶使用復雜,也為了便于整合其他配套服務,我們并沒有直接暴露Kubernetes的API和所有概念給普通用戶。
公有云租戶概念
網(wǎng)易云容器服務基于Kubernetes已有的Namespace的邏輯隔離特性,虛擬出一個租戶的概念,并與Namespace進行永久綁定:一個Namespace只能屬于一個租戶,一個租戶則可以有多個Namespace。這樣Kubernetes里不同租戶之間的Pod、Service、Secret就能自然分割,而且可以直接在原生的Namespace/Resouce級別的認證授權上進行租戶級別的安全改造。
多租戶安全問題
關于Kubernetes的API的安全訪問控制,盡管網(wǎng)易云容器沒有直接暴露Kubernetes的API給用戶,但用戶容器所在的Node端也都要訪問API,Node本質(zhì)就是用戶的資源。我們在最早基于Kubernetes 1.0開發(fā)的時候就專門增加了一套輕量級擴展授權控制插件:基于規(guī)則訪問控制,比如配置各租戶只能Get和Watch屬于自己Namespace下的Pod資源,解決對Kubernetes資源API權限控制粒度不夠精確且無法動態(tài)增減租戶的問題。值得欣慰的是幾個月前官方發(fā)布的1. 6新推出RBAC(基于角色訪問控制)功能,使得授權管理機制得以增強,但服務端對用戶Node端訪問的異常流量控制的缺乏依然是一個隱患,為此,我們也在apiserver端增加請求數(shù)來源分類統(tǒng)計和控制模塊,避免有不良用戶從容器里逃逸到Node上進行惡意攻擊。?
原生的kube-proxy提供的內(nèi)部負載必須要List&Watch集群所有Service和Endpoint,導致就算在多租戶場景下Service和Endpoint也要全部暴露,同時導致iptables規(guī)則膨脹轉(zhuǎn)發(fā)效率極低;為此我們對kube-proxy也做了優(yōu)化改造:每個租戶的Node上只會List&Watch自己的相關Namespace下資源即可,這樣既解決了安全問題又優(yōu)化性能,一箭雙雕。
至于Docker的隔離不徹底的問題,我們則選擇了最徹底的做法:在容器外加了一層用戶看不見的虛擬機,通過IAAS層虛擬機的OS 內(nèi)核隔離保證容器的安全。
容器的IAAS資源管理
容器云作為新一代的基礎設施云服務,資源管理必然也是非常關鍵的。私有云場景下整個集群資源都屬于企業(yè)自己,預留的所有資源都可以一起直接使用、釋放、重用;而公有云多租戶下的所有資源首先是要進行租戶劃分的,一旦加入kubernetes集群,Node、PV、Network的屬主租戶便已確定不變,如果給每個租戶都預留資源,海量租戶累計起來就非常恐怖了,沒法接受。當然,可以讓公有云用戶在創(chuàng)建容器前,提前把所有需要的資源都準備好,但這樣又會讓用戶用起來更復雜,與容器平臺易用性的初衷不符,我們更希望能幫用戶把精力花在業(yè)務本身。
于是我們需要改造kubernetes,以支持按需動態(tài)申請、釋放資源。既然要按需實時申請資源,那就先理下容器的創(chuàng)建流程,簡單起見,我們直接創(chuàng)建Pod來說明這個過程,如圖3所示。
Pod創(chuàng)建出來后,首先控制器會檢查是否有PV(網(wǎng)易云容器為支持網(wǎng)絡隔離還增加租戶Network資源),PV資源是否匹配,不匹配則等待。如果Pod不需要PV或者PV匹配后調(diào)度器才能正常調(diào)度Pod,然后scheduler從集群所有Ready的 Node列表找合適Node綁定到Pod上,沒有則調(diào)度失敗,并從1秒開始以2的指數(shù)倍回退(backoff)等待并重新加入調(diào)度隊列,直到調(diào)度成功。最后在調(diào)度的Node的kubelet上拉鏡像并把容器創(chuàng)建并運行起來。
通過分析上述流程可以發(fā)現(xiàn),可以在控制器上匹配PV或Network時實時創(chuàng)建資源,然后在調(diào)度器因缺少Node而調(diào)度失敗時再實時創(chuàng)建Node(虛擬機VM),再等下次失敗backoff重新調(diào)度。但是仔細分析后會發(fā)現(xiàn)還有很多問題,首先是IAAS中間層提供的創(chuàng)建資源接口都是異步的,輪詢等待效率會很多,而且PV,Network,Node都串行申請會非常慢,容器本來就是秒級啟動,不能到云服務上就變成分鐘級別;其次Node從創(chuàng)建VM,初始化安裝Docker、kubelet、kube-proxy到啟動進程并注冊到Kubernetes上時間漫長,調(diào)度器backoff重新調(diào)度多次也不一定就緒,最后,基于Kubernetes的修改要考慮少侵入,Kubernetes社區(qū)極度活躍一直保持3個月發(fā)布一個大版本的節(jié)奏,要跟上社區(qū)發(fā)展可能需要不斷升級線上版本。
最終,我們通過增加獨立的ResourceController,借助watch機制采用全異步非阻塞、全事件驅(qū)動模式。資源不足就發(fā)起資源異步申請,并接著處理后面流程,而資源一旦就緒立馬觸發(fā)再調(diào)度,申請Node時中間層也提前準備虛擬機資源池,并將Node初始化、安裝步驟預先在虛擬機鏡像中準備好。于是,我們詳細的創(chuàng)建流程演變?yōu)閳D4所示。(注:最新Kubernetes 已經(jīng)通過StorageClass類型支持PV dynamic provisioning)?
與原生的Kubernetes相比,我們增加了一個獨立的 ResourceController管理所有IAAS資源相關的事情,具體的Pod創(chuàng)建步驟如下:
- 1、上層client請求apiserver創(chuàng)建一個Pod。
- 2、ResourceController watch到有新增Pod,檢查PV和Network是否已經(jīng)創(chuàng)建;?
同時,另一邊的scheduler也發(fā)現(xiàn)有新Pod尚未調(diào)度,也嘗試對Pod進行調(diào)度。 - 3、因為資源都沒有提前準備,最初ResourceController檢查時發(fā)現(xiàn)沒有與Pod匹配的PV和Network,會向IAAS中間層請求創(chuàng)建云盤和網(wǎng)絡資源;?
scheduler 則也因為找不到可調(diào)度的Node也同時向IAAS中間層請求創(chuàng)建對應規(guī)格的VM資源(Node),這時Pod也不再重入調(diào)度隊列,后面一切準備就緒才會重調(diào)度。 - 4、因為IAAS中間層創(chuàng)建資源相對較慢,也只提供異步接口,待底層資源準備完畢,便立即通過apiserver注冊PV、Network、Node資源
- 5~6、ResourceController當發(fā)現(xiàn)PV和Network都滿足了,就將他們與Pod綁定;當發(fā)現(xiàn)Pod申請的Node注冊上來,且PV和Network均綁定,會把Pod設置為ResourceReady就緒狀態(tài)
- 7、Scheduler再次watch到Pod處于ResourceReady狀態(tài),則重新觸發(fā)調(diào)度過程,
- 8、Pod調(diào)度成功與新動態(tài)創(chuàng)建Node進行綁定
- 9~10、對應Node的kubelet watch到新調(diào)度的Pod還沒有啟動,則會先拉取鏡像再啟動容器。
集群最大規(guī)模問題
從正式發(fā)布1.0版本至今最新的1.7,Kubernetes共經(jīng)歷了2次大規(guī)模的性能優(yōu)化,從1.0的200個node主要通過增加apiserver cache提升到1000個node,再到1.6通過升級etcdv3和json改protobuf最終提升到5000 node。但是官方稱后續(xù)不會再考慮繼續(xù)優(yōu)化單集群規(guī)模了,已有的集群聯(lián)邦功能又太過簡陋。如果公有云場景下隨著已有用戶規(guī)模不斷增大,一旦快接近集群最大規(guī)模時,就只能將其中一些大用戶一批批遷移出去來騰空間給剩余用戶。
于是我們自己在社區(qū)版本基礎上又做了大量定制化的性能優(yōu)化,目前單集群性能測試最大安全規(guī)模已經(jīng)超過3萬,驗收測試包括集群高水位下,大并發(fā)創(chuàng)建速度deployment和快速重啟master端服務和所有node端kubelet等在內(nèi)的多種極端異常操作,保證創(chuàng)建時間均值<5s,99值<15s,集群中心管控服務最差在3分鐘內(nèi)快速恢復正常。
具體的優(yōu)化措施包括:
- 1、 scheduler優(yōu)化?
根據(jù)租戶之間資源完全隔離互補影響的特性,我們將原有的串行調(diào)度流程,改造為租戶間完全并行的調(diào)度模式,再配合協(xié)程池來爭奪可并行的調(diào)度任務。在調(diào)度算法上,還采用預先排除資源不足的node、優(yōu)化過濾函數(shù)順序等策略進行局部優(yōu)化。 - 2、 Controller優(yōu)化?
熟悉Kubernetes的人都知道,Kubernetes有個核心特點就是事件驅(qū)動,實時性很好,但是有個Sync事件卻干擾了FIFO的順序,我們通過將Add、Update、Delete、Sync事件排序并增加多優(yōu)先級隊列的方式解決這種異常干擾。?
增加Secret本地緩存 - 3、 apiserver優(yōu)化?
apiserver的核心是提供類似CRUD的restful接口,優(yōu)化方向無外乎降低響應時間,減少cpu、內(nèi)存消耗以提高吞吐量,我們最主要的一個優(yōu)化是增加以租戶ID為過濾條件的查詢索引,這樣就能實現(xiàn)在租戶內(nèi)跨Namespace聚合查詢的效果。另外apiserver的客戶端原生的流控策略太暴力,客戶端默認在流控被限制后會反復重試,進一步加劇apiserver的壓力,我們增加了一種基于反饋的智能重試的策略抹平這種突發(fā)流量。 - 4、Node端優(yōu)化?
kube-proxy本來需要控制整個集群負載轉(zhuǎn)發(fā)的,Apiserver有了租戶查詢索引后,我們就能只watch自己租戶內(nèi)的Service/Endpoint,急劇縮小iptables規(guī)則數(shù)量,提高查找轉(zhuǎn)發(fā)效率。而且我們還精簡kubelet和kube-proxy內(nèi)存占用和連接數(shù)。
網(wǎng)易云容器服務的其他實踐及總結
容器的網(wǎng)絡是非常復雜一塊,容器云服務至少要提供穩(wěn)定、靈活、高效的跨主機網(wǎng)絡,雖然開源網(wǎng)絡實現(xiàn)很多,但是它們要么不支持多租戶、要么性能不好,且直接拿沒有經(jīng)過大規(guī)模線上考驗的開源軟件問題總會很多。幸運的時網(wǎng)易云有自己專業(yè)的IAAS云網(wǎng)絡團隊,他們能提供專業(yè)級的VPC網(wǎng)絡解決方案,天生就支持多租戶、安全策略控制和高性能擴展,已經(jīng)做到容器與虛擬主機的網(wǎng)絡是完全互通且地位對等的。
網(wǎng)易云容器服務還在Kubernetes社區(qū)版本基礎上結合產(chǎn)品需求新增了很多功能,包括支持特有的有狀態(tài)容器,及Node故障時容器系統(tǒng)目錄也能自動遷移以保持數(shù)據(jù)不變,多副本Pod可按Node的AvailableZone分布強制均衡調(diào)度(社區(qū)只盡力均衡)、容器垂直擴容、有狀態(tài)容器動態(tài)掛卸載外網(wǎng)IP等。
相比容器的輕量級虛擬化,虛擬機雖然安全級別更高,但是在cpu、磁盤、網(wǎng)絡等方面都存在一定的性能損耗,而有些業(yè)務卻又對性能要求非常高。針對這些特殊需求,最近我們也在開發(fā)基于Kubernetes的高性能裸機容器,繞過虛擬機將網(wǎng)絡、存儲等虛擬化技術直接對接到Docker容器里,在結合SR-IOV網(wǎng)絡技術、網(wǎng)易高性能云盤NBS(netease block storage)等技術將虛擬化的性能損耗降到最低。
最后,分享一些網(wǎng)易云容器服務上線近兩年來的遇到的比較典型的坑。
-
1、Apiserver作為集群hub中心本身是無狀態(tài)的可水平擴展,但是多apiserver讀寫會在Apiserver切換時可能會出現(xiàn)寫入的數(shù)據(jù)不能立馬讀到的問題,原因是etcd的raft協(xié)議不是所有節(jié)點強一致寫的。
-
2、haproxy連接的問題,多Apiserver前用haproxy做負載均衡,haproxy很容易出現(xiàn)客戶端端口不夠用和連接數(shù)過多的問題,可以通過擴大端口范圍、增加源ip地址等方式解決端口問題,通過增加client/service的心跳探活解決異常連接GC的問題。
-
3、用戶覆蓋更新已有tag的私有容器鏡像問題,強烈建議大家不要覆蓋已有tag的鏡像,也不要使用latest這樣模糊的鏡像標簽,否則RS多Pod副本或者同一個Node上同鏡像容器很容易出現(xiàn)版本不一致的詭異問題。
-
4、有些容器小文件非常多,很容易把inode用光而磁盤空間卻剩余很多的問題,建議把這種類型應用調(diào)度到inode配置多的node上,另外原生kubelet也存在不會檢查inode過多觸發(fā)鏡像回收的問題。
-
5、有些Pod刪除時銷毀過慢的問題,Pod支持graceful刪除,但是如果容器鏡像啟動命令寫得不好,可能會導致信號丟失不光沒法graceful刪除還會導致延遲30s的問題
總之,在公有云場景下,用戶來源廣泛,使用習慣千變?nèi)f化沒法控制,我們已經(jīng)碰到過很多純私有云場景下很難出現(xiàn)的問題,如用戶鏡像跑起不來,Pod多容器端口沖突,日志直接輸出到標準輸出,或者日志寫太快沒有切割,甚至把容器磁盤100%寫滿等,因為篇幅有限,所以只能挑選幾個有代表性的專門說明。因為云上要考慮的問題太多,特別是這種基礎設施服務類的,使用場景又非常靈活,線上出現(xiàn)的一些問題之前完全想不到,包括很多還是用戶自己使用的問題,但為了要讓用戶有更好的體驗,也只能盡力而為,優(yōu)先選擇一些通用的問題去解決。
作者:婁超,網(wǎng)易云容器編排技術負責人。曾經(jīng)參與淘寶分布式文件系統(tǒng)tfs和阿里云緩存服務研發(fā),2015年加入網(wǎng)易參與網(wǎng)易云容器服務研發(fā),經(jīng)歷網(wǎng)易云基礎服務(蜂巢)v1.0,v2.0的容器編排相關的設計和研發(fā)工作,并推動網(wǎng)易云內(nèi)部Kubernetes版本不斷升級。?
本文為《程序員》原創(chuàng)文章,未經(jīng)允許不得轉(zhuǎn)載,更多精彩文章請訂閱《程序員》,給我們投稿請聯(lián)系郵箱weiwei@csdn.net。(責編/魏偉)
歡迎掃描下方二維碼,關注CSDN云計算微信,獲取更多干貨原創(chuàng)內(nèi)容。
總結
以上是生活随笔為你收集整理的网易云容器服务基于Kubernetes的实践探索的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: zmbx是哪个保险公司
- 下一篇: [重磅] 如何更好地实现服务调用和消息推