Skip to main content

13.2. Kustomize Basics - Advanced Features and Patches

Mục lục


1. Image Transformer — thay đổi image container

1.1. Vấn đề

Security team gửi ticket lúc 9 giờ sáng: image nginx:1.21 dính một CVE nghiêm trọng, phải lên 1.22 trước cuối ngày. Mở thư mục manifests ra thì thấy sáu file Deployment, mỗi file có đúng một dòng image: nằm lọt thỏm trong spec.template.spec.containers. Sửa tay sáu chỗ, commit, rồi hai tuần nữa lại có bản vá mới — lại sáu chỗ.

Ở phần trước đã gặp khái niệm transformer: một field trong kustomization.yaml ra lệnh cho Kustomize sửa đồng loạt một thuộc tính trên mọi resource mà nó đọc được, thay vì phải mở từng file YAML chỉnh tay. namePrefix thêm tiền tố vào tên, nameSuffix thêm hậu tố, namespace dồn tất cả vào một namespace.

Nhưng cả nhóm transformer đó chỉ chạm tới phần metadata — tên, label, annotation, namespace. Image thì nằm sâu trong spec, mỗi kind lại nằm ở một độ sâu khác nhau. Vì vậy Kustomize tách riêng một transformer chuyên cho image, gọi là images.

1.2. newName — thay đổi image hoàn toàn

images:
- name: nginx
newName: haproxy

Giải thích: name chỉ định image hiện tại cần tìm — Kustomize quét mọi container trong các resource đã import và so khớp với giá trị này. newName là image mới thay thế. Tất cả container đang dùng image nginx sẽ được đổi sang haproxy.

Lưu ý: Thuộc tính name trong section images không liên quan đến thuộc tính name của container trong deployment.yaml. Nó là tên của image, không phải tên của container. Container tên web chạy image nginx vẫn bị transformer này bắt trúng.

1.3. newTag — chỉ đổi tag

Khi chỉ muốn nâng phiên bản, không cần đổi image hoàn toàn:

images:
- name: nginx
newTag: "2.4"

Kết quả: image trở thành nginx:2.4. Tag phải được bọc trong dấu nháy. Nếu ghi 2.4 trần, YAML parser hiểu đó là số thực, và Kustomize sẽ báo lỗi cannot unmarshal number into Go struct field image of type string.

Ngoài newTag, field digest cho phép ghim image theo SHA digest thay vì tag — cách thường dùng ở production khi muốn chắc chắn mọi môi trường chạy đúng một bản build.

1.4. Kết hợp newName và newTag

images:
- name: nginx
newName: haproxy
newTag: "2.4"

Kết quả: nginxhaproxy:2.4. Đổi cả image lẫn tag trong cùng một khai báo.

Chạy kubectl kustomize . để xem Kustomize thực sự sinh ra gì — lệnh này build và in YAML ra màn hình, không đụng tới cluster:

# Output minh họa
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-deployment
spec:
replicas: 1
template:
spec:
containers:
- name: web
image: haproxy:2.4

(Output minh họa — cấu trúc và tên field đúng theo lệnh thật, số liệu cụ thể chỉ mang tính ví dụ.)

Điểm cần nhớ: file deployment.yaml gốc trong base/ không hề bị sửa. Kustomize không ghi đè file nguồn — nó đọc vào, biến đổi trong bộ nhớ, rồi in kết quả ra. Sáu file Deployment ở đầu mục này chỉ cần một khai báo images duy nhất, và lần vá CVE sau chỉ phải sửa đúng một dòng.


2. Patches — ghi đè cụ thể từng resource

2.1. Transformers vs Patches

Transformer rất tiện, nhưng nó có một giới hạn cố hữu: nó thay đổi mọi resource. Nếu chỉ muốn tăng replicas của riêng Deployment api-deployment và không đụng gì tới các Deployment khác thì sao? Không transformer nào làm được việc đó.

Đây là lúc cần tới patch — một bản vá nhắm vào đúng một (hoặc một nhóm) resource được chỉ định rõ.

💡 Hình dung: Transformer giống lệnh "đổi font cho toàn bộ văn bản" — mọi đoạn đều đổi theo. Patch giống việc bôi đen đúng một đoạn rồi chỉnh riêng đoạn đó — phần còn lại của văn bản không hay biết gì.

