容器格式已成為封裝應用程式的事實標準,而與有許多工具可以協助建立容器映像檔。從我觀察到的趨勢來看,容器建置和佈署工具正朝著更深度整合Kubernetes生態系統的方向發展。

雖然Kubernetes本身不建立容器映像檔,但像Shipwright這樣的工具透過與Kubernetes API生態系統的互動,增加了這一功能。這種方法提高了開發速度和環境一致性,將複雜性委託給平台。

在接下來的開發實踐中,我們將看到如何使用Kustomize或Helm控制容器在Kubernetes上的佈署,以及如何增加自動化來支援高可擴充套件性的工作負載與CI/CD和GitOps。

從容器建置到資源管理的整合工作流程

在實際的開發環境中,Shipwright和Kustomize可以形成一個強大的組合:Shipwright負責將原始碼轉換為容器映像檔,而Kustomize則管理這些映像檔在Kubernetes中的佈署。這種整合工作流程具有以下優勢:

  1. 一致性 - 整個流程都在Kubernetes API的範圍內,確保環境一致性
  2. 自動化 - 可以輕鬆地將這些工具整合到CI/CD管道中
  3. 可擴充套件性 - 隨著應用程式的增長,這些工具可以優雅地擴充套件
  4. 可追蹤性 - 整個過程中的每個步驟都可以被追蹤和稽核

這種整合的工作流程為開發團隊提供了一個無縫的體驗,從原始碼到生產佈署,所有步驟都可以自動化和標準化。

容器技術和Kubernetes生態系統正在迅速發展,但Shipwright和Kustomize等工具為我們提供了一個堅實的基礎,使我們能夠充分利用這些技術的優勢,同時降低管理複雜性。透過採用這些工具和實踐,開發團隊可以更專注於構建優秀的應用程式,而不是被基礎設施的細節所困擾。

Kubernetes 組態管理的現代解決方案 - Kustomize

在雲原生時代,Kubernetes 已成為容器協調的標準,但隨之而來的是如何有效管理大量 Kubernetes 設定檔案的挑戰。在多環境佈署、設定變更與版本控制等場景中,傳統的組態管理方式往往顯得力不從心。

Kustomize 作為 Kubernetes 原生的組態管理工具,提供了一種宣告式的方法來自定義和組合 Kubernetes 資源,無需使用範本引擎就能實作強大的設定變更和環境適配。本文將深入剖析 Kustomize 的核心功能和實戰應用,幫助你掌握這個強大工具。

Kustomize 的核心優勢

在開始探討之前,我想分享為何 Kustomize 在眾多組態管理工具中脫穎而出:

  1. 無侵入性設計 - Kustomize 不會修改原始 YAML 檔案,確保基礎設定的完整性
  2. 原生整合 - 從 Kubernetes 1.14 開始,kubectl 已原生支援 Kustomize 功能
  3. 根據補丁機制 - 透過疊加補丁實作設定變更,符合 GitOps 最佳實踐
  4. 無需學習新語法 - 不像 Helm 等工具需要學習範本語言,降低了學習成本

接下來,讓我們透過實際案例來探索 Kustomize 的強大功能。

Kustomize 基礎設定與資源管理

YAML 輸出解析

當我們使用 Kustomize 處理設定時,實際上是在生成最終的 Kubernetes YAML 資源定義。以下是一個典型的 Kustomize 輸出範例:

apiVersion: v1
items:
- apiVersion: v1
  kind: Namespace
  metadata:
    name: pacman
- apiVersion: v1
  kind: Service
  metadata:
    labels:
      app.kubernetes.io/name: pacman-kikd
    name: pacman-kikd
    namespace: pacman
  spec:
    ports:
    - name: http
      port: 8080
      targetPort: 8080
    selector:
      app.kubernetes.io/name: pacman-kikd
