本文發表於一年多前。舊文章可能包含過時內容。請檢查頁面中的資訊自發布以來是否已變得不正確。

DIY:使用 Kubernetes 建立自己的雲(第 1 部分)

在 Ænix,我們對 Kubernetes 懷有深厚的感情,並夢想著所有現代技術都將很快開始利用其卓越的模式。

你是否曾想過構建自己的雲?我敢打賭你想過。但只使用現代技術和方法,不離開舒適的 Kubernetes 生態系統,這可能嗎?我們在開發 Cozystack 過程中的經驗要求我們深入研究這個問題。

你可能會爭辯說,Kubernetes 並非為此目的而設計,為什麼不直接使用 OpenStack 來管理裸金屬伺服器,並在其中按預期執行 Kubernetes 呢?但這樣做,你只是將責任從自己手中轉移到了 OpenStack 管理員手中。這至少會給你的生態系統增加另一個龐大而複雜的系統。

為什麼要將事情複雜化呢?畢竟,Kubernetes 此時已經擁有執行租戶 Kubernetes 叢集所需的一切。

我想與你分享我們基於 Kubernetes 開發雲平臺的經驗,重點介紹我們自己使用的、並且相信值得你關注的開源專案。

在本系列文章中,我將講述我們如何僅使用開源技術從裸金屬準備託管 Kubernetes 的故事。從資料中心準備的基礎層面開始,執行虛擬機器、隔離網路、設定容錯儲存,到製備功能齊全的 Kubernetes 叢集,包括動態卷製備、負載均衡器和自動擴縮。

以此文為始,我將開啟一個由幾部分組成的系列文章。

  • 第 1 部分:為你的雲奠定基礎。在裸金屬上準備和運營 Kubernetes 期間面臨的挑戰,以及一個現成的基礎設施製備方案。
  • 第 2 部分:網路、儲存和虛擬化。如何將 Kubernetes 轉變為啟動虛擬機器的工具,以及為此需要什麼。
  • 第 3 部分:Cluster API 以及如何透過按下一個按鈕開始製備 Kubernetes 叢集。自動擴縮、動態卷製備和負載均衡器是如何工作的。

我將嘗試儘可能獨立地描述各種技術,但同時,我也會分享我們的經驗以及我們為何選擇某種解決方案。

首先,讓我們瞭解 Kubernetes 的主要優勢以及它如何改變了使用雲資源的方式。

重要的是要理解,在雲上和在裸金屬上使用 Kubernetes 是不同的。

雲中的 Kubernetes

當你在雲中操作 Kubernetes 時,你無需擔心持久卷、雲負載均衡器或製備節點的過程。所有這些都由你的雲提供商處理,他們以 Kubernetes 物件的形式接受你的請求。換句話說,伺服器端對你完全隱藏,你也不想知道雲提供商具體是如何實現的,因為這不在你的責任範圍之內。

A diagram showing cloud Kubernetes, with load balancing and storage done outside the cluster

展示雲 Kubernetes 的圖表,其中負載均衡和儲存在叢集外部完成

Kubernetes 提供了方便的抽象,這些抽象在任何地方都以相同的方式工作,允許你在任何雲中的任何 Kubernetes 上部署你的應用程式。

在雲中,你通常有幾個獨立的實體:Kubernetes 控制平面、虛擬機器、持久卷和負載均衡器。使用這些實體,你可以建立高度動態的環境。

多虧了 Kubernetes,虛擬機器現在只被看作是利用雲資源的實用實體。你不再在虛擬機器內部儲存資料。你可以在任何時候刪除所有虛擬機器並重新建立它們,而不會破壞你的應用程式。Kubernetes 控制平面將繼續儲存關於你的叢集中應該執行什麼的資訊。負載均衡器將繼續將流量傳送到你的工作負載,只需更改端點以將流量傳送到新節點。而你的資料將安全地儲存在雲提供的外部持久卷中。

這種方法是在雲中使用 Kubernetes 的基礎。其原因顯而易見:系統越簡單,就越穩定,為了這種簡單性,你選擇在雲中購買 Kubernetes。

裸金屬上的 Kubernetes

在雲中使用 Kubernetes 確實簡單方便,但對於裸金屬安裝來說卻並非如此。在裸金屬世界中,Kubernetes 反而變得難以承受的複雜。首先,因為整個網路、後端儲存、雲負載均衡器等通常不是在叢集外部執行,而是在叢集內部執行。結果是這樣的系統更新和維護起來要困難得多。

A diagram showing bare metal Kubernetes, with load balancing and storage done inside the cluster

