Kubernetes GitOps Tools
本文很好地介紹了GitOps,並給出了當下比較熱門的GitOps工具。
簡介
在本文中,將回顧一下kubernetes上我比較喜歡的GitOps工具。
在我看來,Kubernetes的優勢主要在於它的宣告式性質與控制迴圈相結合,並通過這些控制迴圈持續監控叢集的活動狀態,確保它與etcd中儲存的期望狀態保持一致。這種方式非常強大,但同時其資料庫也被限制為etcd(etcd僅提供了有限的可觀察性),並影響到了叢集變更時的責任性和審計性。另外一個缺點是將etcd和程式碼倉庫作為兩個SOT(sources of truth),有可能會導致配置漂移,造成管理上的困難。
開發者使用程式碼倉庫這種安全且可追溯的方式來儲存程式碼,並開發出了Workflows這種方式來高效地管理中央倉庫,不同的團隊可以並行工作,且不會產生過多的衝突,同時保證對所有變更進行稽核,並支援追溯和回滾。
如果我們能夠從圍繞Git倉庫建立的流程中獲得這些優勢,並將它們擴充套件到基礎設施或是kubernetes中,那不是很好嗎?…歡迎來到GitOps的世界!
首先聊一下什麼是GitOps,以及如何將其應用到Kubernetes,然後再看一下在kubernetes中實現的GitOps宣告式工具,最後回顧一些GitOps友好的工具,即它們是以程式碼的形式實現和宣告的工具。
什麼是GitOps?
GitOps的目的是將etcd的這種宣告式特性擴充套件到(儲存程式碼的)Git 倉庫,並作為SSOT(single source of truth)。通過這種方式,我們可以利用Git帶來的優勢,如程式碼監視、歷史變更、快速回滾、可追溯性等等。
GitOps的核心觀點是使用包含當前期望的(生產環境基礎設施的)宣告式描述的GIt倉庫,並通過自動化流程來確保生產環境與倉庫中的期望狀態保持一致。如果你想要部署一個新的應用或更新一個現有的應用,只需要更新相應的倉庫即可(自動化流程會處理後續的事情)。這就像在生產中使用巡航控制來管理應用程式一樣。
GitOps 不僅限於Kubernetes,實際上它還可以通過將基礎設施作為程式碼儲存到GIt倉庫中來將應用程式碼延伸到基礎設施中,這通常是通過Terraform這樣的工具進行普及的。宣告式基礎設施既程式碼在實現GitOps中扮演著一個重要的作用,但不僅限於此。GitOps圍繞Git構建了整個生態系統和工具,並將其應用到基礎設施,僅僅在Git中使用Terraform並不能保證基礎設施的狀態能夠與生產環境保持一致,還需要持續執行Terraform命令(trrraform apply)來監控實時版本的變化,以及在流水線中實現手動審批等功能。
GitOps的理念是持續監控叢集的狀態並與Git倉庫進行對比,在配置不一致時立即採取相應的動作,防止發生配置漂移。除此之外,你還可以獲得Git帶來的好處,如通過程式碼監視進行手動審批。
對於我來說,這些理念是革命性的,如正確使用,可以讓組織更多關注功能特性,並減少自動化指令碼的編寫工作。這種觀念可以延申到軟體開發的其他領域,如可以將文件儲存在程式碼中,以此來跟蹤歷史變更,並保證文件的及時更新;或使用 ADRs來跟蹤架構決策。
Kubernetes中的Gitops
Kubernetes從一開始就有控制迴圈的想法,這意味著Kunernetes總是會監控叢集的狀態來保證達到期望狀態。例如,使執行的副本數與期望的副本數匹配。將GitOps的理念延申到應用,這樣就可以將服務定義為程式碼,例如,通過定義 Helm Charts,並使用一個通過K8s提供的功能來監控App狀態的工具來調整對應的叢集狀態,即,更新了程式碼倉庫,或更新了生產叢集的helm chart。這才是真正的持續部署。其中的核心原則是,應用部署和生命週期管理應該是自動化的、可審計並易於理解的。
每個環境都應該有一個程式碼倉庫,用於定義給定叢集的期望狀態。然後Kubernetes Operators 會持續監控特定分支(通常是master分支),並在探測到Git發生變更後,將此次變更傳遞到叢集,並更新etcd中的狀態。在這種方式中,etcd只作為一個資料庫,且不是唯一的SOT。可以在包含宣告式Kubernetes基礎設施的Git倉庫中定義應用的Helm chart。此外,還可以連結儲存庫,這樣一個儲存庫可以監視另一個儲存庫,以此類推。Kubernetes GitOps工具可以監控其他倉庫(如Helm Chart倉庫)的狀態,這樣你的叢集環境倉庫中無需包含Helm Chart,只需要一條到Helm 倉庫的連線,並使用該連結監控其變更即可,這樣當你釋出的一個新的chart時,後續會將該chart自動部署到叢集。通過這種方式自動執行端到端的宣告式CI/CD流水線。
宣告式GitOps工具
如果考慮Kubernetes上的GitOps,就需要討論那些在Kubernetes上實現了GitOps原則的工具(負責監控Git的狀態,並將其同步到叢集)。
ArgoCD
在我看來,Kubernetes上最好的GitOps工具就是ArgoCD。ArgoCD 是Argo生態系統的一部分,該生態系統包含了很多很好的工具,後續會進行討論。
使用ArgoCD,可以在程式碼庫中定義每個環境的所有配置。Argo CD會在特定的目標環境中自動部署所需的應用狀態。
Argo CD 作為一個kubernetes controller,持續監控執行的應用,並將當前的活動狀態與所需的目標狀態(如Git repo中描述的狀態)進行比較。Argo CD會報告並呈現這種差異,並通過自動或手動的方式將實時狀態同步到期望的目標狀態。
ArgoCD有一個非常棒的UI,支援SSO,它是安全、可擴充套件且易於使用的。
Flux
Flux 是除Argo CD外另一個非常有名專案。最近的版本包含很多改進,功能上非常接近Argo CD,Flux是CNCF孵化專案。
GitOps工具
在本節中,回顧一下我比較喜歡的GitOps友好的(即基於CRD的)工具。
helm
Helm 無需多言,它是Kubernetes上最著名的包管理器,當然,你應該像在程式語言中使用包一樣,在K8s中使用包管理器。Helm允許使用Charts 的方式打包應用,將複雜的應用抽象為可重用的簡單元件,便於定義、安裝和升級。
它還提供了一個強大的模板引擎,Helm 已經很成熟,它包含很多預定義的charts,支援性強,使用方便。
Helm可以很好地整合到ArgoCD或Flux,後者可以監控Helm倉庫的變化,並在釋出新的charts時進行部署。實現思路是將ArgoCD或Flux 指向Helm倉庫,並指定一個特定的版本或通配版本。如果使用通配版本,一旦釋出了新的版本,就會進行自動部署。你可以使用主版本或次版本的方式進行命名。我通常傾向於將應用打包到charts中,將其作為CI/CD的一部分進行構建,並讓ArgoCD監控特定的倉庫。這種關注點分離允許開發者在獨立於環境的倉庫中管理應用,並讓ArgoCD選擇在哪個環境中部署哪個charts。你可以使用多個Helm倉庫並根據不同的環境推送變更。例如,在合併一個PR後,可以執行一次"bronce"構建,該構建會將Helm chart釋出到一個名為"bronce"的倉庫中。dev環境的ArgoCD倉庫指向"bronce"倉庫,並在可用時部署新版本。staging 環境的ArgoCD倉庫會指向名為"silver"倉庫,而production 環境則指向名為"gold"的倉庫。當需要向staging或production環境推送某些內容時,CI/CD只需將該chart釋出到下一個倉庫即可。
ArgoCD可以覆蓋任何環境的特定Helm值。
Kustomize 是一個新的helm的替代品,它不需要模板引擎,而使用了一個overlay引擎,之上有基本定義和overlays 。
Argo Workflows 和 Argo Events
在Kubernetes中,你可能需要執行批量任務或複雜的工作流,作為資料處理流程、非同步處理或CI/CD的一部分。除此之外,你可能需要執行驅動微服務來響應特定的事件,如檔案上傳或傳送訊息到某個佇列。為了實現這些功能,可以使用 Argo Workflows 和Argo Events。
雖然它們是獨立的專案,但趨向於部署到一起。
Argo Workflows是一個類似Apache Airflow 的編排引擎,但天然適用於Kubernetes。它使用CRDs來定義複雜的workflows(使用YAML表示的steps或DAGs 來表達工作流)。它還有個不錯的UI,支援重試機制,定時任務,輸入輸出跟蹤等。你可以使用它來編排資料處理流水線和批量任務等。
有時你可能希望將流水線與非同步服務(如流引擎Kafka、佇列、webhook或底層儲存服務)整合到一起。例如,你可能希望對上傳檔案到S3這樣的事件做出響應,此時你可以使用Argo Events。
上述兩種工具為需要CI/CD流水線提供了簡單且強大的解決方案,可以在Kubernetes上執行CI/CD流水線。
由於所有workflows 定義都可以打包到Helm charts中,因此Argo Workflows 可以很好地整合到ArgoCD。
對於ML流水線,可以使用Kubeflow實現相同的目的。
對於CI/CD流水線,可以使用Tekton。
Istio
Istio 是市面上最著名的服務網格,它是開源的,且非常流行。由於服務網格內容龐大,因此這裡不會討論細節,但如果你在構建微服務,有可能你會需要一個服務網格來管理通訊、可觀測性、錯誤處理、安全以及(作為微服務架構一部分的)其他交叉方面。使用服務網格可以避免因為重複的邏輯而汙染微服務的程式碼。
簡而言之,一個服務網格就是一個特定的基礎設施層,你可以在上面新增應用,它允許透明地新增可觀測性、流量管理和安全,而無需自己實現這些功能。
Istio使用 CRDs 來實現其所有功能,因此可以將virtual services、gateways、policies等作為程式碼打包在Helm charts中,並使用ArgoCD或Flux來讓Istio變得GitOps友好(雖然不是那麼強大)。
Argo Rollouts
上面已經提到過,你可以使用Kubernetes來執行使用Argo Workflows或類似工具的CI/CD流水線。下一步邏輯上是執行持續部署,但在現實場景中,由於其風險較高,因此大部分公司只做了持續交付,這意味著他們可以實現自動化,但仍然採用手動方式進行審批和校驗,這類手動步驟的根因是這些團隊無法完全信任其自動化。
那麼該如何構建這種信任度來避免使用指令碼,進而實現從程式碼到生產的完全自動化。答案是:可觀測性。你需要關注資源的指標,並通過採集所有的資料來精確地傳達應用的狀態,即使用一組指標來構建信任度。如果Prometheus中包含所有的資料,那麼就可以實現自動化部署,因為此時你可以根據指標來實現滾動更新應用。
簡單地說,你可以使用K8s提供的開箱即用的高階部署技術--滾動升級。我們需要使用金絲雀部署來實現漸進式釋出,目的是將流量逐步路由到新版本的應用,等待指標採集,然後進行分析並於預先定義的規則進行匹配。如果檢查正常,則增加流量;如果發現問題,則回滾部署。
在Kubernetes上可以使用Argo Rollouts來實現金絲雀釋出。
Argo Rollouts是一個Kubernetes controller,它使用一組CRDs來提供高階部署能力,如藍綠、金絲雀、金絲雀分析、實驗等,並向Kubernetes提供漸進式交付功能。
雖然像 Istio 這樣的服務網格可以提供金絲雀釋出,但Argo Rollouts簡化了處理流程,且以開發者為中心。除此之外,Argo Rollouts還可以整合到任何服務網格中。
Argo Rollouts 是GitOps友好的,且能很好地與Argo Workflows和ArgoCD進行整合。使用這三種工具可以為部署建立一個非常強大的宣告式工具集。
Flagger 和Argo Rollouts非常類似,可以很好地與Flux進行整合,因此如果你正在使用Flux,可以考慮使用Flagger。
Crossplane
Crossplane是我最近喜歡的K8s工具,它填補了Kubernetes的一個關鍵空白:像管理K8s資源一樣管理第三方服務。這意味著,你可以使用YAML中定義的K8s資源,像在K8s中配置資料庫一樣配置AWS RDS或GCP cloud SQL等雲供應商的資料庫。
有了Crossplane,就不需要使用不同的工具和方法來分離基礎設施和程式碼。你可以使用K8s資源定義所有內容。通過這種方式,你無需去學習並分開儲存像Terraform 這樣的工具。
Crossplane 是一個開源的Kubernetes擴充套件,可以讓平臺團隊組合來自多個供應商的基礎設施,併為應用團隊提供更高階別的自服務APIs(而無需編碼任何程式碼)。
Crossplane 擴充套件了Kubernetes叢集,使用CRDs來提供基礎設施或管理雲服務。再者,相比於Terraform這樣的工具,它可以完全實現自動部署。Crossplane 使用現成的K8s能力,如使用控制迴圈來持續監控叢集,並自動檢測配置漂移。例如,如果定義了一個可管理的資料庫例項,後續有人手動進行了變更,Crossplane 會自動檢測該問題,並將其設定回先前的值。它將基礎設施作為程式碼並按照GitOps原則來執行。
Crossplane 可以與ArgoCD配合起來,監控原始碼,並保證程式碼庫是唯一的信任源(SOT),程式碼中的任何變更都會傳遞到叢集以及外部雲服務。
如果沒有Crossplane,你可以在K8s服務中實現GitOps,但無法在沒有額外處理的前提下實現雲服務的GitOps。
Kyverno
Kubernetes為敏捷自治團隊提供了極大的靈活性,但能力越大責任越大。必須有一套最佳實踐和規則來保證部署的一致性和連貫性,並使工作負載遵循公司要求的策略和安全。
Kyverno 是一種為Kubernetes設計的策略引擎,它可以像管理Kubernetes資源一樣管理策略,不需要使用新的語言來編寫策略。Kyverno 策略可以校驗、修改和生成Kubernetes資源。
Kyverno 策略是一組規則,每條規則包含一個match子句,一條exclude子句和
validate
,mutate
或generate
中的某條子句。一條規則定義中只可以包含一個validate
,mutate
或generate
子節點。
你可以配置任何有關最佳實踐、網路或安全的策略。例如,可以強制所有包含標籤的服務或所有容器執行在非root許可權下。 這裡提供了一些Kyverno 策略的例子。策略可以應用到整個叢集或特定的名稱空間中。你可以選擇是否期望對策略進行審計或強制它們阻止使用者部署資源。
Kubevela
Kubernetes 的一個問題是開發者需要知道並對平臺和叢集配置有所瞭解。很多開發者抱怨K8s的抽象級別太低,因此在那些只關心編寫和交付應用的開發者中間出現了爭議。
Open Application Model (OAM) 可以解決這個問題,它的理念是圍繞應用建立一個更高階別的抽象,其獨立於底層執行時。更多參見這裡.。
通過關注應用而非容器或編排器。OAM帶來了模組化、可擴充套件和可移植的設計,通過更高階別且一致的API對應用程式部署進行建模。
Kubevela是OMA模型的一種實現。KubeVela是執行時無關,且可擴充套件的,但最重要的是,它以應用程式為中心。在Kubevela 中,應用程式是以Kubernetes資源實現的一等公民。需要區分叢集運維人員(平臺團隊)和開發者(應用團隊)的區別。叢集運維人員通過定義components(構成應用程式的可部署/可提供的實體,如helm charts)和traits來管理叢集和不同的環境。開發者通過組裝components 和traits來定義應用。
平臺團隊:將平臺能力作為components或traits以及目標環境規範進行建模和管理。
應用團隊:選擇一個環境,組裝需要的components和traits,並將其部署到目標環境中。
KubeVela 是CNCF的沙盒專案,目前正處於初始階段,在不久的將來,它可以改變開發者使用Kubernetes的方式,使他們能夠更加關注應用本身。但我對OAM在現實世界中的適用性有一些擔憂,由於一些像系統程式、ML或大資料處理之類的服務,它們在很大程度上取決於底層細節,這種情況就很難融入OAM模型。
Schema Hero
軟體開發中另一種常見的的處理流程是在使用關係型資料庫時,需要管理schema的演進。
SchemaHero是一個開源資料庫的schema遷移工具,可以將schema定義轉化為可以在任何環境執行的遷移指令碼。它使用了Kubernetes的宣告特性來管理資料庫schema的遷移。你可以指定期望的狀態,並讓SchemaHero管理剩下的工作。
Bitnami Sealed Secrets
至此,我們已經涵蓋了很多GitOps工具,我們的目標是將所有內容儲存到Git,並使用Kubernetes的宣告特性來讓環境保持同步。我們可以(也應該)在Git中保證SOT,並讓自動化流程處理配置更改。
有一種資源通常難以儲存到Git中,即secret,如DB密碼或API金鑰。一種常見的解決方案是使用外部"保險庫",如 AWS Secret Manager 或HashiCorp Vault 來儲存這些secret,但這樣也產生了衝突,你需要一個單獨的流程來處理secrets。理想情況下,我們希望通過某種方式將secrets像其他資源一樣安全地儲存到Git中。
Sealed Secrets 就是用來解決這種問題的,它允許你將敏感資料通過強加密儲存到Git中,Bitnami Sealed Secrets天然整合進了Kubernetes中,可以使用Kubernetes中執行的Kubernetes controller來解密secret,而無需依賴其他元件。controller可以解密資料並建立原生的K8s secrets資源。通過這種方式可以將所有內容作為程式碼儲存到倉庫中,進而可以安全地執行持續部署,不需要依賴外部資源。
Sealed Secrets包含兩部分:
- 叢集側的控制器
- 客戶端側程式:
kubeseal
kubeseal 程式使用非對稱加密來對secrets進行加密,且只有controller可以解密。這些加密的secrets被編碼到了K8s的SealedSecret
資源中(可以儲存到Git中)。
Capsule
很多公司使用多租戶來管理不同的客戶,這在軟體開發中很常見,但很難在Kubernetes中實現。一種方式是通過名稱空間
將叢集劃分為獨立的邏輯分割槽,但無法完全隔離使用者,還需要引入網路策略、配額等等。你可以在每個名稱空間中建立網路策略和規則,但這是一個讓人乏味的過程,且無法擴充套件,而且租戶無法使用多個名稱空間,這是一個很大的限制。
分層名稱空間 可以用來解決這些問題。方法是為每個租戶分配分配一個父名稱空間,併為該租戶配置通用的網路策略和配額,並允許建立子名稱空間。這是一個很大的改進,但在租戶層面,缺少安全性和治理方面的原生支援。此外,它還沒有達到生產狀態,但預計將在未來幾個月釋出1.0版本。
一種常見的方式是為每個客戶建立一個叢集,這樣做相對比較安全,並給租戶提供了所需的一切內容,但這種方式很難管理,費用也很高。
Capsule 是一種在單個叢集中為Kubernetes提供多租戶功能的工具。使用Capsule,你可以將所有租戶放到一個叢集中。Capsule會為租戶提供一個"近乎"原生的體驗(雖然有一些小小的限制),租戶可以在其叢集中建立多個名稱空間。這種方式隱藏了多租戶共享底層叢集的事實。
在一個叢集中,Capsule控制器將多個名稱空間聚合到一起,抽象為一個輕量級的Kubernetes,稱為租戶,它是一組Kubernetes名稱空間。在每個租戶中,使用者可以建立其名稱空間並共享分配到的資源,Policy Engine 保證租戶間的隔離性。
租戶級別定義的 Network and Security Policies, Resource Quota, Limit Ranges, RBAC以及其他策略會自動繼承到租戶的所有名稱空間中(類似分層名稱空間)。這樣,使用者可以自主地操作他們的租戶,而不需要叢集管理員的干預。
由於Capsule 的所有配置都可以儲存到Git中,因此它是GitOps的。