13.1. Kustomize Basics - Fundamentals and Overlays
Mục lục
- 1. Kustomize giải quyết vấn đề gì?
- 2. Base và Overlays — hai trụ cột của Kustomize
- 3. Cài đặt Kustomize
- 4. File kustomization.yaml
- 5. Build và Apply — từ config đến cluster
- 6. Multi-Directory — quản lý project lớn
- 7. Common Transformers
- 8. ConfigMap và Secret Generators
1. Kustomize giải quyết vấn đề gì?
Một deployment NGINX chạy ngon trên máy local. Sếp bảo đưa lên staging. Tuần sau, đưa nốt lên production. Cùng một ứng dụng, nhưng số replicas phải khác nhau — máy local yếu chỉ cần 1, staging cần 2-3, production cần 5-10 để chịu được traffic thật.
Trước khi đi tiếp, thống nhất hai từ sẽ xuất hiện liên tục trong toàn bộ tài liệu này:
- Resource là một Kubernetes object được mô tả bằng YAML — Deployment, Service, ConfigMap, Secret đều là resource.
- Manifest là nội dung YAML mô tả một hay nhiều resource, đúng dạng mà
kubectl applynhận vào.
Quay lại ba môi trường. Giải pháp "nhanh" nhất là tạo ba thư mục riêng biệt, copy nguyên config vào mỗi thư mục, rồi sửa replicas tương ứng. Nghe hợp lý. Nhưng khi project phát triển, thêm Service, ConfigMap, Secret vào hệ thống — lúc đó phải copy tất cả sang mọi thư mục. Sửa một dòng ở bản gốc phải nhớ sửa lại ở tất cả nơi khác. Với năm môi trường, rất dễ bỏ sót một chỗ nào đó. Kết quả: mismatching configs — các môi trường không còn đồng nhất, và debug trở nên mệt mỏi vì không ai biết chắc config nào mới là đúng.
💡 Hình dung: Giống việc chỉnh sửa ảnh bằng cách copy nguyên file gốc ra nhiều bản, mỗi bản chỉnh một chút — sau vài lần, không còn biết bản nào là "nguồn chân lý". Kustomize giống layer trong Photoshop: một layer nền duy nhất, rồi chồng lên đó các adjustment layer riêng cho từng môi trường. Sửa layer nền một lần, mọi bản xuất ra đều đổi theo.
Câu hỏi cốt lõi: làm sao có một bộ config duy nhất làm nguồn chân lý, nhưng vẫn tùy biến được cho từng môi trường mà không phải copy paste? Kustomize ra đời để trả lời đúng câu hỏi đó.
2. Base và Overlays — hai trụ cột của Kustomize
2.1. Base config
Base là thư mục chứa những phần giống nhau trên mọi môi trường — nền tảng chung mà mọi biến thể sẽ kế thừa. Nó đóng vai trò "giá trị mặc định", và giá trị mặc định thì luôn có thể ghi đè khi cần.
2.2. Overlays
Overlay là một thư mục khác, chỉ chứa những thay đổi cần thiết cho một môi trường cụ thể. Development muốn 1 replica? Overlay khai báo đúng 1. Staging cần 3? Overlay khai báo đúng 3. Production cần 10? Overlay khai báo đúng 10.
Điểm mấu chốt: overlay không phải bản sao của base. Nó không chứa lại toàn bộ Deployment, chỉ chứa delta — đúng phần khác biệt so với base. Lúc build, Kustomize đọc base trước, rồi áp delta của overlay lên trên, sinh ra manifest hoàn chỉnh.
2.3. Cấu trúc thư mục chuẩn
k8s/
├── base/
│ ├── nginx-deployment.yaml
│ └── kustomization.yaml
└── overlays/
├── development/
│ └── kustomization.yaml
├── staging/
│ └── kustomization.yaml
└── production/
└── kustomization.yaml
Workflow đi theo một chiều rõ ràng: base chứa shared config, overlay chứa environment-specific delta, Kustomize kết hợp cả hai thành final manifest, rồi manifest đó mới được apply vào cluster. Phần tiếp theo của tài liệu sẽ dựng dần từng mảnh của workflow này, bắt đầu từ chỗ đơn giản nhất — một thư mục duy nhất, chưa có overlay.
2.4. Kustomize vs Helm
Helm dùng Go template — nhét biến {{ .Values.replicaCount }} vào file YAML, rồi tách riêng file values.yaml chứa giá trị thực. Cách này mạnh, nhưng cú pháp template không phải YAML thuần, khó đọc, và phải học thêm một ngôn ngữ template nữa.
Kustomize đi ngược lại: dùng YAML thuần, không template. Không có biến kiểu {{ .Values.x }} — chỉ có cấu trúc YAML chuẩn. Config nào cần override thì khai báo đúng override đó. Đơn giản, dễ đọc, dễ debug, và validate được bằng bất kỳ YAML linter nào.
| Tiêu chí | Kustomize | Helm |
|---|---|---|
| Cú pháp | YAML thuần, valid | Go template, không valid YAML thuần |
| Độ phức tạp | Đơn giản | Phức tạp hơn |
| Tính năng | Cơ bản | Nhiều tính năng nâng cao hơn |
| Package manager | Không | Có (giống yum/apt) |
Khi nào dùng cái nào? Kustomize phù hợp khi chỉ cần override vài giá trị trên từng môi trường. Helm phù hợp khi cần templating phức tạp, conditional logic, hooks, hoặc muốn đóng gói "chart" như một package để người khác install. Hai công cụ này cũng không loại trừ nhau — rất nhiều team render chart bằng Helm rồi vá phần còn lại bằng Kustomize.
3. Cài đặt Kustomize
3.1. Yêu cầu
Trước khi cài, đảm bảo đã có Kubernetes cluster đang chạy và kubectl đã cấu hình kết nối tới cluster đó.
3.2. Script cài đặt chính thức
Kustomize cung cấp một script tự nhận diện hệ điều hành và tải đúng binary của bản release mới nhất. Đây vẫn là cách cài binary được ghi trong tài liệu chính thức:
curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash
Lưu ý một chi tiết nhỏ nhưng hay làm mất thời gian: script tải binary về thư mục đang đứng, không tự cài vào PATH. Muốn gọi kustomize từ bất kỳ đâu, bạn cần tự chuyển nó vào một thư mục nằm trong PATH:
sudo mv ./kustomize /usr/local/bin/
Script cũng nhận tham số nếu cần ghim một phiên bản cụ thể hoặc chọn thư mục đích — ví dụ install_kustomize.sh 5.8.1 /usr/local/bin.
3.3. Xác minh cài đặt
kustomize version
# Output minh họa
# v5.8.1
(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ụ.)
Lệnh này in đúng một dòng semver của binary. Nếu không thấy output nào, nhiều khả năng terminal hiện tại chưa nhận PATH mới. Đóng terminal, mở terminal mới, rồi thử lại. Nếu vẫn lỗi, kiểm tra xem binary đã thực sự nằm trong một thư mục thuộc PATH chưa.
3.4. Hai bản Kustomize — standalone và bản nhúng trong kubectl
Có một chi tiết đủ sức làm mất cả buổi debug: trên máy đang có hai bản Kustomize, không phải một.
Bản thứ nhất là binary kustomize vừa cài ở trên. Bản thứ hai nằm sẵn bên trong kubectl — chính là thứ chạy khi gõ kubectl kustomize hoặc kubectl apply -k. Hai bản được release độc lập với nhau, và bản nhúng trong kubectl thường đi sau bản standalone một hoặc vài phiên bản.
kubectl in ra cả hai con số ngay ở lệnh version:
kubectl version --client
# Output minh họa
# Client Version: v1.34.1
# Kustomize Version: v5.7.1
(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ụ.)
Hệ quả rất thực tế: một field mới có từ Kustomize v5.8 sẽ chạy ngon với kustomize build, nhưng kubectl apply -k trên một kubectl còn nhúng v5.7 lại báo lỗi kiểu "unknown field". Config không sai — chỉ là hai chương trình khác nhau đang đọc nó.
Khi gặp tình huống "lệnh này chạy được, lệnh kia báo lỗi", việc đầu tiên nên làm là so hai con số version đó. Và nếu muốn chắc chắn manifest được render đúng bởi phiên bản mình đã test, hãy dùng kustomize build <dir> | kubectl apply -f -: lúc đó kubectl chỉ còn nhiệm vụ gửi YAML lên cluster, toàn bộ phần render do binary standalone lo.
4. File kustomization.yaml
4.1. File Kustomize tìm kiếm gì?
Khi chạy kustomize build, Kustomize tìm file có tên chính xác là kustomization.yaml trong thư mục được chỉ định. File này phải được tạo thủ công và đặt đúng tên — đây là "điểm vào" để Kustomize biết cần quản lý những resource nào.
💡 Hình dung:
kustomization.yamlgiống một công thức nấu ăn. Nửa trên là danh sách nguyên liệu — món này cần những file YAML nào. Nửa dưới là phần hướng dẫn chế biến — nêm thêm gì, đổi gì trước khi dọn ra. Nguyên liệu trong tủ lạnh không bị đụng tới; chỉ có món ăn dọn ra đĩa là đã được nêm.
4.2. Hai phần cốt lõi
File kustomization.yaml chứa đúng hai thứ: danh sách resources cần quản lý, và các transformation áp dụng lên những resource đó.
Phần 1 — Resources:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- nginx-deployment.yaml
- nginx-service.yaml
Khai báo những file YAML nào Kustomize cần đọc và quản lý.
Phần 2 — Transformers:
Transformer là một khai báo bảo Kustomize sửa gì đó trên toàn bộ resource vừa import — thêm label, đổi namespace, gắn prefix vào tên. Kustomize đọc khai báo đó rồi tự sửa lúc build; file YAML gốc không bị chạm vào một dòng nào. Danh sách đầy đủ nằm ở mục 7.
labels:
- pairs:
company: KodeKloud
Kết quả: mọi Deployment và Service trong danh sách resources đều được thêm label company: KodeKloud, mà không ai phải mở từng file ra sửa tay.
4.3. Giải thích apiVersion và kind
Giống mọi Kubernetes resource khác, kustomization.yaml có thể khai báo apiVersion và kind:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
kustomize.config.k8s.io/v1beta1 hiện vẫn là version chính thức của kind Kustomization. Về mặt kỹ thuật, Kustomize sẽ tự điền giá trị mặc định nếu không khai báo. Nhưng nên hard code hai dòng này: nhóm phát triển Kustomize đã dự kiến một API v1 trong tương lai, và những field đã deprecate ở v1beta1 sẽ bị loại hẳn khỏi v1. Ghi rõ apiVersion nghĩa là file của bạn nói rõ nó đang được viết theo luật của bản nào.
4.4. Build để xem kết quả
kustomize build k8s
Lệnh này in final config ra console — tất cả resources đã import, tất cả transformations đã apply. Quan trọng: kustomize build không apply vào cluster. Nó chỉ sinh ra manifest cuối cùng để xem trước.
5. Build và Apply — từ config đến cluster
💡 Hình dung:
kustomize buildlà bản in thử đưa lên màn hình để soát lỗi.kubectl applymới là lúc bấm nút cho máy in chạy thật. Soát bản in thử bao nhiêu lần cũng không tốn giấy; in nhầm ra production thì phải dọn.
5.1. Pipe sang kubectl apply
Vì kustomize build chỉ hiển thị, cần pipe output sang kubectl apply để thực sự deploy:
kustomize build k8s | kubectl apply -f -
# Output minh họa
# deployment.apps/nginx-deployment created
# service/nginx-service created
(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ụ.)
Giải thích từng phần: dấu | (pipe) chuyển output của lệnh bên trái thành input của lệnh bên phải. kustomize build k8s sinh final config. kubectl apply -f - đọc config từ stdin (-f - nghĩa là "đọc từ đầu vào chuẩn thay vì từ file") rồi apply vào cluster.
5.2. Cách ngắn gọn hơn
kubectl từ phiên bản 1.14 trở lên đã hỗ trợ Kustomize sẵn bên trong — chỉ cần flag -k:
kubectl apply -k k8s
-k nghĩa là "kustomize". kubectl tự chạy phần build rồi apply, tất cả trong một lệnh. Gọn hơn hẳn, và trong phòng thi CKA thì đây là cách nên dùng.
Đổi lại, phần build lúc này do bản Kustomize nhúng trong kubectl đảm nhiệm, chứ không phải binary standalone — đúng cái bẫy version đã nói ở mục 3.4. Với các field cơ bản trong tài liệu này thì không khác biệt gì; chỉ khi dùng field mới nhất mới cần để ý.
5.3. Xóa resources
Cú pháp tương tự, chỉ đổi apply thành delete:
kustomize build k8s | kubectl delete -f -
# Hoặc
kubectl delete -k k8s
Thói quen nên tập ngay từ đầu: build trước, đọc output, rồi mới apply. Nó tốn thêm đúng một lệnh, và đổi lại bạn không bao giờ phải đoán xem cluster vừa nhận được cái gì.
6. Multi-Directory — quản lý project lớn
6.1. Vấn đề khi project phình to
Khi YAML files tăng lên 20, 30, 50 file, không thể nhét tất cả vào một thư mục. Giả định có cấu trúc như sau:
k8s/
├── api/
│ ├── api-deployment.yaml
│ └── api-service.yaml
├── database/
│ ├── db-deployment.yaml
│ └── db-service.yaml
├── cache/
│ └── redis.yaml
└── kafka/
└── kafka.yaml
Cách làm thủ công là apply từng thư mục riêng:
kubectl apply -f k8s/api
kubectl apply -f k8s/database
kubectl apply -f k8s/cache
kubectl apply -f k8s/kafka
Bốn lệnh cho một lần deploy. Thêm một thư mục là thêm một lệnh phải nhớ, và không có cách nào build một phát để xem toàn bộ manifest cuối cùng.
💡 Hình dung: Một cuốn sách dày không bắt người đọc lật từng trang để tìm chương. Nó có mục lục ở đầu sách.
kustomization.yamlở thư mục gốc chính là mục lục đó — và khi sách quá dày, mỗi chương lại có mục lục riêng của nó.
6.2. Cách 1 — Root kustomization.yaml liệt kê từng file
Tạo root kustomization.yaml tại thư mục gốc k8s/, liệt kê đường dẫn từng file:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- api/api-deployment.yaml
- api/api-service.yaml
- database/db-deployment.yaml
- database/db-service.yaml
- cache/redis-config.yaml
- kafka/kafka.yaml
Bây giờ chỉ cần một lệnh cho tất cả:
kubectl apply -k k8s
6.3. Cách 2 — kustomization.yaml lồng nhau
Khi số lượng file tiếp tục tăng, danh sách resources trong root kustomization.yaml lại trở nên quá dài — chỉ là đổi chỗ vấn đề chứ chưa giải quyết. Cách tốt hơn: mỗi subdirectory tự có kustomization.yaml riêng, và root chỉ trỏ tới các subdirectory.
k8s/
├── api/
│ ├── api-deployment.yaml
│ ├── api-service.yaml
│ └── kustomization.yaml # Import files trong api/
├── database/
│ ├── db-deployment.yaml
│ ├── db-service.yaml
│ └── kustomization.yaml # Import files trong database/
└── kustomization.yaml # Import các subdirectory
Root kustomization.yaml:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- api
- database
kustomization.yaml trong api/:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- api-deployment.yaml
- api-service.yaml
Lưu ý: Khi chỉ định đường dẫn tới directory (không phải file), Kustomize tự động tìm file
kustomization.yamlbên trong directory đó. Không cần viết rõapi/kustomization.yaml— chỉ cầnapilà đủ.
Lưu ý: Trong các config cũ, việc trỏ tới directory khác được viết bằng field riêng tên
bases:. Field đó đã deprecate và nay gộp chung vàoresources:— gặpbases:trong repo cũ thì đọc nó nhưresources:là đúng.
Lợi ích không chỉ nằm ở chỗ root gọn hơn. Mỗi subdirectory giờ là một đơn vị độc lập, build được riêng để kiểm tra (kustomize build k8s/api), và thêm một service mới chỉ là thêm một thư mục cùng một dòng trong root — không ai phải đọc lại toàn bộ danh sách file để chắc rằng mình không bỏ sót.
7. Common Transformers
7.1. Transformers là gì?
Nhắc lại từ mục 4.2: transformer là cách Kustomize thực hiện thay đổi tự động trên tất cả resources đã import. Thay vì mở từng file YAML và chỉnh tay, chỉ cần khai báo transformer trong kustomization.yaml — Kustomize apply nó vào lúc build, và file gốc vẫn nguyên vẹn.
💡 Hình dung: Transformer giống con dấu của phòng hành chính. Hồ sơ dày bao nhiêu trang cũng vậy, không ai ngồi viết tay dòng "đã duyệt" lên từng trang — chỉ cần một con dấu đóng qua cả tập. Và vì bản gốc trong tủ hồ sơ không bị đóng dấu, lần sau cần một con dấu khác thì vẫn lấy đúng bản gốc đó ra dùng.
7.2. Các loại Common Transformers
| Transformer | Tác dụng |
|---|---|
labels | Thêm label chung vào mọi resource, tùy chọn ghi cả vào selector |
namePrefix | Thêm prefix vào tên mọi resource |
nameSuffix | Thêm suffix vào tên mọi resource |
namespace | Đặt mọi resource vào một namespace |
commonAnnotations | Thêm annotation chung vào mọi resource |
7.3. labels — và cái bẫy selector
Label là cặp key-value gắn vào metadata.labels của resource, dùng để nhóm và lọc. Nhưng trong Kubernetes, label còn một vai trò thứ hai nguy hiểm hơn nhiều: làm selector. Deployment dựa vào spec.selector.matchLabels để biết Pod nào là Pod của nó. Service dựa vào spec.selector để biết gửi traffic tới Pod nào. Nói cách khác, cùng một cặp key-value, chỗ này chỉ là ghi chú, chỗ kia là dây nối giữ hệ thống đứng vững.
Khai báo cơ bản:
labels:
- pairs:
department: engineering
Sau khi build, mọi Deployment và Service đều có department: engineering trong metadata.labels. Selector không bị đụng tới — đó là hành vi mặc định, tương đương includeSelectors: false.
Muốn label chui vào cả selector và cả pod template, phải bật cờ một cách có chủ đích:
labels:
- pairs:
app: nginx
includeSelectors: true
includeTemplates: true
Vì sao mặc định lại là false? Vì spec.selector của một Deployment là immutable — đã tạo rồi thì Kubernetes không cho sửa. Thêm một label vào selector của Deployment đang chạy nghĩa là lần apply tiếp theo sẽ bị từ chối, và cách duy nhất đi tiếp là xóa Deployment rồi tạo lại, tức là downtime.
Quy tắc thực dụng rút ra từ đó:
- Label mang tính mô tả —
department,team,owner,cost-center— cứ để mặc định, đừng động vào selector. - Label định danh ứng dụng —
app— chỉ bậtincludeSelectors: truekhi bạn đặt nó từ đầu, trên workload chưa từng deploy lần nào.
Lưu ý: Field cũ
commonLabelsvẫn chạy được trongkustomize.config.k8s.io/v1beta1nhưng đã bị deprecate từ Kustomize v5.0.0 và sẽ không có mặt trong APIv1. Nó tương đươnglabelskèmincludeSelectors: true, nên gặp config cũ viếtcommonLabelsthì hiểu ngay rằng selector đang bị ghi đè — và lệnhkustomize edit fixsẽ tự chuyển nó sang cú pháp mới.
7.4. namespace
Đặt mọi resource vào một namespace cụ thể:
namespace: debugging
Mọi resource, sau khi build, đều có metadata.namespace: debugging. Đây là transformer hữu dụng nhất khi cần dựng nguyên một bản sao của hệ thống sang namespace khác để thử nghiệm.
7.5. namePrefix và nameSuffix
namePrefix: KodeKloud-
nameSuffix: -web
Tên resource sẽ thành KodeKloud-api-deployment-web. Kustomize không chỉ đổi metadata.name mà còn cập nhật luôn các chỗ đang tham chiếu tới tên đó, nên Service vẫn trỏ đúng vào Deployment sau khi đổi tên.
Thường dùng trong subdirectory kustomization.yaml để phân biệt resources theo folder — api/ thêm -web, database/ thêm -storage.
7.6. commonAnnotations
commonAnnotations:
logging: verbose
Mọi resource sẽ có annotation logging: verbose trong metadata.
Ở đây có một điểm dễ nhầm. Sau khi biết commonLabels đã bị thay bằng labels, phản xạ tự nhiên là đổi luôn commonAnnotations thành annotations. Đừng. Kustomization API không có field tên annotations; commonAnnotations vẫn là cách viết hiện hành và không bị deprecate. Lý do rất đơn giản: annotation chưa bao giờ được dùng làm selector, nên nó không có cái bẫy immutable đã bàn ở mục 7.3, và vì thế cũng không cần một field mới để tách hành vi ra.
7.7. Phạm vi áp dụng — root vs subdirectory
| Vị trí khai báo | Phạm vi |
|---|---|
| Root kustomization.yaml | Áp dụng cho tất cả resources (global) |
| Subdirectory kustomization.yaml | Chỉ áp dụng cho resources được import trong directory đó |
Nếu đặt labels ở root, tất cả resources — kể cả trong subdirectories — đều được label. Nếu đặt trong api/kustomization.yaml, chỉ resources trong api/ được label. Đây cũng là lý do nên đẩy những gì mang tính toàn hệ thống (namespace, label tổ chức) lên root, và giữ lại ở subdirectory những gì chỉ đúng với riêng nhóm resource đó.
8. ConfigMap và Secret Generators
8.1. Vấn đề: sửa ConfigMap mà Pod không thèm restart
Tình huống rất quen: ứng dụng đọc LOG_LEVEL từ một ConfigMap. Cần bật debug, bạn sửa LOG_LEVEL: info thành LOG_LEVEL: debug, chạy kubectl apply, rồi ngồi đợi log debug hiện ra.
Nó không hiện ra.
ConfigMap trong cluster đúng là đã đổi. Nhưng Pod thì không. Deployment không có cách nào biết rằng nội dung một ConfigMap nó tham chiếu vừa thay đổi — spec của Deployment vẫn y nguyên từng ký tự, nên với Kubernetes thì chẳng có gì cần làm cả. Biến môi trường được nạp vào container lúc container khởi động, và container đó vẫn đang chạy với giá trị cũ.
Cách làm đúng theo khuyến nghị của Kubernetes là: tạo một ConfigMap tên mới, rồi sửa Deployment để trỏ sang tên mới đó. Chính việc sửa tên trong spec Deployment mới là thứ kích hoạt rolling update — Kubernetes thấy spec đổi, nên thay Pod cũ bằng Pod mới, và Pod mới đọc config mới.
Làm tay thì đúng nhưng cực kỳ phiền: mỗi lần đổi một dòng config là phải nghĩ ra tên mới, sửa ConfigMap, sửa Deployment, và nhớ dọn ConfigMap cũ. Generators sinh ra để tự động hóa đúng chuỗi thao tác đó.
8.2. configMapGenerator
Generator là loại khai báo bảo Kustomize tạo ra một resource hoàn toàn mới lúc build, thay vì đọc nó từ file có sẵn. Khác với transformer (sửa cái đã có), generator sinh cái chưa có.
configMapGenerator nhận dữ liệu từ ba nguồn:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- nginx-deployment.yaml
configMapGenerator:
- name: app-config
literals:
- LOG_LEVEL=info
- APP_MODE=production
literals— cặp key-value viết thẳng trong kustomization.yaml, ngăn cách bằng dấu=.files— mỗi file thành một key, tên file là key, nội dung file là value.envs— đọc một file.env, mỗi dòngKEY=valuethành một entry riêng.
Ví dụ hai dạng còn lại:
configMapGenerator:
- name: nginx-conf
files:
- nginx.conf
- name: app-env
envs:
- app.env
8.3. Name suffix hash — và vì sao nó mới là điểm mấu chốt
Build thử xem Kustomize sinh ra cái gì:
kustomize build k8s
# Output minh họa
# apiVersion: v1
# data:
# APP_MODE: production
# LOG_LEVEL: info
# kind: ConfigMap
# metadata:
# name: app-config-7hd2t4k9gm
(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ụ.)
Tên không phải app-config mà là app-config-7hd2t4k9gm. Cái đuôi đó là hash băm từ chính nội dung của ConfigMap.
Nhiều người gặp lần đầu sẽ thấy khó chịu và đi tìm cách tắt nó. Nhưng cái đuôi đó chính là toàn bộ lý do generator tồn tại. Đổi LOG_LEVEL=info thành LOG_LEVEL=debug, nội dung đổi, hash đổi, tên ConfigMap đổi theo — và Kustomize tự động sửa mọi chỗ đang tham chiếu tên đó, kể cả envFrom.configMapRef.name trong Deployment. Spec Deployment đổi, nên Kubernetes chạy rolling update. Đúng chuỗi thao tác thủ công ở mục 8.1, nhưng được làm hộ, và không bao giờ quên.
8.4. secretGenerator
Cùng một cơ chế, áp dụng cho Secret:
secretGenerator:
- name: db-credentials
literals:
- DB_USER=admin
- DB_PASSWORD=s3cr3t
type: Opaque
Kustomize tự base64-encode giá trị khi sinh ra Secret, nên không cần chạy echo -n ... | base64 bằng tay nữa. secretGenerator cũng nhận files và envs giống configMapGenerator, cộng thêm field type để khai báo loại Secret — ví dụ kubernetes.io/tls cho cặp cert và key.
Lưu ý: base64 là encoding, không phải mã hóa. Ai đọc được file kustomization.yaml là đọc được password. Đừng commit
literalschứa secret thật lên Git — dùngfilestrỏ tới file nằm ngoài repo, hoặc một công cụ quản lý secret riêng.
8.5. generatorOptions và disableNameSuffixHash
Đôi khi tên có hash thật sự gây vướng: một ConfigMap được tham chiếu từ chỗ Kustomize không nhìn thấy (một CRD lạ, một script bên ngoài, một Ingress annotation viết tay). Lúc đó tắt hash bằng generatorOptions:
generatorOptions:
disableNameSuffixHash: true
labels:
generated-by: kustomize
Khai báo này áp cho mọi generator trong cùng file. Ngoài disableNameSuffixHash, generatorOptions còn nhận labels, annotations, và immutable để đánh dấu ConfigMap/Secret sinh ra là bất biến.
Cũng có thể tắt cho riêng một generator bằng field options của chính nó — nhưng nếu generatorOptions ở cấp file đã đặt disableNameSuffixHash: true thì khai báo cục bộ không lật ngược lại được:
configMapGenerator:
- name: static-config
literals:
- REGION=ap-southeast-1
options:
disableNameSuffixHash: true
💡 Hình dung: Cái hash giống số phiên bản in trên bìa một tập tài liệu nội bộ. Sửa một dòng bên trong là bìa đổi số, và ai đang cầm bản cũ buộc phải đi lấy bản mới — không ai vô tình làm việc với nội dung đã lỗi thời. Tắt
disableNameSuffixHashnghĩa là bỏ số phiên bản đi: bìa lúc nào cũng như nhau, nên người cầm bản cũ chẳng có lý do gì phải đổi.
Vì vậy quy tắc là: mặc định cứ để hash bật. Chỉ tắt khi có một tham chiếu bên ngoài thật sự cần tên cố định — và khi đã tắt, nhớ rằng mình vừa tự nhận lại trách nhiệm restart Pod mỗi lần đổi config, bằng kubectl rollout restart deployment/<tên>.
Nguồn tham khảo
Nguồn gốc: Khóa "Certified Kubernetes Administrator (CKA)" — bài "Kustomize Basics" (vì sao cần Kustomize; base và overlays; cài đặt Kustomize; file kustomization.yaml; build và apply; quản lý project nhiều thư mục; common transformers), 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:
commonLabelsbị deprecate từ Kustomize v5.0.0, thay bằng fieldlabels, và sẽ không có mặt trong APIv1; lệnhkustomize edit fixtự chuyển đổi cú pháp — 2026-09-23, Kustomize Reference — commonLabelslabelsmặc định chỉ ghi vàometadata.labels;includeSelectors: truemới ghi thêm vào selector và pod template,includeTemplates: truechỉ ghi vào pod template, cả hai mặc định làfalse— 2026-09-23, Kustomize Reference — labelscommonAnnotationskhông bị đánh dấu deprecated và Kustomization API không có field tênannotations; các field đã deprecate cùng API gồmcommonLabels,bases,imageTags,patchesStrategicMerge,patchesJson6902,vars— 2026-09-23, kubernetes-sigs/kustomize — api/types/kustomization.goapiVersion: kustomize.config.k8s.io/v1beta1vẫn là version hiện hành của kindKustomization— 2026-09-23, kubernetes-sigs/kustomize — api/types/kustomization.go- Bản Kustomize standalone mới nhất là
kustomize/v5.8.1, phát hành 09/02/2026 — 2026-09-23, kubernetes-sigs/kustomize — Releases kustomize versionmặc định in đúng một chuỗi semver của binary — 2026-09-23, kubernetes-sigs/kustomize — kustomize/commands/version/version.go- Bản Kustomize nhúng trong kubectl được release độc lập và thường đi sau bản standalone;
kubectl version --clientin ra cả Client Version lẫn Kustomize Version — 2026-09-23, kubernetes-sigs/kustomize — README - kubectl v1.34 và v1.35 nhúng kustomize v5.7.1, kubectl v1.36 và v1.37 nhúng kustomize v5.8.1 — 2026-09-23, kubernetes/kubernetes — staging/src/k8s.io/kubectl/go.mod
- Script
install_kustomize.shvẫn là cách cài binary được tài liệu chính thức hướng dẫn; script tải bản release mới nhất về thư mục hiện tại và nhận tham số version cùng thư mục đích — 2026-09-23, Kustomize Installation — Binaries configMapGeneratormặc định gắn hash suffix theo nội dung vào tên ConfigMap; nội dung đổi làm tên đổi, Kustomize cập nhật mọi tham chiếu và workload thực hiện rolling update — 2026-09-23, Kustomize Reference — configMapGenerator- Deployment không có cơ chế nhận biết ConfigMap mà nó tham chiếu đã thay đổi nội dung, nên cách khuyến nghị là tạo ConfigMap tên mới rồi trỏ Deployment sang tên đó để kích hoạt rolling update — 2026-09-23, kubernetes-sigs/kustomize — examples/configGeneration.md
generatorOptionshỗ trợdisableNameSuffixHash,labels,annotations,immutable; đặt ở cấp file sẽ trùm lên khai báooptionscục bộ của từng generator — 2026-09-23, Kustomize Reference — generatorOptionssecretGeneratortự base64-encode giá trị và hỗ trợliterals,files,envs,type,namespace,options— 2026-09-23, Kustomize Reference — secretGenerator