iT邦幫忙

2025 iThome 鐵人賽

DAY 26
0
DevOps

30 天挑戰 CKAD 認證!菜鳥的 Kubernetes 學習日記系列 第 26

【Day26】Kustomize:不用模板也能客製化 Kubernetes 配置 - Part2

  • 分享至 

  • xImage
  •  

gh

前情提要

昨天我們認識了 Kustomize 這個 Kubernetes 原生的配置管理工具。從實際的痛點出發,了解到當需要在多個環境部署相同應用時,複製和維護多份 YAML 檔案會造成管理上的困難。Kustomize 透過 BaseOverlays 的概念解決了這個問題,讓我們能夠重複使用基礎配置,只針對不同環境修改需要變更的部分。

昨天我們只看了 Kustomize 的基礎功能。今天我們將深入研究 Kustomize 真正強大的地方:TransformersPatches。這些進階功能讓我們能夠精確地修改資源配置、管理不同環境的映像檔版本、建立可重用的配置片段,真正發揮 Kustomize 在多環境部署管理上的威力。

Transformers:統一配置修改

Transformers 是 Kustomize 提供的統一修改機制,讓我們能夠對多個資源進行批次性的配置調整,而不需要逐一修改每個 YAML 檔案。這種批次修改的能力在管理大量資源時特別有用,能大幅減少重複工作並降低人為錯誤的機率。

Common Transformers

當我們需要對所有 Kubernetes 資源進行統一的配置修改時,Common Transformers 就是最佳選擇。比如說,我們想為所有資源加上公司的標籤、統一 Namespace、或是添加共同的前綴後綴,這些都可以透過 Transformers 輕鬆完成。

Kustomize 提供了幾種常用的 Transformers:

  • commonLabels / labels:可以為所有資源添加共同的標籤,這在管理資源和設定網路政策時特別有用。透過標籤,我們可以輕鬆篩選和管理相關資源,也能讓 Service 正確選擇到對應的 Pod
  • namePrefixnameSuffix:讓我們能為所有資源名稱加上前綴或後綴,方便區分不同環境的資源。例如在同一個叢集中部署多個版本時,可以透過前綴來避免名稱衝突
  • namespace:能將所有資源統一放入特定的命名空間中,這在多租戶環境或是想要隔離不同應用時非常實用
  • commonAnnotations:可以為所有資源添加註釋,用於記錄元資料或觸發特定的控制器行為,例如記錄部署者資訊、觸發 GitOps 工具的同步等

這些 Transformers 的強大之處在於作用範圍的靈活性。如果在根目錄的 kustomization.yaml 中定義時,它會影響所有被引入的資源;而如果在子目錄中定義時,則只會影響該目錄下的資源。這種階層式的設計讓配置管理變得非常靈活,可以在全域層級設定共通規則,同時在特定子系統中套用額外的規則。

實戰 🔥

讓我們透過實際操作來理解 Common Transformers 的威力。首先看看我們的資料夾結構:

k8s/
├── kustomization.yaml
├── db/
│   ├── kustomization.yaml
│   ├── nosql/
│   ├── sql/
│   └── db-config.yaml
├── monitoring/
│   ├── kustomization.yaml
│   ├── grafana-depl.yaml
│   └── grafana-service.yaml
└── nginx/
    ├── kustomization.yaml
    ├── nginx-depl.yaml
    └── nginx-service.yaml

gh

情境 1:全域標籤設定

假設我們希望所有子目錄的資源都帶有 sandbox: dev 標籤,只需要在根目錄的 kustomization.yaml 中定義:

# k8s/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
  - db/
  - monitoring/
  - nginx/

labels:
  - includeSelectors: true
    pairs:
      sandbox: dev

注意:我在實戰中有遇到 Warning 訊息,表示新版本中 commonLabels 已被 labels 取代。

gh

這樣一來,db、monitoring、nginx 三個子系統的所有資源都會自動加上這個標籤,不需要在每個 YAML 檔案中重複定義。

情境 2:特定子系統的名稱前綴

現在我們希望所有資料庫相關的資源名稱都以 data- 開頭,這樣可以一眼辨識出這些是資料層的元件:

# k8s/db/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
  - nosql/
  - sql/
  - db-config.yaml

namePrefix: data-

gh

