1. 程式人生 > >為什麽 kubernetes 天然適合微服務

為什麽 kubernetes 天然適合微服務

連接 日誌搜索 良好的 虛擬機 讓我 一是 簡化 環境配置 互調

轉至http://www.cnblogs.com/163yun/p/8855360.html

最近總在思考,為什麽在支撐容器平臺和微服務的競爭中,Kubernetes 會取得最終的勝出,事實上從很多角度出發三大容器平臺從功能方面來看,最後簡直是一摸一樣。(可參考《容器平臺選型的十大模式:Docker、DC/OS、K8S 誰與當先?》)

經過一段時間的思索,以及采訪了從早期就開始實踐 Kubernetes 的網易雲架構師們後,我把反思所得總結為今天的這篇文章。

一、從企業上雲的三大架構看容器平臺的三種視角

技術分享圖片

如圖所示,企業上雲的三大架構為 IT 架構、應用架構和數據架構,在不同的公司,不同的人、不同的角色,關註的重點不同。

對大部分的企業來講,上雲的訴求是從 IT 部門發起的,發起人往往是運維部門,他們關註計算、網絡、存儲,試圖通過雲計算服務來減輕 CAPEX 和 OPEX。

有的公司有 ToC 的業務,因而累積了大量的用戶數據,公司的運營需要通過這部分數據進行大數據分析和數字化運營,因而在這些企業裏面往往還需要關註數據架構。

從事互聯網應用的企業,往往首先關註的是應用架構,是否能夠滿足終端客戶的需求,帶給客戶良好的用戶體驗。業務量上往往會有短期內出現爆炸式增長的現象,因而關註高並發應用架構,並希望這個架構可以快速叠代,從而搶占風口。

在容器出現之前,這三種架構往往通過虛擬機雲平臺的方式解決。當容器出現之後,容器的各種良好的特性讓人眼前一亮,它的輕量級、封裝、標準、易遷移、易交付的特性,使得容器技術迅速被廣泛使用。

技術分享圖片

然而一千個人心中有一千個哈姆雷特,由於原來工作的關系,三類角色分別從自身的角度看到了容器的優勢給自己帶來的便捷。

對於原來在機房裏管計算、網絡、存儲的 IT 運維工程師來講,容器更像是一種輕量級的運維模式,在他們看來,容器和虛擬機的最大的區別就是輕量級,啟動速度快,他們往往更願意推出虛擬機模式的容器。

對於數據架構來講,他們每天都在執行各種各樣的數據計算任務,容器相對於原來的 JVM,是一種隔離性較好,資源利用率高的任務執行模式。

從應用架構的角度出發,容器是微服務的交付形式,容器不僅僅是做部署的,而且是做交付的,CI/CD 中的 D 的。

所以這三種視角的人,在使用容器和選擇容器平臺時方法會不一樣。

二、Kubernetes 才是微服務和 DevOps 的橋梁

Swarm:IT 運維工程師

技術分享圖片

從 IT 運維工程師的角度來看:容器主要是輕量級、啟動快,並且自動重啟,自動關聯,彈性伸縮的技術,使得 IT 運維工程師似乎不用再加班。

Swarm 的設計顯然更加符合傳統 IT 工程師的管理模式。

他們希望能夠清晰地看到容器在不同機器的分布和狀態,可以根據需要很方便地 SSH 到一個容器裏面去查看情況。

容器最好能夠原地重啟,而非隨機調度一個新的容器,這樣原來在容器裏面安裝的一切都是有的。

可以很方便地將某個運行的容器打一個鏡像,而非從 Dockerfile 開始,這樣以後啟動就可以復用在這個容器裏面手動做的 100 項工作。

容器平臺的集成性要好,用這個平臺本來是為了簡化運維的,如果容器平臺本身就很復雜,像 Kubernetes 這種本身就這麽多進程,還需要考慮它的高可用和運維成本,這個不劃算,一點都沒有比原來省事,而且成本還提高了。

最好薄薄的一層,像一個雲管理平臺一樣,只不過更加方便做跨雲管理,畢竟容器鏡像很容易跨雲遷移。

Swarm 的使用方式比較讓 IT 工程師有熟悉的味道,其實 OpenStack 所做的事情它都能做,速度還快。

技術分享圖片

Swarm 的問題

然而容器作為輕量級虛擬機,暴露出去給客戶使用,無論是外部客戶,還是公司內的開發,而非 IT 人員自己使用的時候,他們以為和虛擬機一樣,但是發現了不一樣的部分,就會有很多的抱怨。

