為什麽 kubernetes 天然適合微服務 (3)
此文已由作者劉超授權網易雲社區發布。
歡迎訪問網易雲社區,了解更多網易技術產品運營經驗
四、Kubernetes 本身就是微服務架構
基於上面這十個設計要點,我們再回來看 Kubernetes,會發現越看越順眼。
首先 Kubernetes 本身就是微服務的架構,雖然看起來復雜,但是容易定制化,容易橫向擴展。
如圖黑色的部分是 Kubernetes 原生的部分,而藍色的部分是網易雲為了支撐大規模高並發應用而做的定制化部分。
Kubernetes 的 API Server 更像網關,提供統一的鑒權和訪問接口。
眾所周知,Kubernetes 的租戶管理相對比較弱,尤其是對於公有雲場景,復雜的租戶關系的管理,我們只要定制化 API Server,對接 Keystone,就可以管理復雜的租戶關系,而不用管其他的組件。
在 Kubernetes 中幾乎所有的組件都是無狀態化的,狀態都保存在統一的 etcd 裏面,這使得擴展性非常好,組件之間異步完成自己的任務,將結果放在 etcd 裏面,互相不耦合。
例如圖中 pod 的創建過程,客戶端的創建僅僅是在 etcd 中生成一個記錄,而其他的組件監聽到這個事件後,也相應異步的做自己的事情,並將處理的結果同樣放在 etcd 中,同樣並不是哪一個組件遠程調用 kubelet,命令它進行容器的創建,而是發現 etcd 中,pod 被綁定到了自己這裏,方才拉起。
為了在公有雲中實現租戶的隔離性,我們的策略是不同的租戶,不共享節點,這就需要 Kubernetes 對於 IaaS 層有所感知,因而需要實現自己的 Controller,Kubernetes 的設計使得我們可以獨立創建自己的 Controller,而不是直接改代碼。
API-Server 作為接入層,是有自己的緩存機制的,防止所有的請求壓力直接到後端數據庫上。但是當仍然無法承載高並發請求時,瓶頸依然在後端的 etcd 存儲上,這和電商應用一摸一樣。當然能夠想到的方式也是對 etcd 進行分庫分表,不同的租戶保存在不同的 etcd 集群中。
有了 API Server 做 API 網關,後端的服務進行定制化,對於 client 和 kubelet 是透明的。
如圖是定制化的容器創建流程,由於大促和非大促期間,節點的數目相差比較大,因而不能采用事先全部創建好節點的方式,這樣會造成資源的浪費,因而中間添加了網易雲自己的模塊 Controller 和 IaaS 的管理層,使得當創建容器資源不足的時候,動態調用 IaaS 的接口,動態的創建資源。這一切對於客戶端和 kubelet 無感知。
為了解決超過 3 萬個節點的規模問題,網易雲需要對各個模塊進行優化,由於每個子模塊僅僅完成自己的功能,Scheduler 只管調度,Proxy 只管轉發,而非耦合在一起,因而每個組件都可以進行獨立的優化,這符合微服務中的獨立功能,獨立優化,互不影響。而且 Kubernetes 的所有組件都是 Go 開發的,更加容易一些。所以 Kubernetes 上手慢,但是一旦需要定制化,會發現更加容易。
五、Kubernetes 更加適合微服務和 DevOps 的設計
好了,說了 K8S 本身,接下來說說 K8S 的理念設計,為什麽這麽適合微服務。
前面微服務設計的十大模式,其中一個就是區分無狀態和有狀態,在 K8S 中,無狀態對應 deployment,有狀態對應 StatefulSet。
deployment 主要通過副本數,解決橫向擴展的問題。
而 StatefulSet 通過一致的網絡 ID,一致的存儲,順序的升級,擴展,回滾等機制,保證有狀態應用,很好地利用自己的高可用機制。因為大多數集群的高可用機制,都是可以容忍一個節點暫時掛掉的,但是不能容忍大多數節點同時掛掉。而且高可用機制雖然可以保證一個節點掛掉後回來,有一定的修復機制,但是需要知道剛才掛掉的到底是哪個節點,StatefulSet 的機制可以讓容器裏面的腳本有足夠的信息,處理這些情況,實現哪怕是有狀態,也能盡快修復。
在微服務中,比較推薦使用雲平臺的 PaaS,例如數據庫,消息總線,緩存等。但是配置也是非常復雜的,因為不同的環境需要連接不同的 PaaS 服務。
K8S 裏面的 headless service 是可以很好地解決這個問題的,只要給外部服務創建一個 headless service,指向相應的 PaaS 服務,並且將服務名配置到應用中。由於生產和測試環境分成 Namespace,雖然配置了相同的服務名,但是不會錯誤訪問,簡化了配置。
微服務少不了服務發現,除了應用層可以使用 SpringCloud 或者 Dubbo 進行服務發現,在容器平臺層當然是用 Service了,可以實現負載均衡,自修復,自動關聯。
服務編排,本來 K8S 就是編排的標準,可以將 yml 文件放到代碼倉庫中進行管理,而通過 deployment 的副本數,可以實現彈性伸縮。
對於配置中心,K8S 提供了 configMap,可以在容器啟動的時候,將配置註入到環境變量或者 Volume 裏面。但是唯一的缺點是,註入到環境變量中的配置不能動態改變了,好在 Volume 裏面的可以,只要容器中的進程有 reload 機制,就可以實現配置的動態下發了。
統一日誌和監控往往需要在 Node 上部署 Agent,來對日誌和指標進行收集,當然每個 Node 上都有,daemonset 的設計,使得更容易實現。
當然目前最最火的 Service Mesh,可以實現更加精細化的服務治理,進行熔斷,路由,降級等策略。Service Mesh 的實現往往通過 sidecar 的方式,攔截服務的流量,進行治理。這也得力於 Pod 的理念,一個 Pod 可以有多個容器,如果當初的設計沒有 Pod,直接啟動的就是容器,會非常的不方便。
所以 K8S 的各種設計,看起來非常冗余和復雜,入門門檻比較高,但是一旦想實現真正的微服務,K8S 可以給你各種可能的組合方式。實踐過微服務的人,往往會對這一點深有體會。
六、Kubernetes 常見的使用方式
下面我們來看一下,微服務化的不同階段,Kubernetes 的使用方式。
第一階段:使用公有雲虛擬機
也即沒有微服務化的階段,基本上一個進程就能搞定,兩個進程做高可用,不需要使用容器,虛擬機就非常好。
第二階段:容器作為持續集成工具
當微服務開始拆分了,如何保證拆分後功能的一致性,需要持續集成作為保證,如前面的論述,容器是非常好的持續集成工具,是解決 CI/CD 中 D 的,所以一開始用 host 網絡就可以,這樣可以保證部署方式和原來兼容。
如果想用私有雲進行部署,直接部署在物理機上,在性能要求沒有很高,但是又要和其他物理機很好的通信的情況下,可以用 bridge 打平網絡的方式比較好。通過創建網橋,將物理網卡,容器網卡都連接到一個網橋上,可以實現所有的容器和物理機在同樣的一個二層網絡裏面。
如果性能要求比較高,例如要部署類似緩存,則可以使用 sr-iov 網卡。
如果想實現租戶的簡單隔離,則往往使用各種 Overlay 的網絡模式,這是最常用的部署方式。圖中的數據來自網絡。Flannel,Calico 都是非常好的網絡插件,雖然 Flannel 一開始使用用戶態的模式性能不好,後來使用內核態,性能大大改善,使用 gw 模式後,和 Calico 性能相當。
網易雲采用了 Kubernetes 和 IaaS 深度融合的方式,類似 AWS 的 Fargate 的模式,一方面可以使得原來使用虛擬機的用戶平滑地遷移到容器,另一方面可以實現公有雲的租戶隔離。
如圖是融合的網易雲容器服務的架構,這個管理 OpenStack 和 Kubernetes 的管理平臺,也是用的微服務架構,有 API 網關,熔斷限流功能,拆分成不同的服務,部署在 K8S 上的,所以處處是微服務。
網易雲輕舟微服務是圍繞應用和微服務打造的一站式 PaaS 平臺,幫助用戶快速實現易接入、易運維的微服務解決方案。
相關閱讀:為什麽 kubernetes 天然適合微服務 (1)
為什麽 kubernetes 天然適合微服務 (2)
為什麽 kubernetes 天然適合微服務 (3)
相關文章:
【推薦】 一“腳”到位-淋漓盡致的自動化部署
【推薦】 基於 cookie 的 node 中間層灰度流程的一些思考
為什麽 kubernetes 天然適合微服務 (3)