為什么Kubernetes很酷?
在我剛開始學(xué)習(xí) Kubernetes(大約是一年半以前吧?)時,我真的不明白為什么應(yīng)該去關(guān)注它。
在我使用 Kubernetes 全職工作了三個多月后,我才逐漸明白了為什么我應(yīng)該使用它。(我距離成為一個 Kubernetes 專家還很遠(yuǎn)!)希望這篇文章對你理解 Kubernetes 能做什么會有幫助!
我將嘗試去解釋我對 Kubernetes 感興趣的一些原因,而不去使用 “原生云cloud native”、“編排系統(tǒng)orchestration”、“容器container”,或者任何 Kubernetes 專用的術(shù)語 :)。我去解釋的這些觀點主要來自一位 Kubernetes 操作者/基礎(chǔ)設(shè)施工程師,因為,我現(xiàn)在的工作就是去配置 Kubernetes 和讓它工作的更好。
我不會去嘗試解決一些如 “你應(yīng)該在你的生產(chǎn)系統(tǒng)中使用 Kubernetes 嗎?”這樣的問題。那是非常復(fù)雜的問題。(不僅是因為“生產(chǎn)系統(tǒng)”根據(jù)你的用途而總是有不同的要求)
Kubernetes 可以讓你無需設(shè)置一臺新的服務(wù)器即可在生產(chǎn)系統(tǒng)中運行代碼
我***被說教使用 Kubernetes 是與我的伙伴 Kamal 的下面的談話:
大致是這樣的:
- Kamal: 使用 Kubernetes 你可以通過一條命令就能設(shè)置一臺新的服務(wù)器。
- Julia: 我覺得不太可能吧。
- Kamal: 像這樣,你寫一個配置文件,然后應(yīng)用它,這時候,你就在生產(chǎn)系統(tǒng)中運行了一個 HTTP 服務(wù)。
- Julia: 但是,現(xiàn)在我需要去創(chuàng)建一個新的 AWS 實例,明確地寫一個 Puppet 清單,設(shè)置服務(wù)發(fā)現(xiàn),配置負(fù)載均衡,配置我們的部署軟件,并且確保 DNS 正常工作,如果沒有什么問題的話,至少在 4 小時后才能投入使用。
- Kamal: 是的,使用 Kubernetes 你不需要做那么多事情,你可以在 5 分鐘內(nèi)設(shè)置一臺新的 HTTP 服務(wù),并且它將自動運行。只要你的集群中有空閑的資源它就能正常工作!
- Julia: 這兒一定是一個“坑”。
這里有一種陷阱,設(shè)置一個生產(chǎn)用 Kubernetes 集群(在我的經(jīng)險中)確實并不容易。(查看 Kubernetes 艱難之旅 中去開始使用時有哪些復(fù)雜的東西)但是,我們現(xiàn)在并不深入討論它。
因此,Kubernetes ***個很酷的事情是,它可能使那些想在生產(chǎn)系統(tǒng)中部署新開發(fā)的軟件的方式變得更容易。那是很酷的事,而且它真的是這樣,因此,一旦你使用一個運作中的 Kubernetes 集群,你真的可以僅使用一個配置文件就在生產(chǎn)系統(tǒng)中設(shè)置一臺 HTTP 服務(wù)(在 5 分鐘內(nèi)運行這個應(yīng)用程序,設(shè)置一個負(fù)載均衡,給它一個 DNS 名字,等等)??雌饋碚娴暮苡腥?。
對于運行在生產(chǎn)系統(tǒng)中的代碼,Kubernetes 可以提供更好的可見性和可管理性
在我看來,在理解 etcd 之前,你可能不會理解 Kubernetes 的。因此,讓我們先討論 etcd!
想像一下,如果現(xiàn)在我這樣問你,“告訴我你運行在生產(chǎn)系統(tǒng)中的每個應(yīng)用程序,它運行在哪臺主機上?它是否狀態(tài)很好?是否為它分配了一個 DNS 名字?”我并不知道這些,但是,我可能需要到很多不同的地方去查詢來回答這些問題,并且,我需要花很長的時間才能搞定。我現(xiàn)在可以很確定地說不需要查詢,僅一個 API 就可以搞定它們。
在 Kubernetes 中,你的集群的所有狀態(tài) – 運行中的應(yīng)用程序 (“pod”)、節(jié)點、DNS 名字、 cron 任務(wù)、 等等 —— 都保存在一個單一的數(shù)據(jù)庫中(etcd)。每個 Kubernetes 組件是無狀態(tài)的,并且基本是通過下列方式工作的:
- 從 etcd 中讀取狀態(tài)(比如,“分配給節(jié)點 1 的 pod 列表”)
- 產(chǎn)生變化(比如,“在節(jié)點 1 上運行 pod A”)
- 更新 etcd 中的狀態(tài)(比如,“設(shè)置 pod A 的狀態(tài)為 ‘running’”)
這意味著,如果你想去回答諸如 “在那個可用區(qū)中有多少臺運行著 nginx 的 pod?” 這樣的問題時,你可以通過查詢一個統(tǒng)一的 API(Kubernetes API)去回答它。并且,你可以在每個其它 Kubernetes 組件上運行那個 API 去進(jìn)行同樣的訪問。
這也意味著,你可以很容易地去管理每個運行在 Kubernetes 中的任何東西。比如說,如果你想要:
- 部署實現(xiàn)一個復(fù)雜的定制的部署策略(部署一個東西,等待 2 分鐘,部署 5 個以上,等待 3.7 分鐘,等等)
- 每當(dāng)推送到 github 上一個分支,自動化 啟動一個新的 web 服務(wù)器
- 監(jiān)視所有你的運行的應(yīng)用程序,確保它們有一個合理的內(nèi)存使用限制。
這些你只需要寫一個程序與 Kubernetes API(“controller”)通訊就可以了。
另一個關(guān)于 Kubernetes API 的令人激動的事情是,你不會局限于 Kubernetes 所提供的現(xiàn)有功能!如果對于你要部署/創(chuàng)建/監(jiān)視的軟件有你自己的方案,那么,你可以使用 Kubernetes API 去寫一些代碼去達(dá)到你的目的!它可以讓你做到你想做的任何事情。
即便每個 Kubernetes 組件都“掛了”,你的代碼將仍然保持運行
關(guān)于 Kubernetes 我(在各種博客文章中 :))承諾的一件事情是,“如果 Kubernetes API 服務(wù)和其它組件‘掛了’也沒事,你的代碼將一直保持運行狀態(tài)”。我認(rèn)為理論上這聽起來很酷,但是我不確定它是否真是這樣的。
到目前為止,這似乎是真的!
我已經(jīng)斷開了一些正在運行的 etcd,發(fā)生了這些情況:
- 所有的代碼繼續(xù)保持運行狀態(tài)
- 不能做 _新的_ 事情(你不能部署新的代碼或者生成變更,cron 作業(yè)將停止工作)
- 當(dāng)它恢復(fù)時,集群將趕上這期間它錯過的內(nèi)容
這樣做意味著如果 etcd 宕掉,并且你的應(yīng)用程序的其中之一崩潰或者發(fā)生其它事情,在 etcd 恢復(fù)之前,它不能夠恢復(fù)。
Kubernetes 的設(shè)計對 bug 很有彈性
與任何軟件一樣,Kubernetes 也會有 bug。例如,到目前為止,我們的集群控制管理器有內(nèi)存泄漏,并且,調(diào)度器經(jīng)常崩潰。bug 當(dāng)然不好,但是,我發(fā)現(xiàn) Kubernetes 的設(shè)計可以幫助減輕它的許多核心組件中的錯誤的影響。
如果你重啟動任何組件,將會發(fā)生:
- 從 etcd 中讀取所有的與它相關(guān)的狀態(tài)
- 基于那些狀態(tài)(調(diào)度 pod、回收完成的 pod、調(diào)度 cron 作業(yè)、按需部署等等),它會去做那些它認(rèn)為必須要做的事情
- 因為,所有的組件并不會在內(nèi)存中保持狀態(tài),你在任何時候都可以重啟它們,這可以幫助你減輕各種 bug 的影響。
例如,如果在你的控制管理器中有內(nèi)存泄露。因為,控制管理器是無狀態(tài)的,你可以每小時定期去重啟它,或者,在感覺到可能導(dǎo)致任何不一致的問題發(fā)生時重啟它。又或者,在調(diào)度器中遇到了一個 bug,它有時忘記了某個 pod,從來不去調(diào)度它們。你可以每隔 10 分鐘來重啟調(diào)度器來緩減這種情況。(我們并不會這么做,而是去修復(fù)這個 bug,但是,你可以這樣做 :))
因此,我覺得即使在它的核心組件中有 bug,我仍然可以信任 Kubernetes 的設(shè)計可以讓我確保集群狀態(tài)的一致性。并且,總在來說,隨著時間的推移軟件質(zhì)量會提高。唯一你必須去操作的有狀態(tài)的東西就是 etcd。
不用過多地討論“狀態(tài)”這個東西 —— 而我認(rèn)為在 Kubernetes 中很酷的一件事情是,唯一需要去做備份/恢復(fù)計劃的東西是 etcd (除非為你的 pod 使用了持久化存儲的卷)。我認(rèn)為這樣可以使 Kubernetes 運維比你想的更容易一些。
在 Kubernetes 之上實現(xiàn)新的分布式系統(tǒng)是非常容易的
假設(shè)你想去實現(xiàn)一個分布式 cron 作業(yè)調(diào)度系統(tǒng)!從零開始做工作量非常大。但是,在 Kubernetes 里面實現(xiàn)一個分布式 cron 作業(yè)調(diào)度系統(tǒng)是非常容易的!(仍然沒那么簡單,畢竟它是一個分布式系統(tǒng))
我***次讀到 Kubernetes 的 cron 作業(yè)控制器的代碼時,我對它是如此的簡單感到由衷高興。去讀讀看,其主要的邏輯大約是 400 行的 Go 代碼。去讀它吧! => cronjob_controller.go <=
cron 作業(yè)控制器基本上做的是:
每 10 秒鐘:
- 列出所有已存在的 cron 作業(yè)
- 檢查是否有需要現(xiàn)在去運行的任務(wù)
- 如果有,創(chuàng)建一個新的作業(yè)對象去調(diào)度,并通過其它的 Kubernetes 控制器實際運行它
- 清理已完成的作業(yè)
重復(fù)以上工作
Kubernetes 模型是很受限制的(它有定義在 etcd 中的資源模式,控制器讀取這個資源并更新 etcd),我認(rèn)為這種相關(guān)的固有的/受限制的模型,可以使它更容易地在 Kubernetes 框架中開發(fā)你自己的分布式系統(tǒng)。
Kamal 給我說的是 “Kubernetes 是一個寫你自己的分布式系統(tǒng)的很好的平臺” ,而不是“ Kubernetes 是一個你可以使用的分布式系統(tǒng)”,并且,我覺得它真的很有意思。他做了一個 為你推送到 GitHub 的每個分支運行一個 HTTP 服務(wù)的系統(tǒng) 的原型。這花了他一個周末的時間,大約 800 行 Go 代碼,我認(rèn)為它真不可思議!
Kubernetes 可以使你做一些非常神奇的事情(但并不容易)
我一開始就說 “kubernetes 可以讓你做一些很神奇的事情,你可以用一個配置文件來做這么多的基礎(chǔ)設(shè)施,它太神奇了”。這是真的!
為什么說 “Kubernetes 并不容易”呢?是因為 Kubernetes 有很多部分,學(xué)習(xí)怎么去成功地運營一個高可用的 Kubernetes 集群要做很多的工作。就像我發(fā)現(xiàn)它給我了許多抽象的東西,我需要去理解這些抽象的東西才能調(diào)試問題和正確地配置它們。我喜歡學(xué)習(xí)新東西,因此,它并不會使我發(fā)狂或者生氣,但是我認(rèn)為了解這一點很重要 :)
對于 “我不能僅依靠抽象概念” 的一個具體的例子是,我努力學(xué)習(xí)了許多 Linux 上網(wǎng)絡(luò)是如何工作的,才讓我對設(shè)置 Kubernetes 網(wǎng)絡(luò)稍有信心,這比我以前學(xué)過的關(guān)于網(wǎng)絡(luò)的知識要多很多。這種方式很有意思但是非常費時間。在以后的某個時間,我或許寫更多的關(guān)于設(shè)置 Kubernetes 網(wǎng)絡(luò)的困難/有趣的事情。
或者,為了成功設(shè)置我的 Kubernetes CA,我寫了一篇 2000 字的博客文章,述及了我不得不學(xué)習(xí) Kubernetes 不同方式的 CA 的各種細(xì)節(jié)。
我覺得,像 GKE (Google 的 Kubernetes 產(chǎn)品) 這樣的一些監(jiān)管的 Kubernetes 的系統(tǒng)可能更簡單,因為,他們?yōu)槟阕隽嗽S多的決定,但是,我沒有嘗試過它們。