2.2. Hai thành phần của một patch

Một entry trong field patches luôn gồm hai phần:

  1. Target — tiêu chí để Kustomize chọn đúng resource cần vá. Nếu không có target, Kustomize không biết bản vá này dành cho object nào.
  2. Nội dung patch — mô tả thay đổi, viết theo một trong hai cú pháp: JSON 6902 (mục 3) hoặc Strategic Merge (mục 4).

Target nhận các tiêu chí sau, và resource phải khớp tất cả tiêu chí đã khai báo mới bị vá:

Tiêu chíÝ nghĩa
kindLoại resource: Deployment, Service, ConfigMap,...
nameTên resource. Hiểu như regex neo hai đầu, nên web-.* là hợp lệ.
namespaceNamespace của resource, cũng hiểu như regex.
group / versionAPI group và version, ví dụ apps / v1.
labelSelectorChọn theo label, ví dụ env=dev.
annotationSelectorChọn theo annotation, ví dụ zone=west.

Riêng với cú pháp JSON 6902, nội dung patch còn có thêm hai thành phần con:

  • Operation (op) — thao tác cần thực hiện: add (thêm), remove (xóa), replace (thay thế).
  • Value — giá trị cần thêm hoặc thay thế. Thao tác remove không cần field này.

Về tên field: Hai field cũ patchesStrategicMergepatchesJson6902 vẫn chạy được trong API v1beta1, nhưng đã bị đánh dấu deprecated từ kustomize v5.0.0 — gặp chúng trong repo cũ thì cứ đọc như patches phiên bản tách đôi, còn khi viết mới thì luôn dùng patches. (Cùng đợt đó, commonLabels được thay bằng labels, và vars được thay bằng replacements.)


3. JSON 6902 Patch — cú pháp JSON-like

3.1. JSON 6902 là gì

JSON 6902 là cách gọi tắt của RFC 6902 — JSON Patch, một chuẩn IETF mô tả cách biểu diễn "một chuỗi thao tác sửa đổi" trên tài liệu JSON. Chuẩn này định nghĩa sáu thao tác: add, remove, replace, move, copy, test. Trong thực tế làm việc với Kustomize, ba thao tác đầu chiếm gần như toàn bộ use case.

Mỗi thao tác là một entry gồm op, path, và (tùy thao tác) value:

patches:
- target:
kind: Deployment
name: api-deployment
patch: |
- op: replace
path: /spec/replicas
value: 5

Lưu ý patch: | — dấu | là block scalar của YAML, nghĩa là "mọi thứ thụt vào bên dưới là một chuỗi văn bản nhiều dòng". Kustomize nhận chuỗi đó rồi tự parse thành danh sách thao tác.

3.2. Đọc path như thế nào

path không phải cú pháp riêng của Kustomize — nó là JSON Pointer, định nghĩa ở RFC 6901. Quy tắc đọc rất đơn giản: mỗi dấu / là một cấp đi xuống trong cấu trúc YAML.

  • /spec/replicas trỏ tới spec.replicas.
  • /metadata/name trỏ tới metadata.name.
  • /spec/template/spec/containers/0/image trỏ tới image của container đầu tiên.

💡 Hình dung: Đọc path y hệt đọc một đường dẫn thư mục trên máy. /spec/template/spec/containers/0/image giống /home/user/projects/0/readme.txt — bắt đầu từ gốc của document, đi lần lượt qua từng cấp, tới đúng file cần sửa. Số 0 không phải tên field, nó là số thứ tự phần tử trong một thư mục xếp theo thứ tự.

3.3. Ví dụ: thay thế replicas

Giả định base deployment có replicas: 1, và overlay production muốn đổi thành replicas: 5:

patches:
- target:
kind: Deployment
name: api-deployment
patch: |
- op: replace
path: /spec/replicas
value: 5

Trước khi patch, kubectl kustomize base/ in ra:

# Output minh họa
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-deployment
spec:
replicas: 1
selector:
matchLabels:
app: api
template:
metadata:
labels:
app: api
spec:
containers:
- name: web
image: nginx

Sau khi patch, kubectl kustomize overlays/production/ in ra:

# Output minh họa
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-deployment
spec:
replicas: 5
selector:
matchLabels:
app: api
template:
metadata:
labels:
app: api
spec:
containers:
- name: web
image: nginx