- apiVersion: apps/v1
  kind: Deployment
  metadata:
    labels:
      app.kubernetes.io/name: pacman-kikd
    name: pacman-kikd
    namespace: pacman
  spec:
    replicas: 1
    selector:
      matchLabels:
        app.kubernetes.io/name: pacman-kikd
    template:
      metadata:
        labels:
          app.kubernetes.io/name: pacman-kikd
      spec:
        containers:
        - image: lordofthejars/pacman-kikd:1.0.0
          imagePullPolicy: Always
          name: pacman-kikd
          ports:
          - containerPort: 8080
            name: http
            protocol: TCP
kind: List
metadata: {}

這個 YAML 輸出包含了三個 Kubernetes 資源:

  • 一個 Namespace 資源,建立名為 “pacman” 的名稱空間
  • 一個 Service 資源,為應用提供網路存取
  • 一個 Deployment 資源,定義應用的佈署規格

這是 Kustomize 處理 kustomization.yaml 後生成的完整定義,可以直接應用到 Kubernetes 叢集中。

Kustomization 資源組合能力

Kustomize 的一大優勢是能夠組合和參照不同來源的資源。我們可以透過目錄結構來組織不同層級的設定:

.
├── base
│   ├── kustomization.yaml
│   └── deployment.yaml
├── kustomization.yaml
├── configmap.yaml

在這個結構中,base 目錄包含基礎設定,而根目錄的 kustomization.yaml 則參照這些基礎設定並增加自定義內容。

base/kustomization.yaml 可能如下所示:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ./deployment.yaml

而根目錄的 kustomization.yaml 則可能是:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ./base
- ./configmap.yaml

這種結構實作了設定的分層管理:

  1. base 目錄包含基礎佈署設定
  2. 根目錄的 kustomization.yaml 參照 base 目錄,並增加了 configmap.yaml
  3. 當應用根目錄的 kustomization.yaml 時,Kustomize 會自動處理並合併所有參照的資源

這種分層方法特別適合多環境佈署,例如可以有 base、dev、staging、production 等不同層級的設定。

外部資源參照

Kustomize 還支援參照外部資源,例如 GitHub 上的資源函式庫

resources:
- github.com/lordofthejars/mysql
- github.com/lordofthejars/mysql?ref=test

這個設定參照了 GitHub 上的兩個資源:

  1. 第一行參照主分支上的 mysql 資源
  2. 第二行參照 test 分支上的 mysql 資源

這種機制允許我們復用社群中已有的設定,大提高了開發效率。

Kustomize CLI 工具

除了透過 kubectl 使用 Kustomize 功能外,Kustomize 還提供了獨立的 CLI 工具,功能更為豐富:

kustomize build

執行此命令會輸出處理後的 YAML 檔案,與前面展示的輸出相同。如果要直接應用到叢集,可以使用管道:

kustomize build . | kubectl apply -f -

這種方式在需要檢視生成的 YAML 或進行除錯時特別有用。

容器映像更新策略

更新容器映像標籤

在實際開發中,映像版本更新是最常見的操作之一。Kustomize 提供了簡單的方式來更新容器映像標籤。

假設我們有以下佈署設定:

spec:
  containers:
  - image: lordofthejars/pacman-kikd:1.0.0
    imagePullPolicy: Always
    name: pacman-kikd

要將版本從 1.0.0 更新到 1.0.1,只需在 kustomization.yaml 中增加:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ./namespace.yaml
- ./deployment.yaml
- ./service.yaml
images:
- name: lordofthejars/pacman-kikd
  newTag: 1.0.1

images 區塊定義了映像更新規則:

  • name 指定要更新的映像名稱
  • newTag 設定新的標籤值

這樣,無需修改原始 deployment.yaml 檔案,就能在生成的 YAML 中將映像標籤更新為 1.0.1。

使用 Kustomize CLI 更新映像

除了手動編輯 kustomization.yaml 外,還可以使用 Kustomize 命令列工具更新映像標籤:

kustomize edit set image lordofthejars/pacman-kikd:1.0.2

執行後,kustomization.yaml 檔案中的 newTag 會自動更新為 1.0.2。這種方式特別適合自動化流程,例如在 CI/CD 管道中自動更新映像版本。