執行 kubectl build k8s/ 後,會看到所有 db 目錄下的資源名稱都被加上了 data- 前綴,例如原本的 postgres-deployment 會變成 data-postgres-deployment。這種做法的好處是保持了原始 YAML 的乾淨,同時又能在部署時自動套用命名規則。

情境 3:隔離命名空間

監控工具通常會獨立部署在專屬的 namespace 中,方便管理和權限控制。我們可以透過 namespace transformer 來實現:

# k8s/monitoring/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
  - grafana-depl.yaml
  - grafana-service.yaml

namespace: logging

gh

這樣 monitoring 資料夾下的所有資源都會被部署到 logging 這個 namespace,而不會影響其他子系統。這種隔離不僅有助於資源管理,也能提供更好的安全邊界。

情境 4:批次添加註釋

如果我們想在 nginx 和 monitoring 的所有資源上標註負責人資訊,可以使用 commonAnnotations

# k8s/monitoring/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
  - grafana-depl.yaml
  - grafana-service.yaml

namespace: logging
commonAnnotations:
  owner: bob@gmail.com
  
# k8s/nginx/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
  - nginx-depl.yaml
  - nginx-service.yaml

commonAnnotations:
  owner: bob@gmail.com

gh

這樣做的好處是,當團隊成員看到這些資源時,能立即知道該聯繫誰。對於 GitOps 工具來說,annotations 也常被用來觸發特定的自動化流程。

Image Transformers

Image Transformers 專門用來管理容器映像檔的版本和來源,這是多環境部署中最常需要調整的配置之一。在不同環境中,我們經常需要使用不同版本的映像檔,或是從不同的 Registry 拉取映像檔。傳統做法需要在每個環境的 YAML 中手動修改 image 欄位,但 Image Transformer 讓這個過程變得優雅且可控。

透過指定 namenewName,可以替換所有使用特定映像檔的容器。如果只想更新標籤,可以使用 newTag 屬性。這在升級應用版本或是回滾時特別有用,不需要修改任何 YAML 檔配置,只要在 kustomization.yaml 中調整映像檔設定即可。更重要的是,這種方式讓版本管理變得集中化,我們可以在一個地方控制所有環境使用的映像檔版本。

值得注意的是,Image Transformer 是根據映像檔名稱來匹配的,而不是容器名稱。它會掃描所有資源,找出使用指定映像檔的容器並進行替換,因此在根目錄使用時需要特別注意影響範圍,避免誤改到不該改的映像檔。

實戰 🔥

情境 1:全域映像檔替換

假設我們的資料庫原本使用 PostgreSQL,但現在要全面改用 MySQL。透過 Image Transformer,我們可以在根目錄一次性替換所有 PostgreSQL 映像檔:

# k8s/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
  - db/
  - monitoring/
  - nginx/

labels:
  - includeSelectors: true
    pairs:
      sandbox: dev

images:
  - name: postgres
    newName: mysql

gh

執行後,所有原本使用 postgres 映像檔的容器都會自動改用 mysql。這種做法避免了在多個 YAML 檔中逐一修改,大幅降低了出錯的機率。

情境 2:特定子系統的版本控制

如果我們只想針對 nginx 子系統指定特定版本,可以在該子系統的 kustomization.yaml 中定義:

# k8s/nginx/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
  - nginx-depl.yaml
  - nginx-service.yaml

commonAnnotations:
  owner: bob@gmail.com

images:
  - name: nginx
    newTag: "1.23"

gh

這樣只有 nginx 資料夾下的 nginx 映像檔會被指定為 1.23 版本,其他地方的 nginx 映像檔(如果有的話)不會受影響。這種細緻的控制能力讓我們可以針對不同子系統採用不同的版本策略,例如讓前端服務使用最新版本,而讓核心服務保持在穩定版本。

Patches:精確修改的藝術

Patches 提供了更精確的修改方式,讓我們能針對特定資源的特定欄位進行修改。不同於 Common Transformers 的全域修改,Patches 允許我們只改變需要改變的部分,其他配置保持原樣。這種精準控制在處理複雜配置時特別重要,因為有些修改只應該影響特定的資源。

Kustomize 提供兩種 Patch 方式:JSON 6902 PatchStrategic Merge Patch,各有其適用場景和優勢。

JSON 6902 Patch