(Output minh họa — cấu trúc và tên field đúng theo lệnh thật, số liệu cụ thể chỉ mang tính ví dụ.)

Đúng một dòng đổi. selector, template, containers — tất cả đi thẳng từ base sang, không sứt mẻ gì. Đó là toàn bộ ý nghĩa của "patch": mô tả delta, không mô tả lại cả object.

JSON 6902 Patch: op + path + valueBase resourceapi-deploymentspec.replicas: 1JSON 6902 patchop: replacepath: /spec/replicasvalue: 5Resultspec.replicas: 5Read path like a file path: each / goes one level down/metadata/name = metadata.name/spec/replicas = spec.replicas/spec/template/spec/containers/0/image

4. Strategic Merge Patch — YAML thuần, dễ đọc hơn

4.1. "Strategic" nghĩa là gì

Strategic Merge Patch là thuật toán merge riêng của Kubernetes, không phải JSON merge thông thường. Điểm khác biệt nằm ở chữ "strategic": nó biết schema của từng resource, nên nó biết list nào phải merge theo khóa thay vì ghi đè cả list.

Ví dụ cụ thể: spec.template.spec.containers là một list. Với merge thông thường, ghi một container vào patch sẽ thay sạch cả list. Với strategic merge, Kubernetes biết list này có khóa merge là name — nên container nào trùng name thì được sửa, container nào không trùng thì được giữ nguyên hoặc thêm mới.

Nhờ vậy, patch viết ra trông giống hệt một file YAML Kubernetes bình thường — không có op, không có path, không có cú pháp lạ. Chỉ cần copy phần muốn thay đổi từ config gốc, sửa giá trị, và xóa hết phần không đụng tới.

💡 Hình dung: Strategic Merge Patch giống việc đưa cho thợ sửa nhà một bản vẽ chỉ có đúng căn bếp, kèm lời dặn "phần còn lại giữ nguyên". Thợ không hỏi lại phòng ngủ sơn màu gì, vì bản vẽ đã ngầm nói: cái gì không vẽ tức là không đổi.

4.2. Ví dụ: thay thế replicas

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

Bốn dòng đầu không phải để "khai báo lại" Deployment — chúng đóng vai trò target. Kustomize đọc apiVersion, kindmetadata.name trong chính nội dung patch để biết phải vá object nào, nên ở đây không cần viết thêm block target riêng.

Kết quả sau khi build:

# Output minh họa
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-deployment
spec:
replicas: 5
selector:
matchLabels:
app: api
template:
metadata:
labels:
app: api
spec:
containers:
- name: web
image: nginx
ports:
- containerPort: 80

(Output minh họa — cấu trúc và tên field đúng theo lệnh thật, số liệu cụ thể chỉ mang tính ví dụ.)

Patch chỉ nhắc tới spec.replicas, nhưng output vẫn có đủ selector, template, containers, ports. Mọi field không xuất hiện trong patch đều được giữ nguyên từ base — đó là ý nghĩa của "merge".

4.3. So sánh hai phương pháp

Tiêu chíJSON 6902Strategic Merge
Định dạngDanh sách thao tác kiểu JSONYAML Kubernetes thuần
Cách chỉ resourceBlock target riêngSuy ra từ apiVersion + kind + name trong patch
Độ khóPhải viết đúng path từng cấpCopy config gốc rồi xóa bớt
Khả năng đọcKhó đọc với người mớiQuen thuộc, gần như đọc YAML thường
Thao tác theo vị trí trong listCó — chỉ đích danh index 0, 1,...Không — merge theo khóa name

Khuyến nghị: Mặc định dùng Strategic Merge Patch, vì nó dễ đọc và dễ review trong pull request. Chỉ rút JSON 6902 ra khi cần thao tác theo vị trí trong list — chẳng hạn xóa phần tử thứ hai, hoặc chèn vào đúng đầu list.


5. Inline vs Separate File

5.1. Inline Patch — khai báo trực tiếp

Khi patch ngắn, viết thẳng vào kustomization.yaml cho gọn:

patches:
- target:
kind: Deployment
name: api-deployment
patch: |
- op: replace
path: /spec/replicas
value: 5

5.2. Separate File — tách riêng

Khi patch dài, tách ra file riêng rồi trỏ tới bằng path thay vì patch.