通用資源修改技巧

使用 JSON Patch 修改任意欄位

除了更新映像標籤外,Kustomize 還支援使用 JSON Patch 來修改任何 Kubernetes 資源欄位。例如,要將副本數從 1 更改為 3:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ./deployment.yaml
patches:
- target:
    version: v1
    group: apps
    kind: Deployment
    name: pacman-kikd
    namespace: pacman
  patch: |-
    - op: replace
      path: /spec/replicas
      value: 3

這個設定使用 JSON Patch 格式修改資源:

  • target 區塊精確定位要修改的資源
  • patch 區塊定義了修改操作:
    • op: replace 表示替換操作
    • path: /spec/replicas 指定要修改的欄位路徑
    • value: 3 設定新值為 3

當執行 kustomize build 時,生成的 Deployment 資源中的副本數會變為 3。

使用專用欄位更新副本數

對於常見的設定變更,Kustomize 提供了專用欄位。例如,更新副本數可以使用更簡潔的方式:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
replicas:
- name: pacman-kikd
  count: 3
resources:
- deployment.yaml

replicas 區塊提供了更簡潔的語法來更新副本數:

  • name 指定要更新的佈署名稱
  • count 設定新的副本數

這種方式比 JSON Patch 更簡潔,適用於常見的副本數調整場景。

深入理解 Kustomize 工作原理

在我使用 Kustomize 的過程中,發現其核心工作原理是根據資源疊加和補丁機制。與傳統的範本引擎不同,Kustomize 不需要學習複雜的範本語法,而是透過宣告式的方式定義資源變更。

當 Kustomize 處理設定時,會按照以下步驟工作:

  1. 載入所有在 resources 區塊中定義的基礎資源
  2. 應用 patches 和其他自定義區塊(如 imagesreplicas 等)定義的變更
  3. 生成最終的 YAML 資源定義

這種機制保證了基礎資源的不可變性,同時提供了強大的自定義能力,非常適合 GitOps 工作流程。

Kustomize vs Helm:何時選擇哪一個?

在雲原生態系統中,Kustomize 和 Helm 是兩個主要的組態管理工具,它們各有優缺點。

從我的實踐經驗來看,Kustomize 在以下場景中表現出色:

  • 需要對現有 Kubernetes 資源進行小幅調整
  • 團隊偏好宣告式設定而非範本
  • 已有大量現成的 YAML 設定需要復用
  • 設定變更相對簡單,主要是環境差異

而 Helm 則更適合:

  • 需要分享和發布完整應用
  • 設定邏輯複雜,需要條件陳述式和迴圈等功能
  • 需要版本管理和回復機制

在實際專案中,我經常看到兩者結合使用的情況:使用 Helm 安裝基礎應用,然後使用 Kustomize 進行環境特定的調整。

Kustomize 最佳實踐

根據我在多個專案中的實踐經驗,總結了以下 Kustomize 使用的最佳實踐:

  1. 維護清晰的目錄結構:使用 base 和環境特定目錄(如 overlays/devoverlays/prod)組織設定

  2. 保持基礎設定的通用性:base 目錄中的設定應盡可能通用,環境特定的變更放在 overlays 中

  3. 優先使用專用欄位:對於常見變更(如映像標籤、副本數等),優先使用 Kustomize 提供的專用欄位,而非通用的 patches

  4. 限制補丁範圍:當使用 patches 時,盡量精確指定目標資源,避免意外修改

  5. 版本控制:將 Kustomize 設定納入版本控制系統,便於追蹤變更歷史

  6. 使用 build 命令驗證:在應用前使用 kustomize build 命令檢查生成的 YAML,確保變更符合預期

這些實踐可以幫助團隊更有效地管理 Kubernetes 設定,減少佈署錯誤。

進階:使用 Kustomize 實作多環境設定

在實際專案中,多環境設定是一個常見需求。以下是一個典型的多環境 Kustomize 目錄結構:

