2017年3月底,Kubernetes隆重發布了1.6版本,在節點規模、安全性、調度和存儲上都有了重大進展。目前來看,不論從社區關注度還是實踐案例角度,Kubernetes都已經超越Mesos和Docker Swarm,成為最受歡迎的容器編排技術。
網易云從2015下半年開始向Kubernetes社區貢獻代碼,是國內最早的Kubernetes實踐者和貢獻者,也是Kubernetes技術的積極布道者,網易云已經成為CNCF官方授權的CloudNative Meetup主辦方。6月3日,網易云在網易杭州園區舉辦Kubernetes Meetup杭州站,活動邀請了Hyper項目成員、Kubernetes項目官方Project Manager和Feature Maintainer張磊,網易云容器編排技術負責人婁超,才云Caicloud高級軟件工程師岑鵬浩,當當網數字業務事業部技術總監李志偉,為杭州的小伙伴們帶來Kubernetes最新的技術進展和最佳實踐。
本文主要整理了網易云容器編排技術負責人婁超的演講“網易云基于Kubernetes的深度定制化實踐”!
婁超,網易云容器編排技術負責人。曾經參與淘寶分布式文件系統tfs和阿里云緩存服務研發,2015年加入網易參與網易云容器服務研發,經歷網易云基礎服務(蜂巢)v1.0,v2.0的容器編排相關的設計和研發工作,并推動網易云內部Kubernetes版本不斷升級。
網易云容器服務的架構
網易云的容器服務基于網易云的IaaS。為了簡化用戶的操作,Kubernetes并不是直接暴露給用戶的,而是通過上層的業務層為用戶提供容器服務,增加獨立的Netease-Controller, 對接網易IaaS及公共平臺,資源管理和復雜的業務需求。
Kubernetes公有云實踐
Kubernetes的社區版本主要面向私有云市場,沒有租戶的概念,只有namespace的邏輯隔離,Node/pv等資源都是集群全局共享的,服務發現和負載均衡也都是全局的,Node須在集群內預備足夠,不用擔心資源調度出現失敗,也無需關心Docker隔離安全性問題。而對于公有云來說,云中有著海量用戶,用戶的技術背景多樣,需要很高的安全隔離性。網易云在基于Kubernetes實現公有云的過程中,做了很多工作。
- 首先,在多租戶的安全隔離方面,有專門的IaaS團隊提供主機、硬盤和網絡的隔離;
- 對于每個租戶來說,都可以自定義創建namespace;
- 原生的Kubernetes認證很簡單,而且Node是全局共享的,每個Node上都可訪問Kubernetes的所有資源,所以為了實現公有云,網易云做了租戶級別的安全隔離,包括認證、授權和API分類統計和流控報警;
- 在網易云中計算、存儲、網絡資源均按需實時分配、回收,保證資源的利用率盡可能高;因為資源是實時分配的,所以創建起來一般比較慢,所以網易云對創建流程做了一些全局的優化,比如加快Node注冊的進程,根據鏡像選擇主機等;
- 原生的Kubernetes中沒有網絡IP的概念,網易云增加了Network資源類型表示網絡IP。
網易云容器Pod網絡
容器的網絡主要有以下幾種方案:
入門級:Docker 基礎網絡模型 host(共享),bridge(NAT)
進階級:自建網橋(IP-per-pod),可跨主機通訊,如Flannel, Weave
專業級: 多租戶,ACL,高性能可擴展 ,如Calico,GCE高級網絡模式
網易云容器網絡實現
網易云的容器服務的網絡實現與GCE類似,基于底層的IaaS網絡,通過Kubernetes與網易云網絡對接,網易云容器與主機在網絡上完全對等,租戶內全互通。
Kubernetes中沒有定義IP的管理,可能一個容器或節點重啟一下,IP就變了。網易云通過IP的管理實現了IP的保持功能,同時Pod支持私有網、公網雙重網絡。
此外,網易云還實現了Pod的私有網、公網IP映射關系管理,在Kubelet上實現Netease CNI插件管理網卡掛卸載、路由配置。
網易云有狀態容器
提到容器的狀態,人們常用Cattle和Pet來做比喻。Cattle是指無狀態的容器,隨時可以被替換,Pet則是有標記的,它的數據、狀態和配置可能都需要持久化。社區從1.3版本就開始用PetSet實現有狀態的容器,最新的1.6版本中,是叫StatefulSet。
網易云在社區版本的有狀態容器誕生之前(1.0版本),就自研了StatefulPod的實現方式:
和StatefulSet不同的是,它可以支持容器系統卷、數據卷的保持(PV、PVC)。StatefulSet只能支持外掛的數據卷,但是網易云的StatefulPod能夠保證只要不刪除用戶,用戶系統盤的數據也能夠保持下來;
- StatefulPod還能保證容器私有網、公網IP保持(Network);
- 在原生的Docker中,一個Node啟動的所有容器目錄都是統一的,網易云擴展Docker支持容器rootfs目錄自定義;
- 網易云的有狀態容器還支持故障的遷移,比如硬盤和IP等資源都能在Node間漂移。
網易云Kubernetes性能優化
一般在實現公有云時,盡量會保證同一個機房內,只有一個Kubernetes集群,但隨著用戶的增多,集群的規模也越來越大,會出現很多性能問題。網易云隨著社區的發展一路走來,也遇到了很多社區可能在設計之初并沒有預料到的問題,比如:
- Kube-scheduler對所有pod順序串行調度
- Kube-controller的deltaQueue是無優先級的FIFO隊列
- Serviceaccounts控制器里沒有Secret本地緩存
- 所有Node重復配置集群所有Service的iptables規則
- Kubelet的SyncLoop每次檢查都重復GET imagePullSecrets
- 大量Node的心跳匯報嚴重影響了Node的watch
- Kube-apiserver 沒有查詢索引
針對這些問題,網易云做了很多性能優化,首先是master端的調度器:
- 公有云的場景和私有云不一樣,容器分布在不同的租戶中,每個租戶的資源都是獨立的,本身就可以通過租戶來溝通并調度;
- 通常在調度的時候需要一個個去遍歷Node,實際上很多無閑置資源的Node可以不參與調度的檢查,網易云會在遍歷前過濾掉無閑置資源的Node;
- 優化predicate調度算法過濾順序,提高調度效率;
- 網易云中,調度都是基于事件的,比如調度失敗如果是因為Node資源不足,就會發一個事件去申請資源,資源回來后會又會返回一個事件驅動Pod重調度,沒有任何時間等待;
上圖就是在網易云中并行調度的過程。
然后是mater端控制器的優化:
Kubernetes中有很多控制器,比如Node控制器、namespace控制器,其中replication controller是一個核心的控制器,能確保任何時候Kubernetes集群中有指定數量的pod副本在運行。網易云創建了事件優先級機制,根據事件類型進入優先級隊列workqueue。
Node端的優化:
網易云的用戶很多,用戶之間都是完全隔離的,網易云kube-proxy按租戶對Node分組:
- 租戶之間容器網絡完全隔離,不配多余轉發規則;
- 只watch本租戶的Service,再生成iptable 規則。
Kubelet降低master請求負載:
- imagePullSecret推遲都要拉鏡像才GET或增加Secret local cache
- 只watch本租戶相關資源變化(依賴apiserver新加的tenant索引)
- 租戶之間容器網絡完全隔離,不配多余轉發規則;
- 精簡kubelet watch 低master連接數,包括Node
接下來是針對單集群擴展的優化:
根據官方的數據,Kubernetes 1.0最多支持100個Node,3000個Pod;在1.3版本中這個數字上升到2K個Node,6W個Pod,今年最新發布的1.6版本已經支持5K個Node,15W個Pod。
通過上圖可以知道APIserver是整個集群的通信網關,只是一個proxy代理,而且goroutine對web服務完美支持,最終性能瓶頸在對 Etcd的訪問上。
為了解決這個問題,首先想到的是分庫,按Node/RS/Pod/Event分庫存入多個Etcd集群。因為Etcd本身容量和性能均不能水平擴展,而且沒有性能診斷工具;
- Etcd2 調優,比如針對snapshot的優化,采用SSD硬盤等;
- 升級Etcd3,在之前的版本中,每次更改都會發送一個請求,一個請求又對應一個回復,在Etcd3中是批量請求的方式,可能一次請求就把1000個變化推送過來了,所以效率提高很多;
- 更換Kubernetes后端的存儲,換其他性能更優的KV存儲。
Node心跳匯報模式修改
- Node心跳間隔延長
- Node心跳不持久化
- 心跳從Node分離出來,Node心跳只需list不必watch
- NodeController被動改主動探測
其它優化
鏡像、容器的GC完善:目前的GC只考慮了磁盤的空間使用量,沒考慮inode的問題,很多用戶的小文件很多,所以網易云新增了磁盤inode使用率檢查
容器監控統計:Cadvisor新增網絡流量、TCP連接、磁盤相關統計
NodeController安全模式,自定義Protected,Normal,Advanced 3種模式。
- Protected: 底層IAAS主動臨時運維時,為了避免大規模遷移波動, Node離線只報警不遷移
- Normal:有狀態的不遷移,無狀態的及時離線刪除重建。(僅僅底層云盤、網絡故障)
- Advanced:有狀態無狀態都自動遷移恢復
還需要注意的一些問題:
- Pod的graceful delete要容器能正常傳遞SIGTERM信號
- StatefulSet在kubelet掛掉時可能出現兩個同時運行的Pod