JSON 6902 Patch 遵循 RFC 6902 標準,使用操作指令來修改資源。這種方式的特點是明確和精確,每一個修改動作都清楚地定義了要做什麼。每個 Patch 需要三個要素:

  • operation:操作類型,包括 add(新增)、remove(刪除)、replace(替換)
  • target:目標資源的識別條件,指定要修改哪個資源
  • value:要設定的值(remove 操作不需要此欄位)

路徑的指定是使用 JSON 6902 Patch 的關鍵。路徑使用 JSON Pointer 語法,以 / 分隔各層級。例如要修改 Deployment 的 replicas,路徑是 /spec/replicas;對於列表類型的資源,需要使用索引來指定位置,例如 /spec/template/spec/containers/0 代表第一個容器。

# 修改 replicas
patches:
  - target:
      kind: Deployment
      name: api-deployment
    patch: |-
      - op: replace
        path: /spec/replicas
        value: 5
        
# 修改 Container Image
patches:
  - target:
      kind: Deployment
      name: api-deployment
    patch: |-
      - op: replace
        path: /spec/template/spec/containers/0
        value:
          name: haproxy
          image: haproxy

JSON 6902 Patch 的優勢在於明確性和可預測性,清楚知道每個操作會造成什麼影響。但缺點是需要精確知道資源的結構和路徑,對於列表類型的資源,索引的維護也可能成為負擔。

Strategic Merge Patch

Strategic Merge Patch 的方式更直觀和符合 Kubernetes 使用者的習慣。我們只需要寫出想要修改的部分 YAML,Kustomize 會智慧地將它與原始配置合併。這種方式的最大好處是可讀性高,因為它就是標準的 Kubernetes YAML,不需要學習特殊的語法或記住複雜的路徑。

# 修改 replicas
patches:
  - patch: |-
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: api-deployment
      spec:
        replicas: 5

# 修改 Container Image
patches:
  - patch: |-
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: api-deployment
      spec:
        template:
          spec:
            containers:
              - name: haproxy
                image: haproxy

對於字典類型的資源,Strategic Merge Patch 會智慧地合併鍵值對。如果要刪除某個鍵,需要將值設為 null。對於列表類型的資源,Kubernetes 會根據特定的合併策略來處理,例如容器列表會根據容器名稱來匹配和合併。

如果要從列表中刪除某個項目,需要使用特殊的 $patch: delete 指令。這是 Strategic Merge Patch 處理列表刪除的標準方式。

實戰 🔥

讓我們看看實際場景中如何運用這兩種 Patch 方式。先看看專案結構:

k8s/
├── kustomization.yaml
├── mongo-depl.yaml
├── nginx-depl.yaml
├── api-depl.yaml
├── mongo-service.yaml
└── mongo-label-patch.yaml

gh

情境 1:使用 JSON 6902 Patch 進行多項修改

kustomization.yaml 中,我們可以針對不同資源進行不同的修改:

resources:
  - mongo-depl.yaml
  - nginx-depl.yaml
  - mongo-service.yaml

patches:
  # 修改 nginx 的副本數
  - target:
      kind: Deployment
      name: nginx-deployment
    patch: |-
      - op: replace
        path: /spec/replicas
        value: 3

  # 從外部檔案載入 mongo 的 patch 規則
  - target:
      kind: Deployment
      name: mongo-deployment
    path: mongo-label-patch.yaml

  # 同時修改 Service 的多個欄位
  - target:
      kind: Service
      name: mongo-cluster-ip-service
    patch: |-
      - op: replace
        path: /spec/ports/0/port
        value: 30000
      - op: replace
        path: /spec/ports/0/targetPort
        value: 30000

注意到 mongo-deployment 的 patch 規則被寫在獨立檔案中。當 patch 內容較多時,將其拆分到獨立檔案能提高可讀性:

# mongo-label-patch.yaml
- op: add
  path: /spec/template/metadata/labels/cluster
  value: staging

- op: add
  path: /spec/template/metadata/labels/feature
  value: db

這個實戰展示了如何為 Deployment 的 Pod template 添加新的標籤。路徑 /spec/template/metadata/labels/cluster 精確指定了要在哪裡添加新標籤。

情境 2:使用 Strategic Merge Patch 新增資源

現在讓我們改用更直觀的 Strategic Merge Patch。假設我們要為 mongo 添加持久化儲存,為 api 添加快取容器:

