Kubernetes 在宜信落地實踐
伴隨著微服務的架構的普及,結合開源的Dubbo和Spring Cloud等微服務框架,宜信內部很多業務線逐漸了從原來的單體架構逐漸轉移到微服務架構。應用從有狀態到無狀態,具體來說將業務狀態資料如:會話、使用者資料等儲存到中介軟體中服務中。
微服務的拆分雖然將每個服務的複雜度降低,但服務例項的數目卻呈現出爆炸式增長,這給運維增加難度,一方面是服務部署、升級,另一方面是服務的監控故障恢復等。
在2016年,容器技術尤其是Docker迅速流行起來,公司內部開始嘗試將容器放到容器內執行,雖然通過容器解決了服務釋出問題,但很多容器的運維仍然讓運維捉襟見肘。宜信是一家金融科技公司,在引入開源元件的時候,穩定可靠是作為考量的最重要標準,在2017年初kubernetes慢慢成熟,成為容器的管理標準,並且被國內外很多公司採用,在這種背景下,宜信借鑑開源社群和商業PAAS平臺產品,基於kubernetes自研一套容器管理平臺。
整體架構
整個架構圍繞kubernetes構建,分為四個層級,最底層主要是基礎資源,包括網路、計算、儲存,所有的容器都是部署在物理伺服器上,容器掛載商業NAS儲存,網路通過vxlan互連;中間層核心的是資源排程層,主要完成多叢集的管理、釋出部署、智慧排程、自動伸縮等,這層主要是資源管理和服務編排;左側面是提供系統安全,主要是為了系統安全和容器映象安全,右側面是一套程式碼自動編譯、自動構建、自動部署系統;中介軟體層主要提供常用的中介軟體服務,Nginx配置和監控告警等;最上層的是使用者接入層,主要提供使用者的操作入口。整體架構如下圖所示:
Nginx自助管理
公司大部分的服務都是通過Nginx反向代理對外提供服務,為了服務的隔離和負載均衡,總計十幾套的Nginx叢集,這些nginx的版本、配置方式各有不同,導致單純靠人工去運維的成本非常高而且容易出錯,並且容器的IP地址不固定,無法直接配置到nginx後端。自研了一套nginx管理系統,主要是為了解決nginx的模板化配置,如下圖所示:
Nginx-mgr提供HTTP請求,負責接收nginx配置請求,並更新到etcd,每個nginx-agent通過watch Etcd批量重新整理nginx的配置。在實際的生產環境裡,部署的是阿里開源的Tengine而並非nginx,由於配置基本相同不做區分。每個服務都配置了健康檢查,這樣能夠保障在後端故障中自動切換。如果有虛擬機器場景需要手動切換,下圖展示了手動切換nginx的頁面:
由於很多業務都是虛擬機器和容器混跑的情況下,如果後端是容器,我們通過kubernetes的API獲取容器的IP地址動態重新整理。
多叢集管理
雖然kubernetes本身存在採用高可用的部署架構,避免單點故障,但這遠遠還不夠,一方面是因為單個kubernetes叢集部署在一個機房,如果發生機房級別的故障,將會導致服務中斷,另一方面由於單個kubernetes叢集本身故障,如叢集的網路配置錯誤導致整個網路故障等,都將會影響業務的正常使用,在宜信將kubernetes部署在多個機房內,機房之間通過專線互連。那麼多叢集的管理將成為主要難點:第一是如何分配資源,當用戶選擇多叢集部署後,系統根據每個叢集的資源用量,決定每個叢集分配的容器數量,並且保證每個叢集至少有一個容器。叢集自動伸縮時,也會按照此比例建立和回收容器。第二是故障遷移,如圖中的叢集控制器主要為了解決多叢集的自動伸縮和叢集故障時的容器遷移,控制器定時檢測叢集的多個節點,如果多次失敗後將觸發叢集容器遷移的操作,保障服務可靠執行。
第三是網路和儲存的互連,由於跨機房的網路需要互連,我們採用vxlan的網路方案實現,儲存也是通過專線互連。容器的映象倉庫採用Harbor,多叢集之間設定同步策略,並且在每個叢集都設定各自的域名解析,分別解析到不同的映象倉庫。
DNS解析
由於業務人員對容器技術還存在疑慮,所以大部分應用都是虛擬機器和容器的混合部署,容器通過域名訪問虛擬機器和虛擬機器通過域名訪問容器都是普遍存在的,為了統一管理域名,我們沒有采用kubernetes自帶的kube-dns(coreDns)而採用bind提供域名解析。通過kubernetes支援的Default DNS策略將容器的域名指向公司的DNS伺服器,並配置域名管理的API動態新增。
網路方案
kubernetes的CNI的網路方案有很多種,主要分為二層、三層和overlay方案。一方面機房並不允許跑BGP協議,並且需要跨機房的主機互連,所以我們採用了flannel的vxlan方案,為了實現跨機房的互通,兩個叢集的flannel連線到同一個etcd叢集,這樣保障網路配置的一致性。老版本的Flannel存在很多問題,包括:路由條數過多,ARP表快取失效等問題。建議修改成網段路由的形式,並且設定ARP規則永久有效,避免因為etcd等故障導致叢集網路癱瘓。
Flannel的使用還需要注意一些配置優化,預設情況下每天都會申請Etcd的租約,如果申請失敗會刪除etcd網段資訊。為了避免網段變化,可以將etcd資料節點的ttl置為0(永不過期);Docker預設是會masq所有離開主機的資料包,導致flannel中無法獲取源容器的IP地址,通過設定Ipmasq新增例外,排除目標地址為flannel網段資料包;由於flannel使用vxlan的方式,開啟網絡卡的vxlan offloading對效能提升很高。Flannel本身沒有網路隔離,為了實現kubernetes的network policy我們採用canal,它是calico實現kubernetes的網路策略的外掛。
CICD
為了支援Devops流程,在最初的版本我們嘗試使用Jenkins的方式執行程式碼編譯,但Jenkins對多租戶的支援比較差。在第二版通過kubernetes的Job機制,每個使用者的編譯都會啟動一個編譯的Job,首先會下載使用者程式碼,並根據編譯語言選擇對應的編譯映象,編譯完成後生成執行程式,如果jar或者war檔案。通過Dockerfile打成Docker映象並推送到映象倉庫,通過映象倉庫的webhook觸發滾動升級流程。
服務編排
系統設計了應用的邏輯概念,kubernetes雖然有服務的概念,但缺少服務的關聯關係,一個完整的應用通常包括前端、後端API、中介軟體等多個服務,這些服務存在相互呼叫和制約的關係,通過定義應用的概念,不僅可以做到服務啟動先後順序的控制,還可以統一規劃啟停一組服務。
日誌
容器的日誌歸集使用公司自研的watchdog日誌系統,每臺宿主機上通過DaemonSet方式部署日誌採集Agent,Agent通過Docker API獲取需要採集的容器和日誌路徑,採集日誌併發送到日誌中心,日誌中心基於elasticsearch開發,提供多維度日誌檢索和匯出。
監控
容器本身資源監控的效能監控通過Cadvisor + Prometheus的方式,容器內業務的監控整合開源的APM監控系統uav(https://github.com/uavorg/uavstack),完成應用的效能監控。uav的鏈路跟蹤基於JavaAgent技術,如果使用者部署應用勾選了使用uav監控,系統在構建映象時將uav的agent植入到映象內,並修改啟動引數。
除了上述幾個模組外,系統還集Harbor完成容器映象的多租戶管理和映象掃描功能;日誌審計是記錄使用者在管理介面的操作,webshell提供使用者的web控制檯接入,為了支援安全審計,後臺會截獲使用者所有在webshell的操作命令並記錄入庫;儲存管理主要是整合公司商業的NAS儲存,為容器直接提供資料共享和持久化;應用商店主要是通過kubernetes的operator提供開發和測試使用的場景中介軟體服務。
落地實踐
docker不是虛擬機器
在容器推廣的初期業務開發人員對容器還不是很熟悉,會下意識認為容器就是虛擬機器,其實他們不僅是使用方式的區別,更是實現方式和原理的差異,虛擬機器是通過模擬硬體指令虛擬出作業系統的硬體環境,而容器是在共享核心的前提下提供資源的隔離和限制。下圖展示了4.8核心中linux支援的7種namespace。
換句話說,其他的都沒有差異,譬如,時鐘,所有容器和作業系統都共享同一個時鐘,如果修改了作業系統的時間,所有容器都時間都會變化。除此之外,容器內proc檔案系統也是沒有隔離,看到的都是宿主的資訊,這給很多應用程式帶來困擾,JVM初始的堆大小為記憶體總量的1/4,如果容器被限制在2G的記憶體上限,而宿主機通常都是200+G記憶體,JVM很容易觸發OOM, 解決方案通常是啟動時根據記憶體和CPU的限制設定JVM,或者藉助lxcfs等。
Cgroup的資源限制目前對網路和磁碟IO的限制比較弱,v1的cgroup只支援direct IO的限制,但實際的生產環境都是些快取的。目前我們也在測試cgroup v2關於IO的限制。當最新的CNI已經支援網路限速,結合tc可以很好的達到這個效果。
Kubernetes優化
Kubernetes自帶了很多排程演算法,在啟動容器之前會通過排程的演算法,這些演算法都是需要過濾所有的節點並打分排序,大大增加了容器的部署時間,通過刪除一些無用的排程演算法,從而提高部署的速度。容器採用反親和的策略,降低物理機故障對服務造成的影響。
雖然kubernetes開啟了RBAC,但kubernetes token還是不建議掛載到業務容器內,通過關閉ServiceAccountToken提升系統的安全。
Docker映象儲存使用direct-lvm的方式,這樣效能更優,在部署的時候劃分單獨的vg,避免因為Docker問題影響作業系統。通過devicemapper儲存限制每個容器系統盤為10G,避免業務容器耗盡宿主機磁碟空間,容器執行時需要限制每個容器的最大程序數量,避免fork炸彈。
Etcd裡面記錄了kubernetes核心資料,所以etcd個高可用和定時備份是必須的,在kubernetes叢集超過一百個節點以後,查詢速度就會降低,通過SSD能夠有效提升速度。本系統在kubernetes之外通過資料庫儲存服務和
關注證書的有效期,在部署kubernetes叢集時候,很多都是自籤的證書,在不指定的情況下,openssl預設一年的有效期,更新證書需要非常謹慎,因為整個kubernetes的API都是基於證書構建的,所有關聯的服務都需要修改。
總結:
Docker容器加K8S編排是當前容器雲的主流實踐之一,宜信容器叢集管理平臺也採用這種方案。本文主要分享了宜信在容器雲平臺技術上的一些探索和實踐。本文主要包含了Nginx自助管理、 多叢集管理、DNS解析、網路方案、CICD服務編排、 日誌監控、kubernetes 優化一些技術工作,以及宜信內部容器雲平臺化的一些思考,當然我們還有很多不足,歡迎各路英雄來宜信進行深入溝通和交流!