例如自修復功能,重啟之後,原來 SSH 進去手動安裝的軟件不見了,甚至放在硬盤上的文件也不見了,而且應用沒有放在 Entrypoint 裏面自動啟動,自修復之後進程沒有跑起來,還需要手動進去啟動進程,客戶會抱怨你這個自修復功能有啥用?

例如有的用戶會 ps 一下,發現有個進程他不認識,於是直接 kill 掉了,結果是 Entrypoint 的進程,整個容器直接就掛了,客戶抱怨你們的容器太不穩定,老是掛。

容器自動調度的時候,IP 是不保持的,所以往往重啟後原來的 IP 就沒了,很多用戶會提需求,這個能不能保持啊,原來配置文件裏面都配置的這個 IP ,掛了重啟就變了,這個怎麽用啊,還不如用虛擬機,至少沒那麽容易掛。

容器的系統盤,也即操作系統的那個盤往往大小是固定的,雖然前期可以配置,後期很難改變,而且沒辦法每個用戶可以選擇系統盤的大小。有的用戶會抱怨,我們原來本來就很多東西直接放在系統盤的,這個都不能調整,叫什麽雲計算的彈性啊。

如果給客戶說容器掛載數據盤,容器都啟動起來了,有的客戶想像雲主機一樣,再掛載一個盤,容器比較難做到,也會被客戶罵。

如果容器的使用者不知道他們在用容器,當虛擬機來用,他們會覺得很難用,這個平臺一點都不好。

Swarm 上手雖然相對比較容易,但是當出現問題的時候,作為運維容器平臺的人,會發現問題比較難解決。

Swarm 內置的功能太多,都耦合在了一起,一旦出現錯誤,不容易 debug。如果當前的功能不能滿足需求,很難定制化。很多功能都是耦合在 Manager 裏面的,對 Manager 的操作和重啟影響面太大。

Mesos:數據運維工程師

技術分享圖片

從大數據平臺運維的角度來講,如何更快地調度大數據處理任務,在有限的時間和空間裏面,更快地跑更多的任務,是一個非常重要的要素。

所以當我們評估大數據平臺牛不牛的時候,往往以單位時間內跑的任務數目以及能夠處理的數據量來衡量。

從數據運維的角度來講,Mesos 是一個很好的調度器。既然能夠跑任務,也就能夠跑容器,Spark 和 Mesos 天然的集成,有了容器之後,可以用更加細粒度的任務執行方式。

在沒有細粒度的任務調度之前,任務的執行過程是這樣的。任務的執行需要 Master 的節點來管理整個任務的執行過程,需要 Worker 節點來執行一個個子任務。在整個總任務的一開始,就分配好 Master 和所有的 Work 所占用的資源,將環境配置好,等在那裏執行子任務,沒有子任務執行的時候,這個環境的資源都是預留在那裏的,顯然不是每個 Work 總是全部跑滿的,存在很多的資源浪費。

在細粒度的模式下,在整個總任務開始的時候,只會為 Master 分配好資源,不給 Worker 分配任何的資源,當需要執行一個子任務的時候,Master 才臨時向 Mesos 申請資源,環境沒有準備好怎麽辦?好在有 Docker,啟動一個 Docker,環境就都有了,在裏面跑子任務。在沒有任務的時候,所有節點上的資源都是可被其他任務使用的,大大提升了資源利用效率。

這就是 Mesos 最大的優勢,在 Mesos 的論文中,最重要闡述的就是資源利用率的提升,而 Mesos 的雙層調度算法是核心。

原來大數據運維工程師出身的,會比較容易選擇 Mesos 作為容器管理平臺。不過原來是跑短任務,加上 marathon 就能跑長任務。但是後來 Spark 將細粒度的模式 deprecated 掉了,因為效率還是比較差。

Mesos 的問題

技術分享圖片

調度在大數據領域是核心中的核心,在容器平臺中是重要的,但不是全部。所以容器還需要編排,需要各種外圍組件,讓容器跑起來運行長任務,並且相互訪問。Marathon 只是萬裏長征的第一步。

所以早期用 Marathon + Mesos 的廠商,多是裸用 Marathon 和 Mesos 的,由於周邊不全,因而要做各種的封裝,各家不同。大家有興趣可以到社區上去看裸用 Marathon 和 Mesos 的廠商,各有各的負載均衡方案,各有各的服務發現方案。

所以後來有了 DCOS,也就是在 Marathon 和 Mesos 之外,加了大量的周邊組件,補充一個容器平臺應有的功能,但是很可惜,很多廠商都自己定制過了,還是裸用 Marathon 和 Mesos 的比較多。