展示裸金屬 Kubernetes 的圖表,其中負載均衡和儲存在叢集內部完成

你自己判斷:在雲中,要更新一個節點,你通常會刪除虛擬機器(甚至使用 `kubectl delete node`),然後讓你的節點管理工具基於不可變映象建立一個新的。新節點將加入叢集並“正常工作”;遵循 Kubernetes 世界中一個非常簡單和常用的模式。許多叢集每隔幾分鐘就會訂購新的虛擬機器,僅僅因為它們可以使用更便宜的 Spot 例項。然而,當你有一臺物理伺服器時,你不能簡單地刪除並重新建立它,首先因為它通常執行著一些叢集服務、儲存資料,而且其更新過程要複雜得多。

解決這個問題有不同的方法,從 kubeadm、kubespray 和 k3s 所做的就地更新,到透過 Cluster API 和 Metal3 實現物理節點的完全自動化製備。

我喜歡 Talos Linux 提供的混合方法,你的整個系統都描述在一個配置檔案中。該檔案的大多數引數都可以在不重啟或重新建立節點的情況下應用,包括 Kubernetes 控制平面元件的版本。然而,它仍然保持了 Kubernetes 最大的宣告性。這種方法在更新裸金屬節點時最大限度地減少了對叢集服務的不必要影響。在大多數情況下,你不需要在進行次要更新時遷移你的虛擬機器和重建叢集檔案系統。

為你的未來雲準備基礎

那麼,假設你決定建立自己的雲。要從某個地方開始,你需要一個基礎層。你不僅需要考慮如何在你的伺服器上安裝 Kubernetes,還需要考慮如何更新和維護它。考慮到你將不得不考慮諸如更新核心、安裝必要的模組以及軟體包和安全補丁之類的事情。現在你必須考慮比使用雲中現成的 Kubernetes 時不必擔心的事情多得多。

當然,你可以使用像 Ubuntu 或 Debian 這樣的標準發行版,或者你可以考慮像 Flatcar Container Linux、Fedora Core 和 Talos Linux 這樣的專用發行版。每種都有其優缺點。

我們呢?在 Ænix,我們使用了相當多特定的核心模組,如 ZFS、DRBD 和 OpenvSwitch,所以我們決定走預先形成包含所有必要模組的系統映象的路線。在這種情況下,Talos Linux 對我們來說是最方便的。例如,這樣的配置就足以構建一個包含所有必要核心模組的系統映象

arch: amd64
platform: metal
secureboot: false
version: v1.6.4
input:
  kernel:
    path: /usr/install/amd64/vmlinuz
  initramfs:
    path: /usr/install/amd64/initramfs.xz
  baseInstaller:
    imageRef: ghcr.io/siderolabs/installer:v1.6.4
  systemExtensions:
    - imageRef: ghcr.io/siderolabs/amd-ucode:20240115
    - imageRef: ghcr.io/siderolabs/amdgpu-firmware:20240115
    - imageRef: ghcr.io/siderolabs/bnx2-bnx2x:20240115
    - imageRef: ghcr.io/siderolabs/i915-ucode:20240115
    - imageRef: ghcr.io/siderolabs/intel-ice-firmware:20240115
    - imageRef: ghcr.io/siderolabs/intel-ucode:20231114
    - imageRef: ghcr.io/siderolabs/qlogic-firmware:20240115
    - imageRef: ghcr.io/siderolabs/drbd:9.2.6-v1.6.4
    - imageRef: ghcr.io/siderolabs/zfs:2.1.14-v1.6.4
output:
  kind: installer
  outFormat: raw

然後我們使用 `docker` 命令列工具來構建一個作業系統映象

cat config.yaml | docker run --rm -i -v /dev:/dev --privileged "ghcr.io/siderolabs/imager:v1.6.4" - 

結果,我們得到了一個包含我們需要的一切的 Docker 容器映象,我們可以用它在我們的伺服器上安裝 Talos Linux。你也可以這樣做;這個映象將包含所有必要的韌體和核心模組。

但問題來了,你如何將新形成的映象交付到你的節點上?

我一直在思考 PXE 啟動的想法已經有相當長一段時間了。例如,我兩年前寫過一篇文章Kubefarm 專案就完全是使用這種方法構建的。但不幸的是,它並不能幫助你部署你的第一個父叢集,該叢集將容納其他叢集。所以現在你已經準備了一個解決方案,可以幫助你使用 PXE 方法做同樣的事情。

本質上,你所需要做的就是在容器內執行臨時的 DHCPPXE 伺服器。然後你的節點將從你的映象啟動,你可以使用一個簡單的 Debian 風格的指令碼來幫助你引導你的節點。

asciicast

那個 `talos-bootstrap` 指令碼的原始碼可以在 GitHub 上找到。

這個指令碼允許你在五分鐘內在裸金屬上部署 Kubernetes,並獲得一個用於訪問它的 kubeconfig。然而,前面還有許多未解決的問題。

交付系統元件

在這個階段,你已經有了一個能夠執行各種工作負載的 Kubernetes 叢集。然而,它還沒有完全功能化。換句話說,你需要設定網路和儲存,以及安裝必要的叢集擴充套件,比如用於執行虛擬機器的 KubeVirt,還有監控棧和其他系統範圍的元件。

傳統上,這是透過在你的叢集中安裝 Helm charts 來解決的。你可以透過在本地執行 `helm install` 命令來做到這一點,但是當你想要跟蹤更新,或者當你有多個叢集並希望保持它們統一時,這種方法就變得不方便了。實際上,有很多方法可以以宣告的方式來做這件事。為了解決這個問題,我推薦使用最佳的 GitOps 實踐。我指的是像 ArgoCD 和 FluxCD 這樣的工具。

雖然 ArgoCD 憑藉其圖形介面和中央控制平面更適合開發目的,但 FluxCD 另一方面更適合建立 Kubernetes 發行版。使用 FluxCD,你可以指定應該啟動哪些 chart 以及使用什麼引數,並描述依賴關係。然後,FluxCD 會為你處理一切。

建議在你新建立的叢集中一次性安裝 FluxCD 併為其提供配置。這將安裝所有必要的東西,使叢集達到預期的狀態。

透過在你新建立的叢集中執行一次 FluxCD 的安裝並相應地配置它,你可以使其自動部署所有必需品。這將使你的叢集能夠自我升級到所需的狀態。例如,在安裝我們的平臺後,你會看到以下預配置的帶有系統元件的 Helm charts

NAMESPACE                        NAME                        AGE    READY   STATUS
cozy-cert-manager                cert-manager                4m1s   True    Release reconciliation succeeded
cozy-cert-manager                cert-manager-issuers        4m1s   True    Release reconciliation succeeded
cozy-cilium                      cilium                      4m1s   True    Release reconciliation succeeded
cozy-cluster-api                 capi-operator               4m1s   True    Release reconciliation succeeded
cozy-cluster-api                 capi-providers              4m1s   True    Release reconciliation succeeded
cozy-dashboard                   dashboard                   4m1s   True    Release reconciliation succeeded
cozy-fluxcd                      cozy-fluxcd                 4m1s   True    Release reconciliation succeeded
cozy-grafana-operator            grafana-operator            4m1s   True    Release reconciliation succeeded
cozy-kamaji                      kamaji                      4m1s   True    Release reconciliation succeeded
cozy-kubeovn                     kubeovn                     4m1s   True    Release reconciliation succeeded
cozy-kubevirt-cdi                kubevirt-cdi                4m1s   True    Release reconciliation succeeded
cozy-kubevirt-cdi                kubevirt-cdi-operator       4m1s   True    Release reconciliation succeeded
cozy-kubevirt                    kubevirt                    4m1s   True    Release reconciliation succeeded
cozy-kubevirt                    kubevirt-operator           4m1s   True    Release reconciliation succeeded
cozy-linstor                     linstor                     4m1s   True    Release reconciliation succeeded
cozy-linstor                     piraeus-operator            4m1s   True    Release reconciliation succeeded
cozy-mariadb-operator            mariadb-operator            4m1s   True    Release reconciliation succeeded
cozy-metallb                     metallb                     4m1s   True    Release reconciliation succeeded
cozy-monitoring                  monitoring                  4m1s   True    Release reconciliation succeeded
cozy-postgres-operator           postgres-operator           4m1s   True    Release reconciliation succeeded
cozy-rabbitmq-operator           rabbitmq-operator           4m1s   True    Release reconciliation succeeded
cozy-redis-operator              redis-operator              4m1s   True    Release reconciliation succeeded
cozy-telepresence                telepresence                4m1s   True    Release reconciliation succeeded
cozy-victoria-metrics-operator   victoria-metrics-operator   4m1s   True    Release reconciliation succeeded

結論

結果是,你實現了一個高度可重複的環境,你可以提供給任何人,並且知道它的執行方式完全符合預期。這實際上就是 Cozystack 專案所做的事情,你可以完全免費地親自嘗試。

在接下來的文章中,我將討論如何準備 Kubernetes 以執行虛擬機器以及如何透過點選按鈕來執行 Kubernetes 叢集。敬請關注,會很有趣的!