# mongo-patch.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mongo-deployment
spec:
  template:
    spec:
      containers:
        - name: mongo
          volumeMounts:
            - mountPath: /data/db
              name: mongo-volume
      volumes:
        - name: mongo-volume
          persistentVolumeClaim:
            claimName: host-pvc

這個 patch 為 mongo 容器添加了 volume mount 和 PVC。Strategic Merge Patch 會智慧地將這些配置合併到原始的 Deployment 中,不需要重複寫整個 Deployment 定義。

# api-patch.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-deployment
spec:
  template:
    spec:
      containers:
        - name: memcached
          image: memcached

這個 patch 在 api-deployment 中新增了一個 memcached 容器。讓我們看看原始的 api-depl.yaml

# api-depl.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      component: api
  template:
    metadata:
      labels:
        component: api
    spec:
      containers:
        - name: nginx
          image: nginx
        - name: memcached
          image: memcached

情境 3:Strategic Merge Patch 刪除容器

如果我們後來決定不需要 memcached 快取了,可以使用 $patch: delete 指令來移除它:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-deployment
spec:
  template:
    spec:
      containers:
        - $patch: delete
          name: memcached

這個特殊的 $patch: delete 指令告訴 Kustomize 要刪除名為 memcached 的容器。Kubernetes 會根據容器的 name 欄位來識別並刪除對應的容器。

情境 4:使用 JSON 6902 Patch 刪除標籤

現在讓我們用 JSON 6902 Patch 來移除 mongo-deployment 的標籤。先看看原始的配置:

# mongo-depl.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mongo-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      component: mongo
  template:
    metadata:
      labels:
        component: mongo
        org: IThome
    spec:
      containers:
        - name: mongo
          image: mongo

要刪除 org: IThome 標籤,在 kustomization.yaml 中使用 remove 操作:

resources:
  - mongo-depl.yaml
  - api-depl.yaml
  - mongo-service.yaml

patches:
  - target:
      kind: Deployment
      name: mongo-deployment
    patch: |-
      - op: remove
        path: /spec/template/metadata/labels/org

這個實戰看到 JSON 6902 Patch 在刪除特定欄位時的精確性。路徑明確指向要刪除的標籤鍵,不會影響其他標籤。

兩種 Patch 方式的選擇建議

  • JSON 6902 Patch:適合精確的單一欄位修改、刪除操作,或是需要明確控制修改順序的場景
  • Strategic Merge Patch:適合大範圍的配置修改、新增複雜的巢狀結構,或是希望保持 YAML 可讀性的場景

Overlays:多環境管理的核心