而且 Mesos 雖然調度牛,但是只解決一部分調度,另一部分靠用戶自己寫 framework 以及裏面的調度,有時候還需要開發 Executor,這個開發起來還是很復雜的,學習成本也比較高。

雖說後來的 DCOS 功能也比較全了,但是感覺沒有如 Kubernetes 一樣使用統一的語言,而是采取大雜燴的方式。在 DCOS 的整個生態中,Marathon 是 Scala 寫的,Mesos 是 C++ 寫的,Admin Router 是 Nginx+lua,Mesos-DNS 是Go,Marathon-lb 是 Python,Minuteman 是 Erlang,這樣太復雜了吧,林林總總,出現了 Bug 的話,比較難自己修復。

Kubernetes

技術分享圖片

而 Kubernetes 不同,初看 Kubernetes 的人覺得他是個奇葩所在,容器還沒創建出來,概念先來一大堆,文檔先讀一大把,編排文件也復雜,組件也多,讓很多人望而卻步。我就想創建一個容器,怎麽這麽多的前置條件。如果你將 Kubernetes 的概念放在界面上,讓客戶去創建容器,一定會被客戶罵。

在開發人員角度,使用 Kubernetes 絕對不是像使用虛擬機一樣,開發除了寫代碼,做構建,做測試,還需要知道自己的應用是跑在容器上的,而不是當甩手掌櫃。開發人員需要知道,容器是和原來的部署方式不一樣的存在,你需要區分有狀態和無狀態,容器掛了起來,就會按照鏡像還原了。開發人員需要寫 Dockerfile,需要關心環境的交付,需要了解太多原來不了解的東西。實話實說,一點都不方便。

在運維人員角度,使用 Kubernetes 也絕對不是像運維虛擬機一樣,我交付出來了環境,應用之間互相怎麽調用,我才不管,我就管網絡通不通。在運維眼中他做了過多不該關心的事情,例如服務的發現,配置中心,熔斷降級,這都應該是代碼層面關心的事情,應該是 SpringCloud 和 Dubbo 關心的事情,為什麽要到容器平臺層來關心這個。

Kubernetes + Docker,卻是 Dev 和 Ops 融合的一個橋梁。

Docker 是微服務的交付工具,微服務之後,服務太多了,單靠運維根本管不過來,而且很容易出錯,這就需要研發開始關心環境交付這件事情。例如配置改了什麽,創建了哪些目錄,如何配置權限,只有開發最清楚,這些信息很難通過文檔的方式又及時又準確地同步到運維部門來,就算是同步過來了,運維部門的維護量也非常的大。

所以,有了容器,最大的改變是環境交付的提前,是每個開發多花 5% 的時間,去換取運維 200% 的勞動,並且提高穩定性。

而另一方面,本來運維只管交付資源,給你個虛擬機,虛擬機裏面的應用如何相互訪問我不管,你們愛咋地咋地,有了 Kubernetes 以後,運維層要關註服務發現,配置中心,熔斷降級。

兩者融合在了一起。在微服務化的研發的角度來講,Kubernetes 雖然復雜,但是設計的都是有道理的,符合微服務的思想。

三、微服務化的十個設計要點

微服務有哪些要點呢?第一張圖是 SpringCloud 的整個生態。

技術分享圖片

第二張圖是微服務的 12 要素以及在網易雲的實踐。

技術分享圖片

第三張圖是構建一個高並發的微服務,需要考慮的所有的點。(打個廣告,這是一門課程,即將上線。)

技術分享圖片

接下來細說微服務的設計要點。

設計要點一:API 網關。

技術分享圖片

在實施微服務的過程中,不免要面臨服務的聚合與拆分,當後端服務的拆分相對比較頻繁的時候,作為手機 App 來講,往往需要一個統一的入口,將不同的請求路由到不同的服務,無論後面如何拆分與聚合,對於手機端來講都是透明的。

有了 API 網關以後,簡單的數據聚合可以在網關層完成,這樣就不用在手機 App 端完成,從而手機 App 耗電量較小,用戶體驗較好。

有了統一的 API 網關,還可以進行統一的認證和鑒權,盡管服務之間的相互調用比較復雜,接口也會比較多,API 網關往往只暴露必須的對外接口,並且對接口進行統一的認證和鑒權,使得內部的服務相互訪問的時候,不用再進行認證和鑒權,效率會比較高。

有了統一的 API 網關,可以在這一層設定一定的策略,進行 A/B 測試,藍綠發布,預發環境導流等等。API 網關往往是無狀態的,可以橫向擴展,從而不會成為性能瓶頸。