replica-patch.yaml:

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

kustomization.yaml:

patches:
- path: replica-patch.yaml
target:
kind: Deployment
name: api-deployment

Hai field này loại trừ nhau: patch chứa nội dung inline, path trỏ tới file. Một entry chỉ dùng một trong hai.

5.3. Khi nào nên tách file

  • Khi có nhiều patch cùng lúc, để kustomization.yaml không dài tới mức phải cuộn màn hình.
  • Khi bản thân patch dài và phức tạp, nhất là patch đụng vào containers hay volumes.
  • Khi muốn tái sử dụng cùng một patch ở nhiều overlay khác nhau.
  • Khi muốn kustomization.yaml đóng vai trò mục lục — đọc vào là thấy ngay cấu trúc, còn chi tiết nằm ở file con.

6. Thao tác với Lists

6.1. Lists trong Kubernetes

List là mảng trong YAML, biểu diễn bằng dấu - đầu dòng. Phần lớn field quan trọng nhất của Kubernetes đều là list: containers, volumes, ports, env.

spec:
containers:
- name: nginx
image: nginx
- name: web
image: nginx

6.2. Index bắt đầu từ 0

List đánh số từ 0: index 0 là phần tử đầu tiên, index 1 là phần tử thứ hai. Đây là nguồn lỗi kinh điển khi viết JSON 6902 — containers/1 không phải container thứ nhất.

6.3. Thay thế item trong List

JSON 6902 — thay container đầu tiên:

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

Path dài vì phải đi qua đủ spectemplatespeccontainers0. Mỗi / là một cấp trong cấu trúc lồng nhau.

Strategic Merge — ngắn hơn:

patches:
- patch: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-deployment
spec:
template:
spec:
containers:
- name: nginx
image: haproxy

Ở đây name: nginx không phải thứ muốn đổi — nó là khóa để tìm đúng container. Kustomize dò trong list containers xem phần tử nào có name: nginx, rồi chỉ sửa field image của phần tử đó.

6.4. Thêm item vào List

JSON 6902 — dùng token - ở cuối path:

patches:
- target:
kind: Deployment
name: api-deployment
patch: |
- op: add
path: /spec/template/spec/containers/-
value:
name: haproxy
image: haproxy

Token - ở cuối path là quy ước của JSON Pointer, nghĩa là "vị trí ngay sau phần tử cuối cùng" — nên op: add vào đó chính là append. Muốn chèn vào giữa thì thay - bằng index cụ thể: containers/0 chèn vào đầu list, đẩy các phần tử còn lại lùi xuống.

Strategic Merge — chỉ cần khai báo container mới:

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

name: haproxy không trùng với container nào đang có, Kustomize hiểu đây là phần tử mới và thêm vào list.

Kết quả build của cả hai cách là như nhau:

# Output minh họa
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-deployment
spec:
replicas: 1
template:
spec:
containers:
- name: nginx
image: nginx
- name: haproxy
image: haproxy

(Output minh họa — cấu trúc và tên field đúng theo lệnh thật, số liệu cụ thể chỉ mang tính ví dụ.)

6.5. Xóa item khỏi List

JSON 6902 — xóa theo index:

patches:
- target:
kind: Deployment
name: api-deployment
patch: |
- op: remove
path: /spec/template/spec/containers/1

Thao tác remove không cần value. Nhưng nó phụ thuộc vào thứ tự container trong base: base đổi thứ tự một lần là patch này xóa nhầm.

Strategic Merge — dùng directive $patch: delete:

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

Kustomize tìm container có name: database và xóa nó khỏi list. Cách này bám vào tên chứ không bám vào vị trí, nên an toàn hơn hẳn khi base thay đổi.

Rút gọn cả mục này thành một câu để nhớ: thao tác theo tên thì dùng Strategic Merge, thao tác theo vị trí thì dùng JSON 6902 — và ưu tiên tên bất cứ khi nào có thể.


7. Overlays — kết hợp base với environment-specific config

7.1. Overlays giải quyết vấn đề gì

Dev, staging, production chạy cùng một ứng dụng nhưng không bao giờ cấu hình giống hệt nhau: dev một replica cho nhẹ máy, staging ba, production năm. Copy cả thư mục manifests ra làm ba bản là cách nhanh nhất — và cũng là cách nhanh nhất để ba bản trôi dạt khỏi nhau sau vài tháng.

Kustomize tách bài toán thành hai lớp:

  • Base là thư mục chứa phần cấu hình chung cho mọi môi trường, cùng một kustomization.yaml mô tả nó.
  • Overlay là thư mục chứa kustomization.yaml trỏ về base, cộng thêm đúng phần khác biệt của riêng môi trường đó.

Khi build một overlay, Kustomize đọc base trước, áp phần khác biệt lên trên, rồi in ra manifest hoàn chỉnh cho môi trường đó. Base không hề biết mình đang bị overlay nào dùng.

💡 Hình dung: Base là bản vẽ gốc của một căn hộ mẫu, overlay là tờ giấy can đặt chồng lên trên ghi những chỗ sửa cho từng khách hàng. Tờ giấy can nào cũng mỏng, chỉ vài nét — nhưng úp lên bản vẽ gốc là ra một căn hộ hoàn chỉnh, khác nhau ở đúng những nét đã ghi.

7.2. Cấu trúc thư mục

k8s/
├── base/
│ ├── nginx-deployment.yaml
│ └── kustomization.yaml
└── overlays/
├── dev/
│ └── kustomization.yaml
├── staging/
│ └── kustomization.yaml
└── production/
├── grafana-deployment.yaml
└── kustomization.yaml

7.3. Base kustomization.yaml

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
- nginx-deployment.yaml

7.4. Dev overlay

Overlay trỏ về base bằng chính field resources — vì resources nhận cả đường dẫn tới file, lẫn đường dẫn tới thư mục có kustomization.yaml:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
- ../../base

patches:
- patch: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 1

Nếu gặp bases: trong repo cũ: Field bases là cách viết cũ của đúng việc này, đã bị deprecated từ kustomize v2.1.0 và sẽ không có mặt trong API v1 — nó vẫn chạy trong v1beta1, nhưng config viết mới nên dùng resources. Lệnh kustomize edit fix tự chuyển đổi giúp.

7.5. Staging overlay

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
- ../../base

patches:
- patch: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 3

7.6. Production overlay

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
- ../../base

patches:
- patch: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 5

7.7. Đường dẫn tương đối tới base

Đường dẫn trong resources được tính từ chính thư mục chứa kustomization.yaml đó, không phải từ thư mục đang đứng khi gõ lệnh. Đứng ở overlays/dev/, chuỗi ../../base đọc như sau:

  • .. — lùi lên một cấp, từ overlays/dev/ ra overlays/.
  • ../.. — lùi lên hai cấp, ra k8s/.
  • ../../base — từ k8s/ đi vào thư mục base.

7.8. Build thử một overlay

Có hai lệnh cần phân biệt rõ:

  • kubectl kustomize <thư mục> — build và in manifest ra màn hình, không đụng tới cluster. Dùng để kiểm tra trước khi apply.
  • kubectl apply -k <thư mục> — build rồi apply thẳng lên cluster. Cờ -k là viết tắt của --kustomize, và nó là cờ của apply, không phải lệnh độc lập.
kubectl kustomize overlays/staging
# Output minh họa
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.22

(Output minh họa — cấu trúc và tên field đúng theo lệnh thật, số liệu cụ thể chỉ mang tính ví dụ.)

Ưng ý rồi thì apply:

kubectl apply -k overlays/staging
# Output minh họa
deployment.apps/nginx-deployment configured

(Output minh họa — cấu trúc và tên field đúng theo lệnh thật, số liệu cụ thể chỉ mang tính ví dụ.)

Overlays: each environment declares only its deltabase/ (shared)replicas: 1overlays/devresources: ../../basepatches: replicas=1overlays/stagingresources: ../../basepatches: replicas=3overlays/productionresources: ../../basepatches: replicas=5kubectl apply -koverlays/devkubectl apply -koverlays/stagingkubectl apply -koverlays/productionBase knows nothing about its overlays. Each overlay records only the difference.

7.9. Overlays có thể thêm resources hoàn toàn mới

Overlay không chỉ vá base — nó có thể bổ sung resource không hề tồn tại trong base. Ví dụ production cần thêm một Grafana instance để monitor, còn dev và staging thì không:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
- ../../base
- grafana-deployment.yaml

Vì base và file mới đều nằm chung một field resources, Kustomize gom cả hai vào cùng một tập rồi mới áp patch lên. Đây cũng là lý do bases bị gộp vào resources: về bản chất, một base cũng chỉ là "thêm một nguồn resource nữa" mà thôi.


8. Components — khối cấu hình tái sử dụng

8.1. Vấn đề

Giả định một SaaS có ba biến thể deploy: Development, Premium, Self-hosted. Trong đó:

  • Caching (Redis) chỉ cần cho Premium và Self-hosted.
  • External Database (PostgreSQL) chỉ cần cho Development và Premium.

Không biến thể nào là tập con của biến thể nào — nên không thể xếp chúng thành một chuỗi base → overlay tuyến tính. Cách thô nhất là copy khối config Redis vào cả overlay Premium lẫn Self-hosted. Nhưng lần sau đổi memory limit của Redis, phải nhớ sửa cả hai nơi. Quên một nơi là có config drift, và kiểu lỗi này thường chỉ lộ ra lúc production lệch hẳn so với staging.

8.2. Components là gì

Component là một thư mục cấu hình đóng gói trọn một tính năng — đủ resource, patch, generator cần thiết để bật tính năng đó — và overlay nào cần thì chỉ việc khai báo tên nó vào field components. Viết một lần, dùng lại ở nhiều overlay.

Khác biệt với base: base là điểm xuất phát chung mà mọi overlay đều kế thừa, còn component là mẩu cấu hình tùy chọn, overlay tự quyết định có lấy hay không.

💡 Hình dung: Component giống plugin trong một IDE. Bản cài IDE (base) ai cũng giống nhau. Plugin thì mỗi người bật một bộ khác nhau: người này bật Docker, người kia bật Docker lẫn Database, người thứ ba chỉ bật Database. Plugin vẫn nằm một chỗ duy nhất trong thư mục cài đặt — nâng cấp plugin là mọi người bật nó đều được nâng theo.

Components: switch features on per overlayoverlays/devoverlays/premiumoverlays/standalonebase/shared configbase/shared configbase/shared configcomponent: databasepostgres + secretcomponent: databasepostgres + secretdatabase: offcaching: offcomponent: cachingredis + configcomponent: cachingredis + configEach component is written once and lives in a single place.Edit the Redis config here and every overlay with caching on follows.

8.3. Cấu trúc thư mục

k8s/
├── base/
│ └── kustomization.yaml
├── components/
│ ├── caching/
│ │ ├── redis-deploy.yaml
│ │ ├── redis-config.yaml
│ │ ├── redis-secret.yaml
│ │ └── kustomization.yaml
│ └── database/
│ ├── postgres-deploy.yaml
│ ├── database-patch.yaml
│ └── kustomization.yaml
└── overlays/
├── dev/
├── premium/
└── standalone/

8.4. Component kustomization.yaml

Component cũng dùng file kustomization.yaml, nhưng khai báo khác ở cả hai dòng đầu: kindComponent thay vì Kustomization, và apiVersionkustomize.config.k8s.io/v1alpha1 thay vì v1beta1.

components/database/kustomization.yaml:

apiVersion: kustomize.config.k8s.io/v1alpha1
kind: Component

resources:
- postgres-deploy.yaml

secretGenerator:
- name: db-credentials
literals:
- password=supersecret

patches:
- path: database-patch.yaml

Component chứa được resources, secretGenerator, patches — gần như mọi thứ một kustomization.yaml thường có.

Lưu ý về version: API của Component vẫn ở mức v1alpha1 kể từ khi ra mắt ở kustomize v3.7.0 — chưa graduate lên beta hay stable. Ghi nhầm thành v1beta1 là lỗi rất hay gặp, và Kustomize sẽ từ chối build.

8.5. Import Component trong Overlay

overlays/dev/kustomization.yaml — dev chỉ cần database:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
- ../../base

components:
- ../../components/database

overlays/premium/kustomization.yaml — premium cần cả database lẫn caching:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
- ../../base

components:
- ../../components/database
- ../../components/caching

overlays/standalone/kustomization.yaml — standalone chỉ cần caching:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
- ../../base

components:
- ../../components/caching

Ba file, mỗi file chỉ khác nhau ở danh sách components. Đọc lướt qua là biết ngay môi trường nào bật tính năng nào — thứ mà cách copy-paste config không bao giờ cho được.

8.6. Lợi ích của Components

Lợi íchGiải thích
Tái sử dụngViết một lần, khai báo lại ở bao nhiêu overlay cũng được.
Tránh copy-pasteKhông nhân bản config, nên không có chỗ để config drift sinh ra.
Dễ bảo trìSửa ở một nơi duy nhất, mọi overlay đang bật component đó đổi theo.
Rõ ràngMỗi tính năng gói gọn trong một thư mục — tìm cấu hình Redis thì vào components/caching/.

Tới đây đã đủ bộ công cụ để xử lý gần như mọi tình huống thực tế: images cho việc vá image hàng loạt, patches cho việc chỉnh đích danh, overlay cho khác biệt giữa các môi trường, và component cho những tính năng bật/tắt theo từng biến thể. Quy tắc chọn công cụ vẫn là một câu: đổi mọi thứ thì dùng transformer, đổi một thứ thì dùng patch, đổi theo môi trường thì dùng overlay, đổi theo tính năng thì dùng component.


Nguồn tham khảo

Nguồn gốc: Khóa "Certified Kubernetes Administrator (CKA)" — bài "Kustomize Basics" (image transformer; patches; JSON 6902 patch; strategic merge patch; inline vs separate file; thao tác với lists; overlays; components), nền tảng KodeKloud. Giảng viên: Mumshad Mannambeth.

Repo ghi chú, link tài liệu, và đáp án các practice question của toàn bộ khóa học: kodekloudhub/certified-kubernetes-administrator-course.

Fact-check:

  • Field bases bị deprecated từ kustomize v2.1.0; các entry chuyển sang field resources, và kustomize edit fix tự chuyển đổi. Field này còn giữ trong API kustomize.config.k8s.io/v1beta1 nhưng sẽ không có trong API v1 — 2026-09-23, Kustomize Docs — bases
  • Mỗi entry trong resources là đường dẫn tới một file, hoặc đường dẫn (hay URL) trỏ tới một thư mục kustomization khác — ví dụ ../../commonbase — nên resources thay được vai trò của bases — 2026-09-23, Kustomize Docs — resources
  • Kustomize v5.0.0 deprecate patchesStrategicMergepatchesJson6902 (thay bằng patches), vars (thay bằng replacements), imageTags (alias của images); các field này không bị gỡ khỏi API v1beta1 nhưng sẽ không có trong API v1 — 2026-09-23, kubernetes-sigs/kustomize — Release kustomize/v5.0.0
  • commonLabels bị deprecated từ kustomize v5.0.0, thay bằng field labels — 2026-09-23, Kustomize Docs — commonLabels
  • Field patches nhận path (file patch) hoặc patch (nội dung inline), kèm target với các tiêu chí group, version, kind, name, namespace, labelSelector, annotationSelector; namenamespace được hiểu như regex neo hai đầu — 2026-09-23, Kustomize Docs — patches
  • Component khai báo apiVersion: kustomize.config.k8s.io/v1alpha1kind: Component; overlay trỏ về base bằng resources: - ../../base và khai báo component qua field components; tính năng này ra mắt ở kustomize v3.7.0 và vẫn ở mức alpha — 2026-09-23, Kustomize Docs — Components
  • RFC 6902 (JSON Patch) định nghĩa sáu operation: add, remove, replace, move, copy, test; path là một JSON Pointer theo RFC 6901, và ký tự - dùng để trỏ tới vị trí cuối mảng nên add vào đó có tác dụng append — 2026-09-23, IETF RFC 6902 — JavaScript Object Notation (JSON) Patch
  • kubectl kustomize <thư mục> in ra manifest đã build, còn để apply phải dùng kubectl apply -k <thư mục> (hoặc --kustomize); -k là cờ của apply, không phải một lệnh kubectl độc lập — 2026-09-23, Kubernetes Docs — Declarative Management of Kubernetes Objects Using Kustomize
  • Transformer images nhận các field name, newName, newTagdigest — 2026-09-23, Kustomize Docs — images
  • Strategic merge patch là biến thể riêng của Kubernetes, dùng metadata patchStrategy/patchMergeKey của từng field — list containers có merge key là name; directive $patch: delete đánh dấu phần tử cần xóa — 2026-09-23, kubernetes/community — Strategic Merge Patch