在某些技術領域,Kubernetes被認為是一種不必要的複雜浪費時間,初創公司應該避免這種浪費。使用 Kubernetes 和乙個小團隊被視為過度工程的標誌。
翻譯自 Paul Butler 的 The Hater's Guide to Kubernetes。我自己犯了蔑視的錯誤。 我有時可能會抱怨 kubernetes,但它確實是一項很棒的技術。 我強烈推薦給我所有的競爭對手。 — 保羅·巴特勒 (@paulgb) September 9, 2022 儘管我說了一些諷刺的話,但是"驚人的技術產品"這確實是發自內心的讚美。 在那篇博文中,我寫了一篇關於 kubernetes 的複雜性對於它所做的事情是多麼必要。 我們已經在 Jamsocket 上執行 kubernetes 生產幾年了,我發現它工作得很好。 Kubernetes 的寧靜已經在內部實現。 其中乙個關鍵是剝離 Kubernetes 功能的一小部分,並假裝其餘部分不存在。 這篇文章最初是關於我們如何使用 Kubernetes 的內部指南,所以它並不意味著對每個初創公司都有指導意義; 不過,我認為這是乙個很好的起點,可以避免在浩瀚的 kubernetes 中出現許多沙洲。
在我看來,如果你想要以下三件事,Kubernetes是最好的方法:
在伺服器上執行多個程序以計畫作業。
以冗餘方式執行它們,並在它們之間實現負載平衡。
將它們及其關係配置為 **。
從根本上說,Kubernetes 只是乙個抽象層,它允許您將一組機器視為單個(無頭)機器。 如果這是你的用例,並且你可以避免它的其他部分,你可以走得很遠。
有些人告訴我,第 2 點是矯枉過正,初創公司不應該專注於零停機部署或高可用性。 但是我們經常每天進行多次部署,當我們的產品出現故障時,我們客戶的產品也會為他們的使用者帶來失敗。 即使是一分鐘的停機時間也會被某人注意到。 滾動部署使我們有信心隨意且頻繁地進行部署。
對於後台,JamSocket 是一種服務,用於動態啟動 Web 應用程式可以與之通訊的程序。 有點像 AWS Lambda,但流程生命週期繫結到 websocket 連線,而不是單個請求響應。 我們使用 Kubernetes 來執行支援此功能所需的長時間執行的程序。 API 伺服器、容器登錄檔、控制器、日誌收集器、一些 DNS 服務、指標收集等。
有些事情我們不使用 kubernetes:
短暫的過程本身。 我們很早就嘗試過,但我們很快發現它有侷限性(稍後會詳細介紹)。
靜態營銷**。 為此,我們使用 Vercel。 它更昂貴,但對於一家小型初創公司來說,乙個小時的工程時間的機會成本也更高,而 Vercel 為我們節省的時間比它花費的時間還要多。 直接儲存我們不想丟失的任何資料。 我們確實使用一些持久捲來快取或派生資料,但除此之外,我們還在群集外部使用託管的 postgres db 和 blob 儲存。
值得一提的是,我們自己並不管理 kubernetes——使用 kubernetes 的主要優勢是我們可以將其基礎設施級別的操作外包! 我們對 Google Kubernetes Engine 很滿意,雖然 Google Domains 的慘敗動搖了我對 Google Cloud 的信心,但至少我可以高枕無憂,因為我知道遷移到 Amazon EKS 相對簡單。 我們毫不猶豫地使用某些型別的 k8s 資源。 我在這裡只列出我們顯式建立的資源; 這些資源中的大多數都隱式地建立了其他資源(如 pod),我不會提及,但我們肯定會(間接)使用它們。
部署:我們的大多數 Pod 都是通過部署建立的。 每個對我們服務的功能至關重要的部署都有多個副本和滾動更新。
服務業:具體來說,clusterip 用於內部服務,loadbalancer 用於外部服務。 我們避免使用 nodeport 和 externalname 服務,而是更願意將 DNS 配置保留在 kubernetes 之外。
cronjob:用於清理指令碼和類似內容。
configmap跟secrets:用於將資料傳遞給上述資源。
statefulset跟persistentvolumeclaim:我們使用了一些有狀態函式集。 配置比部署稍微複雜一些,但它們可以在重新啟動後保留卷。 我們更願意將重要資料儲存到 k8s 之外的託管服務中。 我們對捲沒有嚴格的規則,因為有時在服務重啟後保留快取之類的東西是件好事,但如果可能的話,我會避免使用它們,因為它們可能與滾動部署(死鎖)互動不佳。
rbac:我們在一些地方使用它,例如授予服務重新整理機密的許可權。 它為我們的小集群增加了足夠的複雜性,我基本上避免了它。
手動編寫 yaml。yaml 有足夠的陷阱,所以我盡可能避免它。 相反,我們的 Kubernetes 資源定義是使用 TypeScript 和 Pulumi 建立的。 非內建資源和運算元。我之前寫過關於控制迴圈模式是一把雙刃劍的文章:這是使 K8s 強大的核心思想,但它也是間接性和複雜性。 Operator 模式和自定義資源允許第三方軟體使用 Kubernetes 強大的基礎設施來執行自己的控制迴圈,這個想法在理論上很棒,但在實踐中我發現很笨拙。 我們不使用 cert-manager,我們使用 caddy 的證書自動化。 helm。由於運算子和缺乏 yaml 規則,Helm 無法工作,但我也認為使用非結構化字串模板來生成機器可解析的內容意味著引入漏洞而沒有好處。 對我來說,這就像在黑板上釘釘子一樣,對不起。 名稱中帶有“網格”的任何內容。我想他們為某些人工作,但他們不為我工作,他們也不為這個人工作。 入口資源。我沒有留下任何傷疤,我知道有些人會有效地使用它們,但我們成功使用 kubernetes 的主題之一是避免新增不必要的間接層。 配置球童對我們有用,這就是我們所做的一切。
嘗試在本地複製整個 k8s 堆疊。我們不會使用 k3s 或 kind 之類的工具來精確地複製生產,而只是使用 docker compose 或我們自己的指令碼來啟動我們目前真正關心的系統子集。
我在上面提到了乙個事實,即我們在 kubernetes 上執行短暫的、互動式的、會話活躍的程序很短的時間。 我們很快意識到,Kubernetes 是為容器啟動時間而設計的,而不是為健壯性和模組化而設計的。 作為一般規則,我的觀點是 kubernetes 適合冗餘執行一些長時間執行的程序,但如果乙個人正在等待 pod 啟動,kubernetes 是錯誤的選擇。 我承認我在這裡談論的是我的書,但至少它是一本開源的書:我們使用麻省理工學院許可的 Rust 編排器,稱為 plane,我們專門設計它來快速排程和執行互動式工作負載的程序(即有人在等待他們)。 為了完整起見,我還應該提到,已經出現的一些 kubernetes 替代品非常好。 特別是如果你不希望或不需要我的初始列表中的要求 3(將基礎結構指定為 ** 的能力)。 對於我們的乙個產品,我們選擇使用 Railway 而不是我們的 K8S 集群,主要是為了預覽環境。 一些真正尊重 Render 的朋友讚不絕口(我涉足過,但個人認為 Railway 的環境模型更簡潔)。 我也更喜歡 Flight Control 的自帶雲方法。 對於許多 SaaS 型別的應用程式,您可能已經使用這些工具(參考前面提到的工具)走得很遠。 但是,如果你滿足本文開頭列出的三個要求,並採取嚴格的方法,那麼不要讓任何人告訴你現在使用 Kubernetes 還為時過早。