Kubernetes GitOps 工具

Kubernetes GitOps Tools

譯自: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 WorkflowsArgo 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友好(雖然不是那麼強大)。

還可以使用LinkerdConsul替代Istio。

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資源。

image-20220209102542391

Kyverno 策略是一組規則,每條規則包含一個match子句,一條exclude子句和validate, mutategenerate中的某條子句。一條規則定義中只可以包含一個validate, mutategenerate子節點。

你可以配置任何有關最佳實踐、網路或安全的策略。例如,可以強制所有包含標籤的服務或所有容器運行在非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的。

Tags: