Kustomize 和 Helm 之間,我為什麼選擇了 Kustomize?

本文將記錄為什麼最終沒有採用 Helm 而是選擇了 Kustomize 作為 Kubernetes 應用的部署工具。

使用各種項目管理之前的情況

首先說說之前的痛點。我們雖然不是個大公司,可是這代碼也是越敲越多,服務也是越做越全。零零總總也有十幾個項目要管理了。然後我們同樣有多套部署環境:內網環境,預生產環境,生產環境。那麼針對每一個環境幾乎都要有一套 Kubernetes 的 YAML 文件,但是各個僅僅是稍有不同。

然後我們自己的 CI 是將構建好的 Docker 鏡像放到 Registry 裏面。

那麼,每次更新的鏡像之後就是通過人手工去部署一下,絕大多數情況就是修改一下鏡像的 Tag,但是由於每個環境的 YAML 略有區別,那麼如果我需要在不同環境切換的時候就需要來回修改這些 YAML 文件,一不小心寫錯了就只能怪自己手殘。然而這種部署方式雖然在 Kubernetes 之下就是改改 YAML 就好了,但是依然感覺很是原始。

希望有什麼改善

仔細想想,自己的需求就是這麼幾個:

  1. 有一個統一的模板可以管理一個項目的 Kubernetes 部署結構。
  2. 有某種方式可以管理不同環境之間微小的差異。
  3. 每次更新基本就是修改鏡像的標籤然後部署,那麼有沒有什麼簡單的辦法實現之,而不是讓我每次都去修改 YAML 文件。

針對 Helm 的調研

既然都說 HelmKubernetes 的包管理工具,那麼我就先去嘗試了一下 Helm

Helm 是 Deis 開發的一個用於 Kubernetes 應用的包管理工具,主要用來管理 Charts。有點類似於 Ubuntu 中的 APT 或 CentOS 中的 YUM。 Helm Chart 是用來封裝 Kubernetes 原生應用程序的一系列 YAML 文件。可以在你部署應用的時候自定義應用程序的一些 Metadata,以便於應用程序的分發。 對於應用發佈者而言,可以通過 Helm 打包應用、管理應用依賴關係、管理應用版本並發佈應用到軟件倉庫。 對於使用者而言,使用 Helm 後不用需要編寫複雜的應用部署文件,可以以簡單的方式在 Kubernetes 上查找、安裝、升級、回滾、卸載應用程序。

更多 Helm 的介紹可參考 「Helm 入門指南」 一文。

簡單的看了看,Helm 給我一種大而無當的感覺:它真的是一個做包管理工具的,複雜的 Go Template 體系以及需要單獨存放的 Charts 讓我感覺其更適合對標 UbuntuAPT 或者 macOSBrew。它更像是對外提供一個複雜的可以依據各種配置信息生成適合於不同環境的軟件發佈包,而不是用於我們這種輕量級的部署配置管理的。所以我就放棄使用 Helm 了。

針對 Kustomize 的調研

在這個時候我想起來了在之前 Github Trending 看到的另外一個用戶做 Kubernetes 配置的工具 Kustomize。簡單的說,它就是一個簡化 Kubernetes YAML 編寫的工具。它提供了兩個重要的功能恰好滿足了我的需求。

Kustomize 是一個新晉選手,只有一個 CLI 工具。在 Kubernetes 1.14 之後,甚至這唯一的工具也成為 kubectl 的一部分。 Kustomize 放棄了對模板的要求,改用 Base + Overlay 的方式對應用的原始 YAML 進行派生。Overlay,顧名思義,就是覆蓋。Kustomize 的 Overlay 可以在 Base 的基礎上,通過對 resource、generator、transformer 等的定義,形成新的應用定義,不論 Base 還是 Overlay,都可以通過 kustomize build 生成有效的 YAML。

Kustomize 的特色

  1. 功能簡單清晰,kubectl 直接支持。
  2. 不考慮派生,僅作為應用的 YAML 組織方式也很有幫助。
  3. 自身支持插件。

繼承和 Patch

Kustomize 可以設置如下的層次:

├── base  │   ├── deployment.yaml  │   ├── kustomization.yaml  │   └── service.yaml  └── overlays      └── stg          ├── ingress.yaml          └── kustomization.yaml

其中 base 里保存各個環境所有的公有配置 base/kustomization.yaml:

resources:  - deployment.yaml  - service.yaml

然後在 overlays 中可以定義子環境 overlays/stg/kustomization.yaml:

bases:  - ../../base    resources:  - ingress.yaml

可以看到 stg 下繼承了 base 的配置,並且添加了 ingress.yaml 配置。同時,Kustomize 不僅僅支持文件級別的 patch,還支持對一個文件某些字段的 patch。

如下圖所示,replica_count.yaml 只包含了有關 replicas 的部分即可,在執行 kustomize build 之後就可以將這部分覆蓋默認的配置。

edit 命令

Kustomize 提供了一個命令行方法對鏡像 Tag 進行修改:

$ kustomize edit set imagetag xxx:94c269ec

如果想更方便的使用,你還可以這麼做:

$ export NEWTAG=94c269ec  $ kustomize edit set imagetag xxx:$NEWTAG

那麼每次都去 ctrl-r 修改這個 export 然後再 ctrl-r 找到第二條命令執行一下就好了。雖然它還是修改了 kustomization.yaml 但是我覺得比打開編輯器改要舒服一些。

Kustomize 額外加分項

輕量級

相對 HelmKustomize 依然保留了對 kubectl apply -f 命令的支持,僅僅作為一個命令行工具;不像 Helm 還需要在 K8s 裏面部署一個 Tiller 可謂是非常的輕量級了。

對 Secret 和 Configmap 的支持

分別舉例說明:

bases:  - ../../base    configMapGenerator:  - literals:    - STORAGE.DATASETUPLOADURL=https://xxx/files/datasets    - STORAGE.CODEUPLOADURL=https://xxx/files/codes    - LIVELOG_PREFIX=https://xxx/jobs    name: storage-server    resources:  - ingress.yaml    imageTags:  - name: xxx    newTag: dc12c4d7
resources:  - deployment.yaml    secretGenerator:  - name: notification-service    commands:      SHORT_MESSAGE_API_KEY: "bash -c 'echo -n $SHORT_MESSAGE_API_KEY'"      MG_API_KEY: "bash -c 'echo -n $MG_API_KEY'"    type: Opaque    generatorOptions:    disableNameSuffixHash: true

secretGeneratorconfigMapGenerator 可以以更靈活的方式生成 configmapsecret,相對來說更方便吧。

然後注意看我 configMapGenerator 的例子,echo -n $xxx 是會有問題的,一定要使用 "bash -c 'echo -n $SHORT_MESSAGE_API_KEY'" 的命令。

Kustomize 和 Helm 的區別

我認為他們的區別主要在工作流程上:

  1. Helm 的基礎流程比較瀑布:定義 Chart->填充->運行,在 Chart 中沒有定義的內容是無法更改的;
  2. Kustomize 的用法比較迭代:Base 和 Overlay 都是可以獨立運作的,增加新對象,或者對編寫 Base 時未預料的內容進行變更,都不在話下。

例如:我們定義了一個很基礎的應用,由 Deployment + Service 組成,如果後續部署中需要完成兩個變更:新建 Ingress 對象和修改鏡像地址/名稱/TAG。

  1. 使用 Helm 你需要的步驟:
  • 在 Chart 中加入對 Ingress 的定義
  • 用變量控制 Ingress 是否進行渲染
  • Ingress 模板應該包含特定的主機名、註解等變量
  • 把鏡像也定義成變量
  • 在 Values.yaml 中對這些變量進行賦值。
  1. 使用 Kustomize 你需要的步驟:
  • 無需對 Base 進行修改
  • 直接在新的 Overlay 中寫入 Ingress Resource
  • 使用內置的 image transformer 替換原有鏡像

結論

要公開發佈一個較為複雜的應用,編寫良好的 Chart 能給用戶很大幫助,用戶通過對 values.yaml 的閱讀,就能對這種複雜的部署產生一個較為深入的認識。

如果是常見的業務應用,因為不同部署之間的差異不大,用 Kustomize 可能會是一個更好的選擇。

參考文檔

  1. https://www.google.com
  2. https://aisensiy.github.io/2018/11/27/helm-and-kustomize/
  3. https://blog.fleeto.us/post/helm-vs-kustomize/