設計要點二:無狀態化,區分有狀態的和無狀態的應用。

技術分享圖片

影響應用遷移和橫向擴展的重要因素就是應用的狀態,無狀態服務,是要把這個狀態往外移,將 Session 數據,文件數據,結構化數據保存在後端統一的存儲中,從而應用僅僅包含商務邏輯。

狀態是不可避免的,例如 ZooKeeper, DB,Cache 等,把這些所有有狀態的東西收斂在一個非常集中的集群裏面。

整個業務就分兩部分,一個是無狀態的部分,一個是有狀態的部分。

無狀態的部分能實現兩點,一是跨機房隨意地部署,也即遷移性,一是彈性伸縮,很容易地進行擴容。

有狀態的部分,如 DB,Cache,ZooKeeper 有自己的高可用機制,要利用到他們自己高可用的機制來實現這個狀態的集群。

雖說無狀態化,但是當前處理的數據,還是會在內存裏面的,當前的進程掛掉數據,肯定也是有一部分丟失的,為了實現這一點,服務要有重試的機制,接口要有冪等的機制,通過服務發現機制,重新調用一次後端服務的另一個實例就可以了。

設計要點三:數據庫的橫向擴展。

技術分享圖片

數據庫是保存狀態,是最重要的也是最容易出現瓶頸的。有了分布式數據庫可以使數據庫的性能可以隨著節點增加線性地增加。

分布式數據庫最最下面是 RDS,是主備的,通過 MySql 的內核開發能力,我們能夠實現主備切換數據零丟失,所以數據落在這個 RDS 裏面,是非常放心的,哪怕是掛了一個節點,切換完了以後,你的數據也是不會丟的。

再往上就是橫向怎麽承載大的吞吐量的問題,上面有一個負載均衡 NLB,用 LVS,HAProxy, Keepalived,下面接了一層 Query Server。Query Server 是可以根據監控數據進行橫向擴展的,如果出現了故障,可以隨時進行替換的修復,對於業務層是沒有任何感知的。

另外一個就是雙機房的部署,DDB 開發了一個數據運河 NDC 的組件,可以使得不同的 DDB 之間在不同的機房裏面進行同步,這時候不但在一個數據中心裏面是分布式的,在多個數據中心裏面也會有一個類似雙活的一個備份,高可用性有非常好的保證。

設計要點四:緩存

技術分享圖片

在高並發場景下緩存是非常重要的。要有層次的緩存,使得數據盡量靠近用戶。數據越靠近用戶能承載的並發量也越大,響應時間越短。

在手機客戶端 App 上就應該有一層緩存,不是所有的數據都每時每刻從後端拿,而是只拿重要的,關鍵的,時常變化的數據。

尤其對於靜態數據,可以過一段時間去取一次,而且也沒必要到數據中心去取,可以通過 CDN,將數據緩存在距離客戶端最近的節點上,進行就近下載。

有時候 CDN 裏面沒有,還是要回到數據中心去下載,稱為回源,在數據中心的最外層,我們稱為接入層,可以設置一層緩存,將大部分的請求攔截,從而不會對後臺的數據庫造成壓力。

如果是動態數據,還是需要訪問應用,通過應用中的商務邏輯生成,或者去數據庫讀取,為了減輕數據庫的壓力,應用可以使用本地的緩存,也可以使用分布式緩存,如 Memcached 或者 Redis,使得大部分請求讀取緩存即可,不必訪問數據庫。

當然動態數據還可以做一定的靜態化,也即降級成靜態數據,從而減少後端的壓力。

設計要點五:服務拆分和服務發現

技術分享圖片

當系統扛不住,應用變化快的時候,往往要考慮將比較大的服務拆分為一系列小的服務。

這樣第一個好處就是開發比較獨立,當非常多的人在維護同一個代碼倉庫的時候,往往對代碼的修改就會相互影響,常常會出現我沒改什麽測試就不通過了,而且代碼提交的時候,經常會出現沖突,需要進行代碼合並,大大降低了開發的效率。

另一個好處就是上線獨立,物流模塊對接了一家新的快遞公司,需要連同下單一起上線,這是非常不合理的行為,我沒改還要我重啟,我沒改還讓我發布,我沒改還要我開會,都是應該拆分的時機。

另外再就是高並發時段的擴容,往往只有最關鍵的下單和支付流程是核心,只要將關鍵的交易鏈路進行擴容即可,如果這時候附帶很多其他的服務,擴容即是不經濟的,也是很有風險的。

再就是容災和降級,在大促的時候,可能需要犧牲一部分的邊角功能,但是如果所有的代碼耦合在一起,很難將邊角的部分功能進行降級。

當然拆分完畢以後,應用之間的關系就更加復雜了,因而需要服務發現的機制,來管理應用相互的關系,實現自動的修復,自動的關聯,自動的負載均衡,自動的容錯切換。

設計要點六:服務編排與彈性伸縮

技術分享圖片

當服務拆分了,進程就會非常的多,因而需要服務編排來管理服務之間的依賴關系,以及將服務的部署代碼化,也就是我們常說的基礎設施即代碼。這樣對於服務的發布,更新,回滾,擴容,縮容,都可以通過修改編排文件來實現,從而增加了可追溯性,易管理性,和自動化的能力。

既然編排文件也可以用代碼倉庫進行管理,就可以實現一百個服務中,更新其中五個服務,只要修改編排文件中的五個服務的配置就可以,當編排文件提交的時候,代碼倉庫自動觸發自動部署升級腳本,從而更新線上的環境,當發現新的環境有問題時,當然希望將這五個服務原子性地回滾,如果沒有編排文件,需要人工記錄這次升級了哪五個服務。有了編排文件,只要在代碼倉庫裏面 revert,就回滾到上一個版本了。所有的操作在代碼倉庫裏都是可以看到的。

設計要點七:統一配置中心

技術分享圖片

服務拆分以後,服務的數量非常多,如果所有的配置都以配置文件的方式放在應用本地的話,非常難以管理,可以想象當有幾百上千個進程中有一個配置出現了問題,是很難將它找出來的,因而需要有統一的配置中心,來管理所有的配置,進行統一的配置下發。

在微服務中,配置往往分為幾類,一類是幾乎不變的配置,這種配置可以直接打在容器鏡像裏面,第二類是啟動時就會確定的配置,這種配置往往通過環境變量,在容器啟動的時候傳進去,第三類就是統一的配置,需要通過配置中心進行下發,例如在大促的情況下,有些功能需要降級,哪些功能可以降級,哪些功能不能降級,都可以在配置文件中統一配置。

設計要點八:統一的日誌中心

技術分享圖片

同樣是進程數目非常多的時候,很難對成千上百個容器,一個一個登錄進去查看日誌,所以需要統一的日誌中心來收集日誌,為了使收集到的日誌容易分析,對於日誌的規範,需要有一定的要求,當所有的服務都遵守統一的日誌規範的時候,在日誌中心就可以對一個交易流程進行統一的追溯。例如在最後的日誌搜索引擎中,搜索交易號,就能夠看到在哪個過程出現了錯誤或者異常。

設計要點九:熔斷,限流,降級

技術分享圖片

服務要有熔斷,限流,降級的能力,當一個服務調用另一個服務,出現超時的時候,應及時返回,而非阻塞在那個地方,從而影響其他用戶的交易,可以返回默認的托底數據。

當一個服務發現被調用的服務,因為過於繁忙,線程池滿,連接池滿,或者總是出錯,則應該及時熔斷,防止因為下一個服務的錯誤或繁忙,導致本服務的不正常,從而逐漸往前傳導,導致整個應用的雪崩。

當發現整個系統的確負載過高的時候,可以選擇降級某些功能或某些調用,保證最重要的交易流程的通過,以及最重要的資源全部用於保證最核心的流程。

還有一種手段就是限流,當既設置了熔斷策略,又設置了降級策略,通過全鏈路的壓力測試,應該能夠知道整個系統的支撐能力,因而就需要制定限流策略,保證系統在測試過的支撐能力範圍內進行服務,超出支撐能力範圍的,可拒絕服務。當你下單的時候,系統彈出對話框說 “系統忙,請重試”,並不代表系統掛了,而是說明系統是正常工作的,只不過限流策略起到了作用。

設計要點十:全方位的監控

技術分享圖片

當系統非常復雜的時候,要有統一的監控,主要有兩個方面,一個是是否健康,一個是性能瓶頸在哪裏。當系統出現異常的時候,監控系統可以配合告警系統,及時地發現,通知,幹預,從而保障系統的順利運行。

當壓力測試的時候,往往會遭遇瓶頸,也需要有全方位的監控來找出瓶頸點,同時能夠保留現場,從而可以追溯和分析,進行全方位的優化。

四、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 的使用方式,詳見這篇文章:微服務化的不同階段 Kubernetes 的不同玩法

為什麽 kubernetes 天然適合微服務