Kubernetes API 与 Operator,不为人知的开发者战争
如果我問(wèn)你,如何把一個(gè) etcd 集群部署在 Google Cloud 或者阿里云上,你一定會(huì)不假思索的給出答案:當(dāng)然是用 etcd Operator!
實(shí)際上,幾乎在一夜之間,Kubernetes Operator 這個(gè)新生事物,就成了開(kāi)發(fā)和部署分布式應(yīng)用的一項(xiàng)事實(shí)標(biāo)準(zhǔn)。時(shí)至今日,無(wú)論是 etcd、TiDB、Redis,還是 Kafka、RocketMQ、Spark、TensorFlow,幾乎每一個(gè)你能叫上名字來(lái)的分布式項(xiàng)目,都由官方維護(hù)著各自的 Kubernetes Operator。而 Operator 官方庫(kù)里,也一直維護(hù)著一個(gè)知名分布式項(xiàng)目的 Operator 匯總。
https://github.com/operator-framework/awesome-operators
短短一年多時(shí)間,這個(gè)列表的長(zhǎng)度已經(jīng)增長(zhǎng)了幾十倍。?
而且更有意思的是,如果你仔細(xì)翻閱這個(gè) Operator 列表,你就不難發(fā)現(xiàn)這樣一個(gè)有趣的事實(shí):現(xiàn)今 Kubernetes Operator 的意義,恐怕已經(jīng)遠(yuǎn)遠(yuǎn)超過(guò)了“分布式應(yīng)用部署”的這個(gè)原始的范疇,而已然成為了容器化時(shí)代應(yīng)用開(kāi)發(fā)與發(fā)布的一個(gè)全新途徑。所以,你才會(huì)在這個(gè)列表里看到,Android SDK 的開(kāi)發(fā)者們,正在使用 Operator “一鍵”生成和更新 Android 開(kāi)發(fā)環(huán)境;而 Linux 系統(tǒng)工程師們,則在使用Operator “一鍵”重現(xiàn)性能測(cè)試集群。
如果說(shuō),Docker 鏡像的提出,完成了應(yīng)用靜態(tài)描述的標(biāo)準(zhǔn)化。那么 Kubernetes Operator 的出現(xiàn),終于為應(yīng)用的動(dòng)態(tài)描述提出了一套行之有效的實(shí)現(xiàn)規(guī)范。更為重要的是,對(duì)于 TiDB、Kafka、RocketMQ 等分布式應(yīng)用的開(kāi)發(fā)者來(lái)說(shuō),這些應(yīng)用運(yùn)行起來(lái)之后的動(dòng)態(tài)描述,才是對(duì)一個(gè)分布式應(yīng)用真正有意義的信息。
而在此之前,用戶如果要想將 TiDB、Kafka 這樣的分布式應(yīng)用很好的使用起來(lái),就不得不去嘗試編寫(xiě)一套復(fù)雜的管理腳本,甚至為此學(xué)習(xí)大量與項(xiàng)目本身無(wú)關(guān)的運(yùn)維知識(shí)。更為麻煩的是,這些腳本、知識(shí)、和經(jīng)驗(yàn),并沒(méi)有一個(gè)很好的辦法能夠有效的沉淀下來(lái)。而任何一種技術(shù)的傳授,如果嚴(yán)重依賴于口口相傳而不是固化的代碼和邏輯的話,那么它的維護(hù)成本和使用門(mén)檻,就可以說(shuō)是“災(zāi)難級(jí)”的。
所以說(shuō),Kubernetes Operator 發(fā)布之初最大的意義,就在于它將分布式應(yīng)用的使用門(mén)檻直接降到了最低。
那么這個(gè)門(mén)檻具體有多低呢?
一般來(lái)說(shuō),無(wú)論這個(gè)分布式應(yīng)用項(xiàng)目有多復(fù)雜,只要它為用戶提供了 Operator,那么這個(gè)項(xiàng)目的使用就只需要兩條命令即可搞定,以 Kafka 為例:
這兩條命令執(zhí)行完成后,一個(gè) Kafka 集群運(yùn)行所需的節(jié)點(diǎn),以及它們所依賴的 ZooKeeper 節(jié)點(diǎn),就會(huì)以容器的方式自動(dòng)出現(xiàn)在你的 Kubernetes 集群里了。
不過(guò),簡(jiǎn)化運(yùn)維和部署,其實(shí)只是 Operator 在用戶層面的表象。而在更底層的技術(shù)層面,Operator 最大的價(jià)值,在于它為“容器究竟能不能管理有狀態(tài)應(yīng)用”這個(gè)頗具爭(zhēng)議話題,畫(huà)上了一個(gè)優(yōu)雅的句號(hào)。
要知道,在2014-2015年的時(shí)候,伴隨著 Docker 公司和 Docker 項(xiàng)目的走紅,整個(gè)云計(jì)算生態(tài)幾乎都陷入了名為“容器”的狂熱當(dāng)中。然而,相比于 “容器化”浪潮的如火如荼,這個(gè)圈子卻始終對(duì)“有狀態(tài)應(yīng)用”諱莫如深。
事實(shí)上,有狀態(tài)應(yīng)用(比如, 前面提到的Kafka )跟無(wú)狀態(tài)應(yīng)用(比如,一個(gè)簡(jiǎn)單的Jave Web網(wǎng)站)的不同之處,就在于前者對(duì)某些外部資源有著綁定性的依賴,比如遠(yuǎn)程存儲(chǔ),或者網(wǎng)絡(luò)設(shè)備,以及,有狀態(tài)應(yīng)用的多個(gè)示例之間往往有著拓?fù)潢P(guān)系。這兩種設(shè)計(jì),在軟件工程的世界里可以說(shuō)再普通不過(guò)了,而且我們幾乎可以下這樣一個(gè)結(jié)論:所有的分布式應(yīng)用都是有狀態(tài)應(yīng)用。
但是,在容器的世界里,分布式應(yīng)用卻成了一個(gè)“異類”。我們知道,容器的本質(zhì),其實(shí)就是一個(gè)被限制了“世界觀”的進(jìn)程。在這種隔離和限制的大基調(diào)下,容器技術(shù)本身的“人格基因”,就是對(duì)外部世界(即:宿主機(jī))的“視而不見(jiàn)”和“充耳不聞”。所以我們經(jīng)常說(shuō),容器的“狀態(tài)”一定是“易失”的。其實(shí),容器對(duì)它的“小世界”之外的狀態(tài)和數(shù)據(jù)漠不關(guān)心,正是這種“隔離性”的主要體現(xiàn)。
但狀態(tài)“易失”并不能說(shuō)是容器的缺陷:我們既然對(duì)容器可以重現(xiàn)完整的應(yīng)用執(zhí)行環(huán)境的“一致性”拍手稱贊,那就必然要對(duì)這種能力背后的限制了然于心。這種默契,也正是早期的 Docker 公司所向披靡的重要背景:在這個(gè)階段,相比于“容器化”的巨大吸引力,開(kāi)發(fā)者是可以暫時(shí)接受一部分應(yīng)用不能運(yùn)行在容器里的。
而分布式應(yīng)用容器化的困境,其實(shí)就在于它成為了這種“容器化”默契的“終極破壞者”。
一個(gè)應(yīng)用本身可以擁有多個(gè)可擴(kuò)展的實(shí)例,這本來(lái)是容器化應(yīng)用令人津津樂(lè)道的一個(gè)優(yōu)勢(shì)。但是一旦這些實(shí)例像分布式應(yīng)用這樣具有了拓?fù)潢P(guān)系,以及,這些實(shí)例本身不完全等價(jià)的時(shí)候,容器化的解決方案就再次變得“丑陋”起來(lái):這種情況下,應(yīng)用開(kāi)發(fā)者們不僅又要為這些容器實(shí)例編寫(xiě)一套難以維護(hù)的管理腳本,還必須要想辦法應(yīng)對(duì)容器重啟后狀態(tài)丟失的難題。而這些容器狀態(tài)的維護(hù),實(shí)際上往往需要打破容器的隔離性、讓容器對(duì)外部世界有所感知才能做到,這就使得容器化與有狀態(tài),成為了兩種完全相悖的需求。
不過(guò),從上面的敘述中相信你也應(yīng)該已經(jīng)察覺(jué)到,分布式應(yīng)用容器化的難點(diǎn),并不在于容器本身有什么重大缺陷,而在于我們一直以來(lái)缺乏一種對(duì)“狀態(tài)”的合理的抽象與描述,使得狀態(tài)可以和容器進(jìn)程本身解耦開(kāi)來(lái)。這也就解釋了為什么,在 Kubernetes 這樣的外部編排框架逐漸成熟起了之后,業(yè)界才逐漸對(duì)有狀態(tài)應(yīng)用管理開(kāi)始有了比較清晰的理解和認(rèn)識(shí)。
而我們知道, Kubernetes 項(xiàng)目最具價(jià)值的理念,就是它圍繞 etcd 構(gòu)建出來(lái)的一套“面向終態(tài)”編排體系,這套體系在開(kāi)源社區(qū)里,就是大名鼎鼎的“聲明式 API”。
“聲明式 API”的核心原理,就是當(dāng)用戶向 Kubernetes 提交了一個(gè) API 對(duì)象的描述之后,Kubernetes 會(huì)負(fù)責(zé)為你保證整個(gè)集群里各項(xiàng)資源的狀態(tài),都與你的 API 對(duì)象描述的需求相一致。更重要的是,這個(gè)保證是一項(xiàng)“無(wú)條件的”、“沒(méi)有期限”的承諾:對(duì)于每個(gè)保存在 etcd 里的 API 對(duì)象,Kubernetes 都通過(guò)啟動(dòng)一種叫做“控制器模式”(Controller Pattern)的無(wú)限循環(huán),不斷檢查,然后調(diào)諧,最后確保整個(gè)集群的狀態(tài)與這個(gè) API 對(duì)象的描述一致。
比如,你提交的 API 對(duì)象是一個(gè)應(yīng)用,描述的是這個(gè)應(yīng)用必須有三個(gè)實(shí)例,那么無(wú)論接下來(lái)你的 API 對(duì)象發(fā)生任何“風(fēng)吹草動(dòng)”,控制器都會(huì)檢查一遍這個(gè)集群里是不是真的有三個(gè)應(yīng)用實(shí)例在運(yùn)行。并且,它會(huì)根據(jù)這次檢查的結(jié)果來(lái)決定,是不是需要對(duì)集群做某些操作來(lái)完成這次“調(diào)諧”過(guò)程。當(dāng)然,這里控制器正是依靠 etcd 的 Watch API 來(lái)實(shí)現(xiàn)對(duì) API 對(duì)象變化的感知的。在整個(gè)過(guò)程中,你提交的 API 對(duì)象就是 Kubernetes 控制器眼中的“金科玉律”,是接下來(lái)控制器執(zhí)行調(diào)諧邏輯要達(dá)到的唯一狀態(tài)。這就是我們所說(shuō)的“終態(tài)”的含義。
而 Operator 的設(shè)計(jì),其實(shí)就是把這個(gè)“控制器”模式的思想,貫徹的更加徹底。在 Operator 里,你提交的 API 對(duì)象不再是一個(gè)單體應(yīng)用的描述,而是一個(gè)完整的分布式應(yīng)用集群的描述。這里的區(qū)別在于,整個(gè)分布式應(yīng)用集群的狀態(tài)和定義,都成了Kubernetes 控制器需要保證的“終態(tài)”。比如,這個(gè)應(yīng)用有幾個(gè)實(shí)例,實(shí)例間的關(guān)系如何處理,實(shí)例需要把數(shù)據(jù)存儲(chǔ)在哪里,如何對(duì)實(shí)例數(shù)據(jù)進(jìn)行備份和恢復(fù),都是這個(gè)控制器需要根據(jù) API 對(duì)象的變化進(jìn)行處理的邏輯。
從上述敘述中,你就應(yīng)該能夠明白, Operator 其實(shí)就是一段代碼,這段代碼 Watch 了 etcd 里一個(gè)描述分布式應(yīng)用集群的API 對(duì)象,然后這段代碼通過(guò)實(shí)現(xiàn) Kubernetes 的控制器模式,來(lái)保證這個(gè)集群始終跟用戶的定義完全相同。而在這個(gè)過(guò)程中,Operator 也有能力利用 Kubernetes 的存儲(chǔ)、網(wǎng)絡(luò)插件等外部資源,協(xié)同的為應(yīng)用狀態(tài)的保持提供幫助。
所以說(shuō),Operator 本身在實(shí)現(xiàn)上,其實(shí)是在 Kubernetes 聲明式 API 基礎(chǔ)上的一種“微創(chuàng)新”。它合理的利用了 Kubernetes API 可以添加自定義 API 類型的能力,然后又巧妙的通過(guò) Kubernetes 原生的“控制器模式”,完成了一個(gè)面向分布式應(yīng)用終態(tài)的調(diào)諧過(guò)程。
而 Operator 本身在用法上,則是一個(gè)需要用戶大量編寫(xiě)代碼的的開(kāi)發(fā)者工具。 不過(guò),這個(gè)編寫(xiě)代碼的過(guò)程,并沒(méi)有像很多人當(dāng)初料想的那樣導(dǎo)致 Operator 項(xiàng)目走向小眾,反而在短短三年的時(shí)間里, Operator 就迅速成為了容器化分布式應(yīng)用管理的事實(shí)標(biāo)準(zhǔn)。時(shí)至今日,Operator 項(xiàng)目的生態(tài)地位已經(jīng)毋庸置疑。就在剛剛結(jié)束的2018年 KubeCon 北美峰會(huì)上,Operator 項(xiàng)目和大量的用戶案例一次又一次出現(xiàn)在聚光燈前,不斷的印證著這個(gè)小小的“微創(chuàng)新”對(duì)整個(gè)云計(jì)算社區(qū)所產(chǎn)生的深遠(yuǎn)影響。
不過(guò),在 Operator 項(xiàng)目引人矚目的成長(zhǎng)經(jīng)歷背后,你是否考慮過(guò)這樣一個(gè)問(wèn)題:
Kubernetes 項(xiàng)目一直以來(lái),其實(shí)都內(nèi)置著一個(gè)管理有狀態(tài)應(yīng)用的能力叫作 StatefulSet。而如果你稍微了解 Kubernetes 項(xiàng)目的話就不難發(fā)現(xiàn),Operator 和 StatefulSet,雖然在對(duì)應(yīng)用狀態(tài)的抽象上有所不同,但它們的設(shè)計(jì)原理,幾乎是完全一致的,即:這兩種機(jī)制的本質(zhì),都是圍繞Kubernetes API 對(duì)象的“終態(tài)”進(jìn)行調(diào)諧的一個(gè)控制器(Controller)而已。
可是,為什么在一個(gè)開(kāi)源社區(qū)里,會(huì)同時(shí)存在這樣的兩個(gè)核心原理完全一致、設(shè)計(jì)目標(biāo)也幾乎相同的有狀態(tài)應(yīng)用管理方案呢?作為 CoreOS 公司后來(lái)廣為人知的“左膀右臂”之一(即:etcd 和 Operator),Operator 項(xiàng)目能夠在 Kubernetes 生態(tài)里爭(zhēng)取到今天的位置,是不是也是 CoreOS 公司的開(kāi)源戰(zhàn)略使然呢?
事實(shí)上,Operator 項(xiàng)目并沒(méi)有像很多人想象的那樣出生就含著金鑰匙。只不過(guò),在當(dāng)時(shí)的確沒(méi)有人能想到,當(dāng) CoreOS 的兩名工程師帶著一個(gè)業(yè)余項(xiàng)目從一間平淡無(wú)奇的公寓走出后不久,一場(chǎng)圍繞著 Kubernetes API 生態(tài)、以爭(zhēng)奪“分布式應(yīng)用開(kāi)發(fā)者”為核心的的重量級(jí)角逐,就徐徐拉開(kāi)了序幕。
2016 年秋天,原 CoreOS 公司的工程師鄧洪超像往常一樣,來(lái)到了同事位于福斯特城(Foster City)的公寓進(jìn)行結(jié)對(duì)編程。每周四相約在這里結(jié)對(duì),是這兩位工程師多年來(lái)約定俗成的慣例。
↑CoreOS 當(dāng)年開(kāi)發(fā) etcd 所在的車(chē)庫(kù)
不過(guò),與以往不同的是,相比于往常天馬行空般的頭腦風(fēng)暴,這一次,這兩位工程師的腦子里正在琢磨著的,是一個(gè)非常“接地氣”的小項(xiàng)目。
我們知道,Kubernetes 項(xiàng)目實(shí)現(xiàn)“容器編排”的核心,在于一個(gè)叫做“控制器模式”的機(jī)制,即:通過(guò)對(duì) etcd 里的 API 對(duì)象的變化進(jìn)行監(jiān)視(Watch),Kubernetes 項(xiàng)目就可以在一個(gè)叫做 Controller 的組件里對(duì)這些變化進(jìn)行響應(yīng)。而無(wú)論是 Pod 等應(yīng)用對(duì)象,還是 iptables、存儲(chǔ)設(shè)備等服務(wù)對(duì)象,任何一個(gè) API 對(duì)象發(fā)生變化,那么 Kubernetes 接下來(lái)需要執(zhí)行的響應(yīng)邏輯,就是對(duì)應(yīng)的 Controller 里定義的編排動(dòng)作。
所以,一個(gè)自然而然的想法就是,作為 Kubernetes 項(xiàng)目的用戶,我能不能自己編寫(xiě)一個(gè) Controller 來(lái)定義我所期望的編排動(dòng)作呢?比如:當(dāng)一個(gè) Pod 對(duì)象被更新的時(shí)候,我的 Controller 可以在“原地”對(duì) Pod 進(jìn)行“重啟”,而不是像 Deployment 那樣必須先刪除 Pod,然后再創(chuàng)建 Pod。
這個(gè)想法,其實(shí)是很多應(yīng)用開(kāi)發(fā)者以及 PaaS 用戶的強(qiáng)烈需求,也是一直以來(lái)縈繞在 CoreOS 公司 CEO Alex Polvi 腦海里的一個(gè)念頭。而在一次簡(jiǎn)單的內(nèi)部討論提及之后,這個(gè)念頭很快就激發(fā)出了兩位工程師的技術(shù)靈感,成為了周四結(jié)對(duì)編程的新主題。
而這一次,他們決定把這個(gè)小項(xiàng)目,起名叫做:Operator。
所以顧名思義,Operator 這個(gè)項(xiàng)目最開(kāi)始的初衷,是用來(lái)幫助開(kāi)發(fā)者實(shí)現(xiàn)運(yùn)維(Operate)能力的。但 Operator 的核心思想,卻并不是“替開(kāi)發(fā)者做運(yùn)維工作”,而是“讓開(kāi)發(fā)者自己編寫(xiě)運(yùn)維工具”。更有意思的是,這個(gè)運(yùn)維工具的編寫(xiě)標(biāo)準(zhǔn),或者說(shuō),編寫(xiě) Operator 代碼可以參考的模板,正是 Kubernetes 的“控制器模式(Controller Pattern)”。
前面已經(jīng)說(shuō)過(guò), Kubernetes 的“控制器模式”,是圍繞著比如 Pod 這樣的 API 對(duì)象,在 Controller 通過(guò)響應(yīng)它的增刪改查來(lái)定義對(duì) Pod 的編排動(dòng)作。
而 Operator 的設(shè)計(jì)思路,就是允許開(kāi)發(fā)者在 Kubernetes 里添加一個(gè)新的 API 對(duì)象,用來(lái)描述一個(gè)分布式應(yīng)用的集群。然后,在這個(gè) API 對(duì)象的 Controller 里,開(kāi)發(fā)者就可以定義對(duì)這個(gè)分布式應(yīng)用集群的運(yùn)維動(dòng)作了。
舉個(gè)例子, 假設(shè)下面這個(gè) YAML 文件定義的,是一個(gè) 3 節(jié)點(diǎn) etcd 集群的描述:
有了這樣一個(gè) etcdCluster 對(duì)象,那么開(kāi)發(fā)者接下來(lái)要做的事情,就是編寫(xiě)一個(gè) etcdCluster Controller,使得當(dāng)任何用戶提交這樣一個(gè) YAML 文件給 Kubernetes 之后,我們自己編寫(xiě)的 Controller 就會(huì)響應(yīng) etcdCluster “增加”事件,為用戶創(chuàng)建出 3 個(gè)節(jié)點(diǎn)的 etcd 集群出來(lái)。然后,它還會(huì)按照我們?cè)?Controller 編寫(xiě)的事件響應(yīng)邏輯,自動(dòng)的對(duì)這個(gè)集群的節(jié)點(diǎn)更新、刪除等事件做出處理,執(zhí)行我定義的其他運(yùn)維功能。像這樣一個(gè) etcdCluster Controller,就是 etcd Operator 的核心組成部分了。
而作為 etcd 的開(kāi)發(fā)者,CoreOS 的兩位工程師把對(duì) etcd 集群的運(yùn)維工作編寫(xiě)成 Go 語(yǔ)言代碼,一點(diǎn)都不困難。可是,要完成這個(gè) Operator 真正困難在于:Kubernetes 只認(rèn)識(shí) Pod、Node、Service 等這些 Kubernetes 自己原生的 API 對(duì)象,它怎么可能認(rèn)識(shí)開(kāi)發(fā)者自己定義的這個(gè) etcdCluster 對(duì)象呢?
在當(dāng)時(shí), Kubernetes 項(xiàng)目允許用戶自己添加 API 對(duì)象的插件能力,叫做 Third Party Resource,簡(jiǎn)稱:TPR。
TPR 允許你提交一個(gè) YAML 文件,來(lái)定義你想要的的新 API 對(duì)象的名字,比如:etcdCluster;也允許你定義這個(gè)對(duì)象允許的合法的屬性,比如:int 格式的 size 字段, string 格式的 version 字段。然后,你就可以提交一個(gè)具體的 etcdCluster 對(duì)象的描述文件給 Kubernetes,等待該對(duì)應(yīng)的 Controller 進(jìn)行處理。
而這個(gè) Controller,就是 Operator 的主干代碼了。
所以接下來(lái),CoreOS 的兩位工程師輕車(chē)熟路,在 Operator 里對(duì) etcdCluster 對(duì)象的增、刪、改事件的響應(yīng)位置,寫(xiě)上了創(chuàng)建、刪除、更新 etcd 節(jié)點(diǎn)的操作邏輯。然后,調(diào)試運(yùn)行,看著一個(gè) etcd 集群按照 YAML 文件里的描述被創(chuàng)建起來(lái)。大功告成!
就這樣,在一個(gè)普通的周四下午,世界上第一個(gè) Operator 誕生在了灣區(qū)的一所公寓當(dāng)中。
而對(duì)于 CoreOS 的兩位工程師來(lái)說(shuō),編寫(xiě)這個(gè)小工具的主要目的,就是借助 Kubernetes 的核心原理來(lái)自動(dòng)化的管理 etcd 集群,更重要的是,不需要使用 Kubernetes 里自帶的 StatefulSet。
你可能已經(jīng)知道,Kubernetes 里本身就內(nèi)置了一個(gè)叫做 StatefulSet 的功能,是專門(mén)用來(lái)管理有狀態(tài)應(yīng)用的。而 StatefulSet 的核心原理,其實(shí)是對(duì)分布式應(yīng)用的兩種狀態(tài)進(jìn)行了保持:
- 分布式應(yīng)用的拓?fù)錉顟B(tài),或者說(shuō),節(jié)點(diǎn)之間的啟動(dòng)順序;
- 分布式應(yīng)用的存儲(chǔ)狀態(tài),或者說(shuō),每個(gè)節(jié)點(diǎn)依賴的持久化數(shù)據(jù)。
可是,為了能夠?qū)崿F(xiàn)上述兩種狀態(tài)的保持機(jī)制,StatefulSet 的設(shè)計(jì)就給應(yīng)用開(kāi)發(fā)者帶來(lái)了額外的束縛。
比如,etcd 集群各節(jié)點(diǎn)之間的拓?fù)潢P(guān)系,并不依賴于節(jié)點(diǎn)名字或者角色(比如 Master 或者 Slave)來(lái)確定,而是記錄在每個(gè) etcd 節(jié)點(diǎn)的啟動(dòng)參數(shù)當(dāng)中。這使得 StatefulSet 通過(guò)“為節(jié)點(diǎn)分配有序的 DNS 名字”的拓?fù)浔3址绞?#xff0c;實(shí)際上沒(méi)有了用武之地,反而還得要求開(kāi)發(fā)者在節(jié)點(diǎn)的啟動(dòng)命令里添加大量的邏輯來(lái)生成正確的啟動(dòng)命令,非常不優(yōu)雅。類似的,對(duì)于存儲(chǔ)狀態(tài)來(lái)說(shuō),etcd 集群對(duì)數(shù)據(jù)的備份和恢復(fù)方法,也跟 StatefulSet 依賴的的遠(yuǎn)程持久化數(shù)據(jù)卷方案并沒(méi)有太大關(guān)系。
不難看到, StatefulSet 其實(shí)比較適用于應(yīng)用本身節(jié)點(diǎn)管理能力不完善的項(xiàng)目,比如 MySQL。而對(duì)于 etcd 這種已經(jīng)借助 Raft 實(shí)現(xiàn)了自管理的分布式應(yīng)用來(lái)說(shuō), StatefulSet 的使用方法和帶來(lái)的各種限制,其實(shí)是非常別扭的。
而帶著工程師特有的較真兒精神,鄧洪超和他的同事借助 Kubernetes 原生的擴(kuò)展機(jī)制實(shí)現(xiàn)的,正是一個(gè)比 StatefulSet 更加靈活、能夠把控制權(quán)重新交還給開(kāi)發(fā)者的分布式應(yīng)用管理工具。他們把這個(gè)工具起名叫做 Operator,并在幾個(gè)月后的 KubeCon 上
進(jìn)行了一次 Demo ,推薦大家嘗試使用 Operator 來(lái)部署 etcd 集群。
沒(méi)有人能想到的是,這個(gè)當(dāng)時(shí)還處于 PoC 狀態(tài)的小項(xiàng)目一經(jīng)公布,就立刻激發(fā)起了整個(gè)社區(qū)的模仿和學(xué)習(xí)的熱潮。
很快,大量的應(yīng)用開(kāi)發(fā)者紛紛涌進(jìn) Kubernetes 社區(qū),爭(zhēng)先恐后的宣布自己的分布式項(xiàng)目可以通過(guò) Operator 運(yùn)行起來(lái)。而敏銳的公有云提供商們很快看出了這其中的端倪:Operator 這個(gè)小框架,已然成為了分布式應(yīng)用和有狀態(tài)應(yīng)用“上云”的必經(jīng)之路。Prometheus,Rook,伴隨著越來(lái)越多的、以往在容器里運(yùn)行起來(lái)困難重重的應(yīng)用,通過(guò) Operator 走上了 Kubernetes 之后,Kubernetes 項(xiàng)目第一次出現(xiàn)在了開(kāi)發(fā)者生態(tài)的核心位置。這個(gè)局面,已經(jīng)遠(yuǎn)遠(yuǎn)超出了鄧洪超甚至 CoreOS 公司自己的預(yù)期。
更重要的是,不同于 StatefulSet 等 Kubernetes 原生的編排概念,Operator 依賴的 Kubernetes 能力,只有最核心的聲明式 API 與控制器模式;Operator 具體的實(shí)現(xiàn)邏輯,則編寫(xiě)在自定義 Controller 的代碼中。這種設(shè)計(jì)給開(kāi)發(fā)者賦予了極高的自由度,這在整個(gè)云計(jì)算和 PaaS 領(lǐng)域的發(fā)展過(guò)程中,都是非常罕見(jiàn)的。
此外,相比于 Helm、Docker Compose 等描述應(yīng)用靜態(tài)關(guān)系的編排工具,Operator 定義的乃是應(yīng)用運(yùn)行起來(lái)后整個(gè)集群的動(dòng)態(tài)邏輯。得益于 Kubernetes 項(xiàng)目良好的聲明式 API 的設(shè)計(jì)和開(kāi)發(fā)者友好的 API 編程范式,Operator 在保證上述自由度的同時(shí),又可以始終如一的展現(xiàn)出清晰的架構(gòu)和設(shè)計(jì)邏輯,使得應(yīng)用的開(kāi)發(fā)者們,可以通過(guò)復(fù)制粘貼就快速搭建出一個(gè) Operator 的框架,然后專注于填寫(xiě)自己的業(yè)務(wù)邏輯。
在向來(lái)講究“用腳投票”的開(kāi)發(fā)者生態(tài)當(dāng)中,Operator 這樣一個(gè)編程友好、架構(gòu)清晰、方便代碼復(fù)制粘貼的小工具,本身就已經(jīng)具備了某些成功的特質(zhì)。
然而,Operator 的意外走紅,并沒(méi)有讓 CoreOS 公司“一夜成名”,反而差點(diǎn)將這個(gè)初出茅廬的項(xiàng)目,扼殺在萌芽狀態(tài)。
在當(dāng)時(shí)的 Kubernetes 社區(qū)里,跟應(yīng)用開(kāi)發(fā)者打交道并不是一個(gè)非常常見(jiàn)的事情。而 Operator 項(xiàng)目的誕生,卻把 Kubernetes 項(xiàng)目第一次拉近到了開(kāi)發(fā)者的面前,這讓整個(gè)社區(qū)感覺(jué)了不適應(yīng)。而作為 Kubernetes 項(xiàng)目 API 治理的負(fù)責(zé)人,Google 團(tuán)隊(duì)對(duì)這種沖突的感受最為明顯。
對(duì)于 Google 團(tuán)隊(duì)來(lái)說(shuō),Controller 以及控制器模式,應(yīng)該是一個(gè)隱藏在 Kubernetes 內(nèi)部實(shí)現(xiàn)里的核心機(jī)制,并不適合直接開(kāi)放給開(kāi)發(fā)者來(lái)使用。退一步說(shuō),即使開(kāi)放出去,這個(gè) Controller 的設(shè)計(jì)和用法,也應(yīng)該按照 Kubernetes 現(xiàn)有的 API 層規(guī)范來(lái)進(jìn)行,最好能成為 Kubernetes 內(nèi)置 Controller Manager 管理下的一部分。可是, Operator 卻把直接編寫(xiě) Controller 代碼的自由度完全交給了開(kāi)發(fā)者,成為了一個(gè)游離于 Kubernetes Controller Manager 之外的外部組件。
帶著這個(gè)想法,社區(qū)里的很多團(tuán)隊(duì)從 Operator 項(xiàng)目誕生一開(kāi)始,就對(duì)它的設(shè)計(jì)和演進(jìn)方向提出了質(zhì)疑,甚至建議將 Operator 的名字修改為 Custom Kubernetes Controller。而無(wú)巧不成書(shū),就在 Google 和 CoreOS 在 Controller 的話語(yǔ)權(quán)上爭(zhēng)執(zhí)不下的時(shí)候, Kubernetes 項(xiàng)目的發(fā)起人之一 Brendan Burns 突然宣布加入了微軟,這讓 Google 團(tuán)隊(duì)和 Operator 項(xiàng)目的關(guān)系一下子跌倒了冰點(diǎn)。
你可能會(huì)有些困惑:Brendan Burns 與 Kubernetes 的關(guān)系我是清楚的,但這跟 Operator 又有什么瓜葛嗎?
實(shí)際上,你可能很難想到,Brendan Burns 和他的團(tuán)隊(duì),才是 TPR (Third Party Resource)這個(gè)特性最初的發(fā)起人。
所以,幾乎在一夜之間,Operator 項(xiàng)目鏈路上的每一個(gè)環(huán)節(jié),都與 Google 團(tuán)隊(duì)完美的擦肩而過(guò)。眼睜睜的看著這個(gè)正冉冉升起的開(kāi)發(fā)者工具突然就跟自己完全沒(méi)了關(guān)系,這個(gè)中滋味,確實(shí)不太好受。
于是,在 2017年初,Google 團(tuán)隊(duì)和 RedHat 公司開(kāi)始主動(dòng)在社區(qū)推廣 UAS(User Aggregated APIServer),也就是后來(lái) APIServer Aggregator 的雛形。APIServer Aggregator 的設(shè)計(jì)思路是允許用戶編寫(xiě)一個(gè)自定義的 APIServer,在這里面添加自定義 API。然后,這個(gè) APIServer 就可以跟 Kubernetes 原生的 APIServer 綁定部署在一起統(tǒng)一提供服務(wù)了。不難看到,這個(gè)設(shè)計(jì)與 Google 團(tuán)隊(duì)認(rèn)為自定義 API 必須在 Kubernetes 現(xiàn)有框架下進(jìn)行管理的想法還是比較一致的。
緊接著,RedHat 和 Google 聯(lián)盟開(kāi)始游說(shuō)社區(qū)使用 UAS 機(jī)制取代 TPR,并且建議直接從 Kubernetes 項(xiàng)目里廢棄 TPR 這個(gè)功能。一時(shí)間,社區(qū)里謠言四起,不少已經(jīng)通過(guò) TPR 實(shí)現(xiàn)的項(xiàng)目,也開(kāi)始轉(zhuǎn)而使用 UAS 來(lái)重構(gòu)以求自保。 而 Operator 這個(gè)嚴(yán)重依賴于 TPR 的小項(xiàng)目,還沒(méi)來(lái)得及發(fā)展壯大,就被推向了關(guān)閉的邊緣。
面對(duì)幾乎要與社區(qū)背道而馳的困境,CoreOS 公司的 CTO Brandon Philips 做出了一個(gè)大膽的決定:讓社區(qū)里的所有開(kāi)發(fā)者發(fā)聲,挽救 TPR 和 Operator。
2017 年 2月,Brandon Philips 在 GitHub 上開(kāi)了一個(gè)帖子(Gist), 號(hào)召所有使用 TPR 或者 Operator 項(xiàng)目的開(kāi)發(fā)者在這里留下的自己的項(xiàng)目鏈接或者描述。這個(gè)帖子,迅速的成為了當(dāng)年容器技術(shù)圈最熱門(mén)的事件之一,登上了 HackerNews 的頭條。有趣的是,這個(gè)帖子直到今天也仍然健在,甚至還在被更新,你可以點(diǎn)擊這個(gè)鏈接去感受一下當(dāng)時(shí)的盛況。https://gist.github.com/philips/a97a143546c87b86b870a82a753db14c
而伴隨著 Kubernetes 項(xiàng)目的迅速崛起,短短一年時(shí)間不到,夾縫中求生存的 Operator 項(xiàng)目,開(kāi)始對(duì)公有云市場(chǎng)產(chǎn)生了不可逆轉(zhuǎn)的影響,也逐步改變了開(kāi)發(fā)者們對(duì)“云”以及云上應(yīng)用開(kāi)發(fā)模式的基本認(rèn)知。甚至就連 Google Cloud 自己最大的客戶之一 Snapchat ,也成為了 Operator 項(xiàng)目的忠實(shí)用戶。在來(lái)自社區(qū)的巨大壓力下,在這個(gè)由成千上萬(wàn)開(kāi)發(fā)者們自發(fā)維護(hù)起來(lái)的 Operator 生態(tài)面前,Google 和 RedHat 公司最終選擇了反省和退讓。
有意思的是,這個(gè)退讓的結(jié)果,再一次為這次鬧劇增添了幾分戲劇性。
就在 Brandon Phillips 的開(kāi)發(fā)者搜集帖發(fā)布了不到三個(gè)月后,RedHat 和 Google 公司的工程師突然在 Kubernetes 社區(qū)里宣布:TPR 即將被廢棄,取而代之的是一個(gè)名叫 CRD,Custom Resource Definition 的東西。
于是,開(kāi)發(fā)者們開(kāi)始憂心忡忡的按照文檔,將原本使用 TPR 的代碼都升級(jí)成 CRD。而就在這時(shí),他們卻驚奇的發(fā)現(xiàn),這兩種機(jī)制除了名字之外,好像并沒(méi)有任何不同。所謂的升級(jí)工作,其實(shí)就是將代碼里的 TPR 字樣全局替換成 CRD 而已。
難道,這只是虛驚一場(chǎng)?
其實(shí),很少有人注意到,在 TPR 被替換成 CRD 之后,Brendan Burns 和微軟團(tuán)隊(duì)就再也沒(méi)有出現(xiàn)在“自定義 API”這個(gè)至關(guān)重要的領(lǐng)域里了。而 CRD 現(xiàn)在的負(fù)責(zé)人,都是來(lái)自 Google 和 RedHat 的工程師。
在這次升級(jí)事件之后不久,CoreOS 公司在它的官方網(wǎng)站上發(fā)布了一篇叫做:TPR Is Dead! Kubernetes 1.7 Turns to CRD 的博客,旨在指導(dǎo)用戶從 TRP 升級(jí)成 CRD。不過(guò),現(xiàn)在回頭再看一眼這篇文章,平淡無(wú)奇的講述背后,你能否感受到當(dāng)年這場(chǎng)“開(kāi)發(fā)者戰(zhàn)爭(zhēng)”的蛛絲馬跡呢?
其實(shí),Operator 并不平坦的晉級(jí)之路,只是 Kubernetes API 生態(tài)風(fēng)起云涌的冰山一角。幾乎在每個(gè)星期,甚至每一天,都有太多圍繞著 Kubernetes 開(kāi)發(fā)者生態(tài)的角逐,在這個(gè)無(wú)比繁榮的社區(qū)背后,以不為人知的方式開(kāi)始或者謝幕。
而這一切紛爭(zhēng)的根本原因卻無(wú)比直白。Kubernetes 項(xiàng)目,已經(jīng)被廣泛認(rèn)可為云計(jì)算時(shí)代應(yīng)用開(kāi)發(fā)者們的終端入口。這正是為何,無(wú)論是 Google、微軟,還是 CoreOS 以及 Heptio,所有這個(gè)生態(tài)里的大小玩家,都在不遺余力的在 Kubernetes API 層上捍衛(wèi)著自己的話語(yǔ)權(quán),以期在這個(gè)未來(lái)云時(shí)代的開(kāi)發(fā)者入口上,爭(zhēng)取到自己的一席之地。
而在完成了對(duì)收 CoreOS 的收購(gòu)之后,RedHat 終于在這一領(lǐng)域拿到了可以跟 Google 和微軟一較高低的關(guān)鍵位置。2018年,RedHat 不失時(shí)機(jī)的發(fā)布了 Operator Framework,希望通過(guò) Operator 周邊工具和生態(tài)的進(jìn)一步完善,把 Operator 確立成為分布式應(yīng)用開(kāi)發(fā)與管理的關(guān)鍵依賴。而伴隨著 Operator 越來(lái)越多的介入到應(yīng)用開(kāi)發(fā)和部署流程之后, Kubernetes API 一定會(huì)繼續(xù)向上演進(jìn),進(jìn)一步影響開(kāi)發(fā)者的認(rèn)知和編程習(xí)慣。這,已經(jīng)成為了云計(jì)算生態(tài)繼續(xù)發(fā)展下去的必然趨勢(shì)。
而作為這個(gè)趨勢(shì)堅(jiān)定不移的貫徹者,無(wú)論是 Istio,還是 Knative,都在用同樣的經(jīng)歷告訴我們這樣的道理:只有構(gòu)建在 Kubernetes 這個(gè)云時(shí)代基礎(chǔ)設(shè)施事實(shí)標(biāo)準(zhǔn)上的開(kāi)發(fā)者工具,才有可能成為下一個(gè)開(kāi)發(fā)者領(lǐng)域的 “Operator” 。
?
原文鏈接
本文為云棲社區(qū)原創(chuàng)內(nèi)容,未經(jīng)允許不得轉(zhuǎn)載。
總結(jié)
以上是生活随笔為你收集整理的Kubernetes API 与 Operator,不为人知的开发者战争的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: IPv6时代已来:双十一中的IPv6大规
- 下一篇: 在 IntelliJ IDEA 中部署应