.
├── base
│   ├── deployment.yaml
│   ├── kustomization

## Kustomize 的資源修補技術:超越基本組態管理

在 Kubernetes 的世界裡,資源管理與設定修改可能會成為一項挑戰。隨著應用程式規模的擴大,環境的多樣化,手動修改 YAML 檔案不僅耗時與容易出錯。這時,Kustomize 作為 Kubernetes 原生的組態管理工具,提供了強大的資源修補功能,讓我們能夠以更有條理、更可靠的方式管理資源變更。

### JSON Patch:精準修改 Kubernetes 資源

Kustomize 支援使用 JSON Patch 表示式來精確修改 Kubernetes 資源。這種方法允許我們對資源進行細粒度的變更,而不需要複製整個資源定義。

在實際應用中,我經常使用 JSON Patch 來調整佈署規格或增加新的標籤。例如,以下是一個修改佈署副本數量並增加新標籤的 Kustomize 設定:

```yaml
patches:
- target:
    version: v1
    group: apps
    kind: Deployment
    name: pacman-kikd
    namespace: pacman
  patch: |-
    - op: replace
      path: /spec/replicas
      value: 3
    - op: add
      path: /metadata/labels/testkey
      value: testvalue

這段設定做了兩件事:首先使用 replace 操作將佈署的副本數從原本的值修改為 3;其次使用 add 操作在資源的 metadata 標籤中增加了一個鍵為 testkey、值為 testvalue 的新標籤。JSON Patch 的強大之處在於它允許我們精確定位資源結構中的特定路徑,並對其進行修改、增加或刪除操作。

應用這個修補後,原始的佈署資源會轉變為:

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app.kubernetes.io/name: pacman-kikd
    testkey: testvalue
  name: pacman-kikd
  namespace: pacman
spec:
  replicas: 3
  selector:
    ...

外部修補檔案:提高可維護性

對於較複雜的修補操作,將 JSON Patch 表示式放在外部檔案中可以提高可維護性。這種方法特別適合團隊環境,因為它讓修補邏輯更容易被審核和理解。

我們可以建立一個名為 external_patch.yaml 的外部修補檔案:

- op: replace
  path: /spec/replicas
  value: 3
- op: add
  path: /metadata/labels/testkey
  value: testvalue

然後在 Kustomize 設定中參照這個檔案:

patches:
- target:
    version: v1
    group: apps
    kind: Deployment
    name: pacman-kikd
    namespace: pacman
  path: external_patch.yaml

策略性合併修補:更人工智慧的資源修改

除了 JSON Patch,Kustomize 還支援策略性合併修補(Strategic Merge Patch,簡稱 SMP)。這是一種更人工智慧的修補方式,特別適合 Kubernetes 資源。

SMP 的優勢在於它理解 Kubernetes 資源的結構,因此可以更人工智慧地處理陣列和其他複雜資料結構。例如,要更新容器映像,我們只需提供最小的佈署檔案:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ./deployment.yaml
patches:
- target:
    labelSelector: "app.kubernetes.io/name=pacman-kikd"
  patch: |-
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: pacman-kikd
    spec:
      template:
        spec:
          containers:
          - name: pacman-kikd
            image: lordofthejars/pacman-kikd:1.2.0

在這個例子中,我們使用標籤選擇器來定位目標資源,然後提供了一個最小化的佈署檔案作為修補。Kustomize 夠聰明,能夠自動檢測這是一個 SMP 而非 JSON Patch。實際應用時,它會保留原始佈署檔案中的所有其他欄位,只更新我們指定的容器映像。

這種方法的優雅之處在於我們只需專注於要更改的部分,而不必擔心整個資源定義。對於容器映像更新這類別常見操作,SMP 提供了更簡潔的解決方案。

多環境佈署策略:一次編寫,多處執行

在實際的開發流程中,我們通常需要將同一應用程式佈署到不同的環境中—例如開發、測試和生產環境。每個環境可能需要稍微不同的設定,如名稱空間、容器映像標籤或資源限制。

Kustomize 透過其覆寫(overlay)功能優雅地解決了這個問題,讓我們能夠在分享基礎設定的同時,為每個環境定義特定的變更。

根據名稱空間的多環境設定

讓我們看一個將同一應用佈署到 staging 和 production 環境的例子。首先,我們需要建立一個目錄結構:

.
├── base
│   ├── deployment.yaml
│   └── kustomization.yaml
├── production
│   └── kustomization.yaml
└── staging
    └── kustomization.yaml

在基本目錄中,kustomization.yaml 檔案參照了所有基礎資源:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ./deployment.yaml

對於 staging 環境,我們可以定義特定的修改:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../base
namespace: staging
images:
- name: lordofthejars/pacman-kikd
  newTag: 1.2.0-beta

這個 staging 環境的設定做了兩件事:首先,它參照了基本目錄中的資源作為起點;其次,它指定了所有資源應該佈署到 staging 名稱空間,並將容器映像標籤設定為 1.2.0-beta

生產環境的設定類別似,但使用不同的名稱空間和映像標籤:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../base
namespace: prod
images:
- name: lordofthejars/pacman-kikd
  newTag: 1.1.0

當我們在 staging 目錄中執行 kustomize build 命令時,會生成適用於 staging 環境的資源定義,包括正確的名稱空間和映像標籤。同樣,在 production 目錄中執行相同命令會生成適用於生產環境的資源。

使用字首和字尾增強資源識別

在某些情況下,我們可能希望根據環境增加資源名稱字首或字尾,以便更容易識別不同環境中的資源。Kustomize 提供了 namePrefixnameSuffix 欄位來實作這一點:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../base
namespace: staging
namePrefix: staging-
nameSuffix: -v1-2-0
images:
- name: lordofthejars/pacman-kikd
  newTag: 1.2.0-beta

應用這個設定後,原始資源名稱 pacman-kikd 將變成 staging-pacman-kikd-v1-2-0。這種命名模式使得在日誌或監控工具中識別不同環境的資源變得更加容易。同時,Kustomize 會自動更新所有參照這些資源的其他資源,確保參照關係保持一致性。

這種根據環境的設定方法不僅簡化了多環境佈署,還提高了設定的可維護性,因為大部分設定保持不變,只有環境特定的部分需要單獨維護。

在 Kustomize 中生成 ConfigMap

ConfigMap 是 Kubernetes 中管理應用程式設定的關鍵資源。在 Kustomize 中,我們有兩種方式處理 ConfigMap:將其作為普通資源增加,或使用 ConfigMapGenerator 動態生成。

ConfigMapGenerator 的優勢

使用 ConfigMapGenerator 而非直接宣告 ConfigMap 有一個顯著優勢:它會自動在 ConfigMap 名稱後附加一個雜湊值,並更新參照該 ConfigMap 的佈署資源。這個看似微小的變化實際上對應用程式生命週期管理有重大影響。

讓我們考慮一個場景:應用程式使用 ConfigMap 儲存資料函式庫超時設定。當我們需要增加這個值時,修改 ConfigMap 並重新佈署。然而,如果 ConfigMap 是唯一變更的資源,Kubernetes 不會自動觸發應用程式的滾動更新,因此新的設定不會生效。

使用 ConfigMapGenerator 時,任何設定檔的變更都會導致 ConfigMap 名稱中的雜湊值發生變化,這進而會觸釋出署資源的更新。由於佈署定義已經變更,Kubernetes 會自動執行滾動更新,確保應用程式使用新的設定。

實際應用 ConfigMapGenerator

ConfigMapGenerator 的另一個優勢是它可以將多個設定檔合併到單個 ConfigMap 中。這對於每個環境有不同設定檔的情況特別有用。

例如,我們可以這樣定義一個 ConfigMapGenerator:

configMapGenerator:
- name: game-config
  files:
  - game.properties
  - ui.properties

這個設定會從兩個檔案 game.propertiesui.properties 生成一個名為 game-config-[hash] 的 ConfigMap,其中 [hash] 是根據檔案內容計算的雜湊值。如果任一檔案內容發生變化,雜湊值也會變化,進而觸發應用程式的更新。

我們還可以直接在 Kustomization 檔案中指定鍵值對:

configMapGenerator:
- name: db-config
  literals:
  - DB_HOST=mysql
  - DB_PORT=3306
  - DB_TIMEOUT=30s

當這些值發生變更時,生成的 ConfigMap 名稱也會變化,確保應用程式始終使用最新的設定。

停用雜湊字尾

在某些情況下,我們可能不希望 ConfigMap 名稱包含雜湊字尾。例如,如果 ConfigMap 被外部系統參照,或者我們希望保持名稱穩定以便手動檢查。Kustomize 允許我們透過 disableNameSuffixHash 選項停用雜湊字尾:

configMapGenerator:
- name: game-config
  files:
  - game.properties
  disableNameSuffixHash: true

這會生成一個名稱固定為 game-config 的 ConfigMap,但此時我們失去了自動觸發更新的能力。

管理環境特定的設定變數

在多環境佈署中,不同環境通常需要不同的設定變數。Kustomize 允許我們為每個環境單獨定義 ConfigMap 或使用不同的檔案作為輸入。

例如,在基礎目錄中,我們可以有一個通用的設定生成器:

# base/kustomization.yaml
configMapGenerator:
- name: app-config
  files:
  - common-config.properties

然後在每個環境特定的目錄中,我們可以覆寫或擴充這個設定:

# staging/kustomization.yaml
configMapGenerator:
- name: app-config
  behavior: merge
  files:
  - staging-config.properties
# production/kustomization.yaml
configMapGenerator:
- name: app-config
  behavior: merge
  files:
  - production-config.properties

behavior: merge 選項告訴 Kustomize 將環境特定的設定與基礎設定合併,而不是完全替換它。這樣,我們可以在基礎設定中定義共用的設定,並在每個環境中只指定需要改變的部分。

透過這種方式,我們能夠維護一套基礎設定,同時為每個環境提供所需的特定設定,大簡化了多環境組態管理。

在實際專案中

Kustomize 進階應用:動態 ConfigMap 管理

在 Kubernetes 的資源管理中,ConfigMap 是儲存應用程式組態資料的重要元件。搭配 Kustomize 的 ConfigMapGenerator,我們可以實作更靈活的組態管理方式,特別是在需要經常變更組態時,這種方法能自動觸發應用程式的滾動更新。

ConfigMapGenerator 實戰應用

讓我們從一個簡單的例子開始。首先建立一個包含 ConfigMapGenerator 的 kustomization.yaml 檔案。

佈署檔案與前面章節類別似,但增加了 volumes 區段來掛載 ConfigMap:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: pacman-kikd
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: pacman-kikd
  template:
    metadata:
      labels:
        app.kubernetes.io/name: pacman-kikd
    spec:
      containers:
      - image: lordofthejars/pacman-kikd:1.0.0
        imagePullPolicy: Always
        name: pacman-kikd
        volumeMounts:
        - name: config
          mountPath: /config
      volumes:
      - name: config
        configMap:
          name: pacman-configmap  # 這個名稱會在 kustomization.yaml 中使用

接下來,在 kustomization.yaml 中定義 ConfigMapGenerator,動態產生 ConfigMap:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ./deployment.yaml
configMapGenerator:
- name: pacman-configmap  # 對應佈署檔案中的 ConfigMap 名稱
  literals:
  - db-timeout=2000
  - db-username=Ada
  • 這個 kustomization.yaml 檔案使用 configMapGenerator 區段動態產生 ConfigMap
  • name: pacman-configmap 定義了 ConfigMap 的基本名稱
  • literals 區段允許直接在檔案中定義鍵值對
  • 範例中設定了兩個組態專案:資料函式庫間和使用者名稱

使用以下命令建構最終的 Kubernetes 資源清單:

kustomize build

執行此命令後,Kustomize 會產生一個新的 ConfigMap,並自動附加雜湊值到名稱後面:

apiVersion: v1
data:
  db-timeout: "2000"
  db-username: Ada
kind: ConfigMap
metadata:
  name: pacman-configmap-96kb69b6t4  # 注意這裡的雜湊值
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app.kubernetes.io/name: pacman-kikd
  name: pacman-kikd
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: pacman-kikd
  template:
    metadata:
      labels:
        app.kubernetes.io/name: pacman-kikd
    spec:
      containers:
      - image: lordofthejars/pacman-kikd:1.0.0
        imagePullPolicy: Always
        name: pacman-kikd
        volumeMounts:
        - mountPath: /config
          name: config
      volumes:
      - configMap:
          name: pacman-configmap-96kb69b6t4  # 與上方產生的 ConfigMap 名稱相符
        name: config

自動觸發滾動更新

Kustomize 的一個強大特性是當組態值變更時,會自動計算新的雜湊值,這會觸發應用程式的滾動更新。讓我們修改 kustomization.yaml 檔案中的 db-timeout 值,從 2000 改為 1000:

configMapGenerator:
- name: pacman-configmap
  literals:
  - db-timeout=1000  # 值從 2000 改為 1000
  - db-username=Ada

再次執行 kustomize build,可以看到 ConfigMap 名稱的雜湊值已經變更:

apiVersion: v1
data:
  db-timeout: "1000"
  db-username: Ada
kind: ConfigMap
metadata:
  name: pacman-configmap-6952t58tb4  # 新的雜湊值
---
apiVersion: apps/v1
kind: Deployment
...
volumes:
- configMap:
    name: pacman-configmap-6952t58tb4  # 佈署也自動更新為新的 ConfigMap
  name: config
  • ConfigMapGenerator 會為每個 ConfigMap 生成一個根據內容的雜湊值
  • 當組態內容變更時,雜湊值也會變更,產生新的 ConfigMap 名稱
  • 佈署中參照的 ConfigMap 名稱會自動更新,這會觸發 Kubernetes 的滾動更新
  • 這個機制確保組態變更後,應用程式會自動重新佈署以使用新的組態

合併組態屬性

ConfigMapGenerator 還支援從不同來源合併組態屬性,這對於環境特定設定非常有用。

例如,建立一個 dev_literals 目錄,並在其中新增 kustomization.yaml 檔案:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../literals  # 指向基礎目錄

configMapGenerator:
- name: pacman-configmap
  behavior: merge  # 合併行為(也可以是 create 或 replace)
  literals:
  - db-username=Alexandra  # 覆寫基礎組態中的值

執行 kustomize build 命令,會產生包含合併後組態屬性的 ConfigMap:

apiVersion: v1
data:
  db-timeout: "1000"  # 繼承自基礎目錄
  db-username: Alexandra  # 覆寫的值
kind: ConfigMap
metadata:
  name: pacman-configmap-ttfdfdk5t8
  • behavior: merge 指示 Kustomize 將這個 ConfigMapGenerator 的內容與基礎目錄中的合併
  • 當兩個 ConfigMapGenerator 有相同的鍵時,覆寫層級的值會優先
  • 這種方法非常適合維護環境特定的組態差異(如開發環境、測試環境和生產環境)
  • 雜湊值會根據合併後的完整內容計算,確保任何變更都會觸發更新

使用屬性檔案定義組態

除了直接在 kustomization.yaml 中定義組態值外,Kustomize 還支援從 .properties 檔案讀取組態。

建立一個 connection.properties 檔案:

db-url=prod:4321/db
db-username=ada

然後在 kustomization.yaml 中使用 files 欄位而非 literals:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ./deployment.yaml
configMapGenerator:
- name: pacman-configmap
  files:
  - ./connection.properties  # 屬性檔案的路徑

執行 kustomize build 命令會產生以下 ConfigMap:

apiVersion: v1
data:
  connection.properties: |-
    db-url=prod:4321/db
    db-username=ada
kind: ConfigMap
metadata:
  name: pacman-configmap-g9dm2gtt77
  • 使用 files 欄位指定要包含在 ConfigMap 中的檔案
  • 檔案的名稱會成為 ConfigMap 中的鍵,檔案的內容會成為值
  • 這種方法特別適合處理較大的組態檔案或需要保持特定格式的組態
  • 與 literals 方法相同,任何檔案內容的變更都會導致雜湊值變更,進而觸發滾動更新

Kustomize 與 Helm 的比較

Kustomize 是一個簡單但功能強大的工具,它採用無範本技術,允許你定義純 YAML 檔案並使用合併策略或 JSON Patch 表示式覆寫值。專案結構非常自由,你可以根據個人喜好定義目錄佈局,唯一的要求是存在 kustomization.yaml 檔案。

但還有另一個知名的 Kubernetes 資源管理工具:Helm。玄貓認為 Helm 稍微複雜一些,但功能更強大,特別是當要佈署的應用程式或服務有多個依賴項(如資料函式庫件伺服器、快取等)時。

Helm 簡介與基礎

Helm 與 Kustomize 的運作方式類別似,但它是一個範本解決方案,更像是套件管理器,生成可版本化、可分享或可佈署的成品。Helm 使用 Go 範本語言處理 YAML 檔案,幫助安裝和管理 Kubernetes 應用程式。

建立 Helm 專案

不同於 Kustomize(可以在 kubectl 命令中使用或作為獨立的 CLI 工具),Helm 需要下載並安裝在本機上。Helm 是 Kubernetes 的套件管理器,它將相關的資源清單檔案封裝成單一的邏輯佈署單元:圖表。

Helm 圖表 對於解決安裝複雜性和簡化應用程式升級非常有用。在此我們使用 Helm 3.7.2,你可以從 GitHub 下載並安裝到你的 PATH 目錄中。

按照以下步驟建立一個 Helm 圖表 目錄結構:

  1. 首先建立必要的目錄:
mkdir pacman
mkdir pacman/templates
cd pacman
  1. 接著建立三個檔案:
    • 一個定義 圖表 的檔案
    • 一個使用 Go 範本語言和 Sprig 函式庫署範本
    • 一個包含應用程式組態值的檔案
  • Helm 專案遵循特定的目錄結構,其中 templates 目錄包含所有的 Kubernetes 資源範本
  • 與 Kustomize 不同,Helm 使用根據 Go 的範本系統,允許更複雜的邏輯和條件
  • Helm 的主要優勢在於它的套件管理功能,可以將應用程式及其依賴項封裝為可分享的 圖表
  • 這種方法特別適合複雜的微服務架構,其中多個服務需要協同佈署

Helm vs Kustomize:何時選擇何者?

在選擇 Kustomize 或 Helm 時,可以考慮以下因素:

  1. 專案複雜度

    • 對於簡單的應用程式或單一服務,Kustomize 通常足夠與更易於上手
    • 對於包含多個相互依賴元件的複雜應用程式,Helm 的套件管理功能更有價值
  2. 團隊經驗

    • Kustomize 的學習曲線較平緩,不需要學習特定的範本語言
    • Helm 需要學習 Go 範本語言,但提供更強大的功能
  3. 重用性需求

    • 如果需要建立可分享、可重複使用的佈署套件,Helm 是更好的選擇
    • 如果主要關注特定環境的客製化,Kustomize 可能更合適
  4. 組態管理方式

    • Kustomize 使用覆寫和修補的方法,保持原始 YAML 不變
    • Helm 使用範本和值檔案,可能更適合需要大量變數的場景

玄貓在實際專案中經常兩者結合使用:使用 Helm 管理複雜的應用程式結構和依賴關係,然後在特定環境中使用 Kustomize 進行最終的客製化調整。這種組合方法結合了兩個工具的優點,提供了強大而靈活的解決方案。