最近在反思,為什么在支撐容器平臺和微服務的競爭中,Kubernetes會取得最終的勝出。因為在很多角度來講三大容器平臺從功能角度來說,最后簡直是一摸一樣,具體的比較可以參考本人前面的兩篇文章。
《Docker, Kubernetes, DCOS 不談信仰談技術》
《容器平臺選型的十大模式: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的使用方式。
第一階段:使用公有云虛擬機
也即沒有微服務化的階段,基本上一個進程就能搞定,兩個進程做高可用,不需要使用容器,虛擬機就非常好。
第二階段:容器作為持續集成工具
當微服務開始拆分了,如何保證拆分后功能的一致性,需要持續集成作為保證,如前面的論述,容器是非常好的持續集成工具,是解決CI/CD中D的,所以一開始用host網絡就可以,這樣可以保證部署方式和原來兼容。
如果想用私有云進行部署,直接部署在物理機上,在性能要求沒有很高,但是又要和其他物理機很好的通信的情況下,可以用bridge打平網絡的方式比較好。通過創建網橋,將物理網卡,容器網卡都連接到一個網橋上,可以實現所有的容器和物理機在同樣的一個二層網絡里面。
如果性能要求比較高,例如要部署類似緩存,則可以使用sr-iov網卡。
如果想實現租戶的簡單隔離,則往往使用各種Overlay的網絡模式,這是最常用的部署方式。圖中的數據來自網絡。Flannel,Calico都是非常好的網絡插件,雖然Flannel一開始使用用戶態的模式性能不好,后來使用內核態,性能大大改善,使用gw模式后,和Calico性能相當。
網易云采用了Kubernetes和IaaS深度融合的方式,類似AWS的Fargate的模式,一方面可以使得原來使用虛擬機的用戶平滑地遷移到容器,另一方面可以實現公有云的租戶隔離。
如圖是融合的網易云容器服務的架構,這個管理OpenStack和Kubernetes的管理平臺,也是用的微服務架構,有API網關,熔斷限流功能,拆分成不同的服務,部署在K8S上的,所以處處是微服務。