Overlays 是 Kustomize 實現多環境管理的核心機制,也是它最能展現價值的地方。透過在不同的 overlay 目錄中定義環境特定的 patches 和額外資源,我們可以從同一個 base 配置衍生出適合開發、測試、預發布、生產等不同環境的配置。這種方式完美實踐了 DRY(Don't Repeat Yourself)原則,讓我們能夠維護單一來源的真實配置,同時又能靈活地為每個環境客製化。

每個 overlay 都有自己的 kustomization.yaml,其中透過 resources 屬性(舊版使用 bases)引用 base 配置,然後定義該環境特有的修改。這不僅限於 patches,也可以在 overlay 中加入該環境獨有的資源,比如只在生產環境中啟用的監控元件、只在開發環境需要的除錯工具等。

resources:
  - ../../base

resources:
  - redis-depl.yaml

patch: |-
  - op: replace
    path: /spec/replicas
    value: 5

這種設計讓環境之間的差異變得明確且易於管理。當我們需要了解生產環境和開發環境有什麼不同時,只需要查看對應的 overlay 目錄即可,不需要逐一比對完整的 YAML 檔案。

實戰 🔥

讓我們透過一個完整的多環境專案來理解 Overlays 的實際應用。這是我們的專案結構:

k8s/
├── base/
│   ├── kustomization.yaml
│   ├── api-deployment.yaml
│   ├── db-configMap.yaml
│   ├── mongo-depl.yaml
│   └── mysql-depl.yaml
└── overlays/
    ├── dev/
    │   └── kustomization.yaml
    ├── staging/
    │   ├── kustomization.yaml
    │   └── configMap-patch.yaml
    ├── QA/
    │   └── kustomization.yaml
    └── prod/
        ├── kustomization.yaml
        ├── api-patch.yaml
        └── redis-depl.yaml

gh

注意:我有遇到 Warning 訊息表示新版本中 bases 欄位已被 resources 取代。

情境 1:生產環境的映像檔選擇

首先來看 base 中的 API deployment 基礎配置:

# /k8s/base/api-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-deployment
spec:
  replicas: 2
  selector:
    matchLabels:
      component: api
  template:
    metadata:
      labels:
        component: api
    spec:
      containers:
        - name: api
          image: nginx
          env:
            - name: DB_CONNECTION
              value: db.kodekloud.com

基礎配置中使用的是 nginx。但在生產環境,我們想使用效能更好的 memcached 作為快取層:

# /k8s/overlays/prod/kustomization.yaml
resources:
  - ../../base
  - redis-depl.yaml  # 生產環境獨有的 Redis

patches:
  - api-patch.yaml
# /k8s/overlays/prod/api-patch.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-deployment
spec:
  template:
    spec:
      containers:
        - name: api
          image: memcached

這個實戰展示了幾個重要概念:

  1. 基礎配置的繼承:prod overlay 透過 resources: - ../../base 繼承了所有基礎配置
  2. 環境特定資源redis-depl.yaml 只在生產環境部署,開發和測試環境不需要
  3. 精確的配置覆寫:patch 只修改了映像檔,其他配置(如 replicas、環境變數)都維持 base 的設定

情境 2:預發布環境的密碼管理

在 staging 環境,我們需要使用不同的資料庫憑證。先看 base 中的 ConfigMap:

# /k8s/base/db-configMap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: db-creds
data:
  username: admin
  password: default123

在 staging overlay 中覆寫這些憑證:

# /k8s/overlays/staging/kustomization.yaml
resources:
  - ../../base

patches:
  - configMap-patch.yaml
# /k8s/overlays/staging/configMap-patch.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: db-creds
data:
  username: mongo
  password: superp@ssword123

這個 Strategic Merge Patch 會覆寫 base 中的 username 和 password,但保留 ConfigMap 的其他屬性(如果有的話)。這種做法確保每個環境使用正確的憑證,而不會在 base 中暴露敏感資訊。

情境 3:QA 環境使用不同的 Web Server

QA 團隊想測試新的 Caddy web server,但不想影響其他環境。我們可以針對 QA 環境進行映像檔替換:

# /k8s/overlays/QA/kustomization.yaml
resources:
  - ../../base

labels:
  - includeSelectors: true
    pairs:
      environment: QA

patches:
  - target:
      kind: Deployment
      name: api-deployment
    patch: |-
      - op: replace
        path: /spec/template/spec/containers/0/image
        value: caddy

這裡同時展示了兩個功能:

  1. 環境標籤:為 QA 環境的所有資源添加 environment: QA 標籤,方便追蹤和管理
  2. JSON 6902 Patch:精確替換第一個容器的映像檔為 Caddy

部署到 QA 環境:

kubectl apply -k /k8s/overlays/QA

情境 4:Staging 環境的專屬資料庫

假設 staging 環境需要獨立的 MySQL 資料庫進行整合測試。我們可以在 staging overlay 中添加這個資源:

首先建立 MySQL deployment 配置:

# /k8s/base/mysql-depl.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      component: mysql
  template:
    metadata:
      labels:
        component: mysql
        org: Ithome
    spec:
      containers:
        - name: mysql
          image: mysql
          env:
            - name: MYSQL_ROOT_PASSWORD
              value: mypassword

然後在 base 的 kustomization.yaml 中註冊這個資源:

# /k8s/base/kustomization.yaml
resources:
  - api-deployment.yaml
  - db-configMap.yaml
  - mongo-depl.yaml
  - mysql-depl.yaml

現在當我們部署 staging 環境時,它就會包含 MySQL:

kubectl apply -k /k8s/overlays/staging

這個實戰展示了 Overlays 的靈活性:我們在 base 中定義了 MySQL 配置,但可以選擇性地在不同環境中部署或不部署它。如果某個環境不需要 MySQL,只要在其 overlay 的 kustomization.yaml 中不引用即可。

Overlays 的最佳實踐

  1. 保持 base 簡潔:base 中只放共通配置,環境特定的內容放在 overlays
  2. 明確的環境差異:每個 overlay 應該清楚表達該環境的特殊需求
  3. 使用描述性的目錄名稱:dev、staging、prod 這樣的命名一目了然
  4. 合理的資源分層:不要讓 overlay 過度複雜,必要時可以建立中間層
  5. 版本控制:將整個目錄結構納入 Git,追蹤配置變更歷史

Components:可重複使用配置的最佳實踐

Components 是 Kustomize 中較新但極為實用的功能,它解決了「某些功能只在部分環境中啟用」的問題。這是一個在實務中經常遇到的場景:比如快取功能只在生產和預發布環境啟用,而開發環境不需要;或是日誌收集系統只在特定環境部署。

如果把這些可選功能放在 base 中,所有環境都會有,這不是我們想要的。如果複製到各個需要的 overlay 中,又違反了 DRY(Don't Repeat Yourself)原則,造成維護上的困擾。每次修改這些功能時,都需要在多個地方同步更新。

Components 提供了第三種更優雅的選擇:將這些可選功能打包成獨立的元件,然後在需要的 overlay 中引用。一個 Component 可以包含資源定義、patches、secrets、ConfigMaps 等所有相關配置,形成一個完整的功能模組。透過在 overlay 的 kustomization.yaml 中列出需要的 components,就能像組裝樂高積木一樣靈活地組合功能。

這種模組化的設計不僅提高了配置的可重用性,也讓環境配置變得更加語義化。當看到某個 overlay 引用了 auth、logging、caching 這些 components,就能立即理解該環境包含哪些功能。

Component 的基本結構

一個典型的 Component 包含自己的 kustomization.yaml,但 kind 設定為 Component 而非 Kustomization

# components/db/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1alpha1
kind: Component

resources:
  - postgres-depl.yaml

secretGenerator:
  - name: postgres-cred
    literals:
      - password=postgres123

patches:
  - deployment-patch.yaml

這個資料庫 Component 包含了:

  1. 資源定義:PostgreSQL deployment
  2. Secret 生成:自動產生資料庫憑證
  3. Patches:將憑證注入到需要的應用中

對應的 patch 檔案:

# components/db/deployment-patch.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-deployment
spec:
  template:
    spec:
      containers:
        - name: api
          env:
            - name: DB_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: postgres-cred
                  key: password

在需要資料庫的環境中引用這個 Component:

# overlays/prod/kustomization.yaml
resources:
  - ../../base

components:
  - ../../components/db

這樣 production 環境就會自動包含 PostgreSQL 及其相關配置,而開發環境如果不需要資料庫,完全不用引用這個 Component。

實戰 🔥

現在讓我們透過一個實際專案來深入理解 Components 的威力。這是我們的專案結構:

project_mercury/
├── base/
│   ├── kustomization.yaml
│   └── api-deployment.yaml
├── components/
│   ├── auth/
│   │   ├── kustomization.yaml
│   │   ├── keycloak-depl.yaml
│   │   └── api-patch.yaml
│   ├── logging/
│   │   ├── kustomization.yaml
│   │   ├── fluentd-depl.yaml
│   │   └── api-patch.yaml
│   └── caching/
│       ├── kustomization.yaml
│       ├── redis-depl.yaml
│       ├── redis-service.yaml
│       └── api-patch.yaml
└── overlays/
    ├── community/
    │   └── kustomization.yaml
    ├── enterprise/
    │   └── kustomization.yaml
    └── premium/
        └── kustomization.yaml

gh

情境 1:社群版只需基本功能

社群版(community)是免費版本,只提供基本功能和身份驗證:

# /overlays/community/kustomization.yaml
resources:
  - ../../base

components:
  - ../../components/auth

這個配置清楚表達:社群版 = 基礎功能 + 身份驗證,不包含日誌收集和快取等進階功能。

情境 2:為社群版增加日誌功能

假設我們決定讓社群版也能收集日誌以改善用戶支援。只需要在 kustomization.yaml 中添加 logging component:

# /overlays/community/kustomization.yaml
resources:
  - ../../base

components:
  - ../../components/auth
  - ../../components/logging

部署這個更新:

kubectl apply -k /root/code/project_mercury/overlays/community

gh

執行後會看到:

  • 原有的 base 資源(api-deployment 等)
  • auth component 的資源(Keycloak)
  • logging component 的新資源(Fluentd)
  • 所有相關的 patches 都被正確套用

這就是 Components 的美妙之處:新增功能就像打開開關一樣簡單,不需要修改任何現有配置,也不會影響其他環境。

情境 3:建立新的 Caching Component

現在讓我們實際建立一個新的 Component。企業版需要 Redis 快取來提升效能,我們來為它建立 caching component。

首先建立 Redis 相關的資源:

# components/caching/redis-depl.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: redis-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      component: redis
  template:
    metadata:
      labels:
        component: redis
    spec:
      containers:
        - name: redis
          image: redis:7-alpine
          ports:
            - containerPort: 6379
# components/caching/redis-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: redis-service
spec:
  type: ClusterIP
  selector:
    component: redis
  ports:
    - port: 6379
      targetPort: 6379

關鍵的部分是 API patch,讓 API 能夠連接到 Redis:

# components/caching/api-patch.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-deployment
spec:
  template:
    spec:
      containers:
        - name: api
          env:
            - name: REDIS_CONNECTION
              value: redis-service

這個 patch 為 API 容器注入了 REDIS_CONNECTION 環境變數,指向 Redis service。這是 Component 設計的精髓:不僅部署新資源,還要確保現有應用能正確使用這些新資源。

最後建立 Component 的 kustomization.yaml:

# components/caching/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1alpha1
kind: Component

resources:
  - redis-depl.yaml
  - redis-service.yaml

patches:
  - path: api-patch.yaml

現在可以在企業版中使用這個 Component:

# overlays/enterprise/kustomization.yaml
resources:
  - ../../base

components:
  - ../../components/auth
  - ../../components/logging
  - ../../components/caching

部署企業版:

kubectl apply -k /root/code/project_mercury/overlays/enterprise

檢查部署結果,會看到 API deployment 的環境變數中包含了來自不同 Components 的配置:

gh

Components 的設計原則

  1. 單一職責:每個 Component 應該只負責一個明確的功能模組
  2. 自包含性:Component 應該包含該功能所需的所有資源和配置
  3. 非侵入式:Component 透過 patches 整合,不修改 base 配置
  4. 可組合性:多個 Components 應該能安全地組合使用,不會產生衝突
  5. 環境獨立:Component 的定義不應該假設特定的環境

Components vs Overlays 的區別

  • Overlays:代表一個完整的部署環境(dev、staging、prod)
  • Components:代表可選的功能模組(auth、logging、caching)
  • 使用方式:Overlays 引用 base 和多個 Components 來組成完整配置

這種分層設計讓配置管理變得極為靈活:

  • Base 定義核心應用
  • Components 定義可選功能
  • Overlays 組合 Base 和 Components 形成特定環境

總結

在這兩天的 Kustomize 學習中,我們從基礎的 Base 和 Overlays 概念,一路深入到 Transformers、Patches 和 Components 的進階應用。Kustomize 真正的強大之處在於它的「組合式」設計哲學:

  1. Transformers 提供批次修改能力,讓我們能統一管理標籤、命名空間、映像檔版本等全域性配置
  2. Patches 提供精確控制能力,讓我們能針對特定資源進行細緻的修改
  3. Overlays 提供環境隔離能力,讓我們能從同一份 base 衍生出多個環境配置
  4. Components 提供模組化能力,讓我們能建立可重用的功能模組

這些機制相互配合,形成了一個強大而靈活的配置管理系統。更重要的是,Kustomize 是 Kubernetes 原生的工具,不需要學習額外的模板語法,所有配置都是標準的 Kubernetes YAML,這大大降低了學習曲線。

到今天的內容是我爬文觀察到 2025 年版本的 CKAD 考試,接下來就是去練習報名後的官方模擬考,希望能有好的結果。明天要繼續探索更進階的主題,像是 Istio 服務網格,這些內容雖然不在 CKAD 考試範圍內,但對於實際的 Kubernetes 運維工作非常有價值。

下一篇文章:Istio:為 Kubernetes 叢集裝上導航系統


上一篇
【Day25】Kustomize:不用模板也能客製化 Kubernetes 配置 - Part1
下一篇
【Day27】Istio:為 Kubernetes 叢集裝上導航系統
系列文
30 天挑戰 CKAD 認證!菜鳥的 Kubernetes 學習日記30
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言