Lab 6 — GitOps với Kustomize
🎯 Mục tiêu
Sau Lab này, bạn sẽ:
- Hiểu Kustomize giải quyết vấn đề gì trong GitOps.
- Biết cách tổ chức Kubernetes manifests cho nhiều environment.
- Biết sử dụng Base / Overlay.
- Biết deploy Kustomize application bằng ArgoCD.
- Hiểu cách thay đổi
dev,staging,productionmà không copy-paste toàn bộ YAML. - Biết một số nguyên tắc tổ chức Kustomize trong production.
🤔 1. Vấn đề thực tế
Ở các lab trước, chúng ta đã deploy application bằng Kubernetes và ArgoCD.
Giả sử Todo App có 3 environment:
Development
│
├── 1 replica
└── image: todo:v1.0.0
Staging
│
├── 2 replicas
└── image: todo:v1.0.0
Production
│
├── 5 replicas
└── image: todo:v1.0.0
Thoạt nhìn khá đơn giản.
Nhưng Kubernetes manifests bắt đầu nhiều lên:
deployment.yaml
service.yaml
configmap.yaml
ingress.yaml
...
Nếu copy toàn bộ YAML cho từng environment:
kubernetes/
├── dev/
│ ├── deployment.yaml
│ ├── service.yaml
│ └── ingress.yaml
│
├── staging/
│ ├── deployment.yaml
│ ├── service.yaml
│ └── ingress.yaml
│
└── production/
├── deployment.yaml
├── service.yaml
└── ingress.yaml
Bạn sẽ có rất nhiều YAML bị trùng lặp.
Ví dụ Service của dev và production gần như giống nhau.
Nếu sửa:
service:
port: 8080
bạn có thể phải sửa ở nhiều nơi.
Đây là một vấn đề lớn trong GitOps:
GitOps cần Git là Source of Truth, vì vậy repository phải dễ đọc, dễ thay đổi và hạn chế duplication.
Kustomize giúp giải quyết vấn đề này.
🧠 2. Hiểu nhanh về Kustomize
2.1 Kustomize là gì?
Kustomize là công cụ giúp bạn tạo ra Kubernetes manifests khác nhau từ một bộ manifests cơ sở mà không cần copy toàn bộ YAML.
Thay vì:
Dev YAML
Staging YAML
Production YAML
ta có:
Base
│
┌───────┼────────┐
▼ ▼ ▼
Dev Staging Production
Base chứa những thứ chung.
Overlay chứa những thứ khác nhau.
2.2 Base là gì?
Base là cấu hình Kubernetes dùng chung cho tất cả environment.
Ví dụ:
base/
├── deployment.yaml
├── service.yaml
└── kustomization.yaml
Base có thể chứa:
Deployment
Service
ConfigMap
Ingress
Những thứ này không cần phải copy cho từng environment.
2.3 Overlay là gì?
Overlay là lớp cấu hình nằm trên Base để thay đổi behavior cho từng environment.
Ví dụ:
overlays/
├── dev/
├── staging/
└── production/
Mỗi environment có thể thay đổi:
replicas
image
resources
environment variables
Ingress
ConfigMap
Ví dụ:
Base
replicas: 1
│
├── dev
│ replicas: 1
│
├── staging
│ replicas: 2
│
└── production
replicas: 5
🏗️ 3. Architecture
Repository của chúng ta sẽ có cấu trúc:
gitops-repo/
│
├── apps/
│ └── todo/
│
│ ├── base/
│ │ ├── deployment.yaml
│ │ ├── service.yaml
│ │ └── kustomization.yaml
│ │
│ └── overlays/
│ │
│ ├── dev/
│ │ ├── kustomization.yaml
│ │ └── replica-patch.yaml
│ │
│ ├── staging/
│ │ ├── kustomization.yaml
│ │ └── replica-patch.yaml
│ │
│ └── production/
│ ├── kustomization.yaml
│ └── replica-patch.yaml
Flow:
Git Repository
│
▼
┌───────────┐
│ Base │
│ │
│ Deployment│
│ Service │
└─────┬─────┘
│
┌────────────┼────────────┐
▼ ▼ ▼
Dev Staging Production
│ │ │
▼ ▼ ▼
replicas: 1 replicas: 2 replicas: 5
│ │ │
└────────────┼────────────┘
▼
ArgoCD
│
▼
Kubernetes
Điểm quan trọng:
ArgoCD không thay thế Kustomize.
ArgoCD chịu trách nhiệm:
Git → Kubernetes
Kustomize chịu trách nhiệm:
Base + Overlay → Kubernetes Manifest
Hai công cụ bổ sung cho nhau.
🧪 4. Chuẩn bị Lab
4.1 Kiểm tra Kustomize
Các phiên bản Kubernetes hiện đại thường đã tích hợp Kustomize trong kubectl.
Kiểm tra:
kubectl version --client
Sau đó:
kubectl kustomize version
Nếu command hoạt động là chúng ta có thể bắt đầu.
🛠️ 5. Tạo GitOps Repository
5.1 Tạo cấu trúc thư mục
mkdir -p gitops-repo/apps/todo/base
mkdir -p gitops-repo/apps/todo/overlays/dev
mkdir -p gitops-repo/apps/todo/overlays/staging
mkdir -p gitops-repo/apps/todo/overlays/production
cd gitops-repo
Kiểm tra:
tree
Kết quả:
apps
└── todo
├── base
└── overlays
├── dev
├── staging
└── production
🧱 6. Tạo Base
6.1 Tại sao cần Base?
Todo App có một số cấu hình giống nhau ở mọi environment:
Deployment
Service
Container port
Service port
Labels
Không có lý do gì phải viết lại chúng 3 lần.
Vì vậy chúng ta đưa chúng vào base.
6.2 Tạo Deployment
Tạo:
apps/todo/base/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: todo-backend
spec:
replicas: 1
selector:
matchLabels:
app: todo-backend
template:
metadata:
labels:
app: todo-backend
spec:
containers:
- name: todo-backend
image: nginx:1.27
ports:
- containerPort: 80
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
Ở đây chúng ta sử dụng nginx để lab tập trung vào Kustomize.
Trong project thật, bạn có thể thay bằng:
your-registry/todo-backend:v1.0.0
🧩 7. Tạo Service
Tạo:
apps/todo/base/service.yaml
apiVersion: v1
kind: Service
metadata:
name: todo-backend
spec:
selector:
app: todo-backend
ports:
- port: 80
targetPort: 80
type: ClusterIP
📝 8. Tạo kustomization.yaml
Đây là file quan trọng nhất của Kustomize.
Tạo:
apps/todo/base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yaml
Bạn có thể hiểu đơn giản:
kustomization.yaml
│
├── deployment.yaml
│
└── service.yaml
Nó nói cho Kustomize biết:
"Hãy lấy những resource này và tạo thành một Kubernetes application."
🔍 9. Build Base
Explain
Trước khi đưa Kustomize vào ArgoCD, chúng ta nên kiểm tra local trước.
Điều này rất quan trọng.
Nếu Kustomize build sai:
Git
↓
ArgoCD
↓
ERROR
Debug sẽ khó hơn.
Vì vậy:
Validate manifest trước, commit sau.
Do
Chạy:
kubectl kustomize apps/todo/base
Hoặc:
kubectl kustomize apps/todo/base > /tmp/todo.yaml
See Result
Bạn sẽ thấy Kustomize tạo ra:
apiVersion: apps/v1
kind: Deployment
...
---
apiVersion: v1
kind: Service
...
Kustomize không tạo ra Kubernetes resource mới.
Nó chỉ:
YAML nguồn
↓
Kustomize
↓
Manifest Kubernetes hoàn chỉnh
🌱 10. Tạo Development Environment
10.1 Tại sao cần Overlay?
Dev cần ít resource.
Ví dụ:
Dev
replicas = 1
Production:
Production
replicas = 5
Chúng ta không muốn sửa Base mỗi lần deploy production.
Vì vậy tạo Overlay.
10.2 Tạo Dev kustomization
Tạo:
apps/todo/overlays/dev/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: todo-dev
resources:
- ../../base
replicas:
- name: todo-backend
count: 1
Ở đây:
../../base
có nghĩa:
Dev sử dụng Base làm cấu hình nền.
Sau đó:
replicas:
- name: todo-backend
count: 1
ghi đè số replica.
🔵 11. Tạo Staging Environment
Tạo:
apps/todo/overlays/staging/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: todo-staging
resources:
- ../../base
replicas:
- name: todo-backend
count: 2
Staging sử dụng cùng Base nhưng:
replicas = 2
🔴 12. Tạo Production Environment
Tạo:
apps/todo/overlays/production/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: todo-production
resources:
- ../../base
replicas:
- name: todo-backend
count: 5
Production:
replicas = 5
🔍 13. So sánh các Environment
Bây giờ chúng ta có:
BASE
│
┌─────────┼─────────┐
▼ ▼ ▼
DEV STAGING PRODUCTION
│ │ │
1 pod 2 pods 5 pods
Điểm quan trọng là:
deployment.yaml
service.yaml
chỉ tồn tại một lần.
Chúng ta không copy chúng cho từng environment.
🧪 14. Build Development
Do
kubectl kustomize apps/todo/overlays/dev
Hoặc:
kubectl kustomize apps/todo/overlays/dev > /tmp/todo-dev.yaml
See Result
Bạn sẽ thấy:
spec:
replicas: 1
và:
metadata:
namespace: todo-dev
🧪 15. Build Production
Chạy:
kubectl kustomize apps/todo/overlays/production
Bạn sẽ thấy:
spec:
replicas: 5
và:
metadata:
namespace: todo-production
Như vậy:
Base
│
├── Dev Overlay
│ ↓
│ replicas: 1
│
├── Staging Overlay
│ ↓
│ replicas: 2
│
└── Production Overlay
↓
replicas: 5
🚀 16. Deploy trực tiếp bằng kubectl
Trước khi dùng ArgoCD, hãy thử deploy bằng Kubernetes.
Dev
kubectl apply -k apps/todo/overlays/dev
Kiểm tra:
kubectl get pods -n todo-dev
Bạn sẽ thấy Pod:
todo-backend-xxxxxxxxxx-xxxxx
Kiểm tra Deployment:
kubectl get deployment -n todo-dev
Expected:
NAME READY UP-TO-DATE AVAILABLE
todo-backend 1/1 1 1
🔄 17. Kustomize + ArgoCD
Đây mới là phần quan trọng nhất của Lab.
Trước đây:
Developer
│
▼
Git
│
▼
kubectl apply
│
▼
Kubernetes
Bây giờ:
Developer
│
▼
Git Repository
│
▼
ArgoCD
│
│ Kustomize
▼
Kubernetes
ArgoCD có thể đọc:
apps/todo/overlays/dev
và tự xử lý Kustomize.
Bạn không cần build YAML rồi commit YAML generated vào Git.
🏗️ 18. Tạo ArgoCD Application
Tạo:
argocd/todo-dev.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: todo-dev
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/YOUR_USERNAME/gitops-repo.git
targetRevision: main
path: apps/todo/overlays/dev
destination:
server: https://kubernetes.default.svc
namespace: todo-dev
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
Thay:
YOUR_USERNAME
bằng GitHub username của bạn.
📤 19. Push Repository lên GitHub
Tạo repository:
gitops-repo
Sau đó:
git init
git add .
git commit -m "feat: add todo app with kustomize"
git branch -M main
git remote add origin https://github.com/YOUR_USERNAME/gitops-repo.git
git push -u origin main
🚀 20. Deploy Application vào ArgoCD
Apply ArgoCD Application:
kubectl apply -f argocd/todo-dev.yaml
Kiểm tra:
kubectl get applications -n argocd
Bạn sẽ thấy:
NAME SYNC STATUS HEALTH STATUS
todo-dev Synced Healthy
Kiểm tra Kubernetes:
kubectl get all -n todo-dev
👀 21. Quan sát trên ArgoCD
Mở ArgoCD UI.
Bạn sẽ thấy:
todo-dev
│
├── Deployment
│ └── todo-backend
│
└── Service
└── todo-backend
ArgoCD đang theo dõi:
Git
│
│ desired state
▼
ArgoCD
│
│ actual state
▼
Kubernetes
Nếu hai trạng thái khác nhau:
Git:
replicas = 1
Kubernetes:
replicas = 3
ArgoCD có thể phát hiện:
OutOfSync
và với:
selfHeal: true
ArgoCD sẽ cố gắng đưa Kubernetes trở lại trạng thái trong Git.
🧪 22. Thử nghiệm Self-Healing
Đây là một bài test rất quan trọng.
Do
Thay đổi Deployment trực tiếp:
kubectl scale deployment todo-backend \
-n todo-dev \
--replicas=3
Kiểm tra:
kubectl get deployment -n todo-dev
Bạn sẽ thấy:
READY
3/3
See Result
Một lúc sau:
kubectl get deployment -n todo-dev
có thể trở lại:
READY
1/1
Tại sao?
Vì Git vẫn nói:
replicas = 1
ArgoCD coi Git là:
Desired State — trạng thái mong muốn.
Kubernetes đang có:
Actual State — trạng thái thực tế.
ArgoCD phát hiện:
Desired State
replicas = 1
≠
Actual State
replicas = 3
và reconcile lại.
🧠 23. Hiểu bản chất GitOps + Kustomize + ArgoCD
Đây là phần bạn nên nhớ.
Không cần học thuộc hàng chục câu lệnh.
Chỉ cần hiểu:
Git
│
│ Source of Truth
▼
┌─────────────────┐
│ Kustomize │
│ │
│ Base + Overlay │
└────────┬────────┘
│
▼
ArgoCD
│
│ Reconcile
▼
Kubernetes
Kustomize làm gì?
Base
+
Overlay
↓
Manifest cuối cùng
ArgoCD làm gì?
Git
↓
Compare
↓
Sync
↓
Kubernetes
Kubernetes làm gì?
Run Application
🌍 24. Quản lý nhiều Environment
Bây giờ hãy tưởng tượng project thực tế:
GitOps Repository
│
└── apps
│
└── todo
│
├── base
│
└── overlays
├── dev
├── staging
└── production
Mỗi environment có ArgoCD Application riêng:
Git
│
┌───────┼────────┐
▼ ▼ ▼
dev staging production
│ │ │
▼ ▼ ▼
ArgoCD ArgoCD ArgoCD
│ │ │
▼ ▼ ▼
Kubernetes Kubernetes Kubernetes
Trong thực tế, bạn có thể có:
todo-dev
todo-staging
todo-production
và mỗi Application trỏ tới:
apps/todo/overlays/dev
apps/todo/overlays/staging
apps/todo/overlays/production
⚙️ 25. Khi nào nên dùng Kustomize?
Kustomize đặc biệt phù hợp khi:
- Có nhiều environment.
- Manifest Kubernetes tương đối giống nhau.
- Chỉ cần thay đổi một số giá trị giữa các environment.
- Muốn tránh copy-paste YAML.
- Muốn Git repository dễ đọc.
Ví dụ:
Base
│
┌──────────┼──────────┐
▼ ▼ ▼
Dev Staging Prod
│ │ │
1 pod 2 pods 5 pods
Đây là use case rất phổ biến của Kustomize.
⚠️ 26. Những lỗi thường gặp
❌ 26.1 Sai đường dẫn Base
Ví dụ:
resources:
- ../../base
Nếu cấu trúc thư mục sai, Kustomize sẽ báo lỗi.
Kiểm tra:
tree apps/todo
❌ 26.2 Resource name không đúng
Ví dụ Base:
metadata:
name: todo-backend
nhưng Overlay:
replicas:
- name: backend
count: 3
Kustomize không tìm thấy resource:
backend
vì tên thật là:
todo-backend
Kinh nghiệm: khi patch không hoạt động, kiểm tra kind và metadata.name trước.
❌ 26.3 ArgoCD báo OutOfSync
Đừng ngay lập tức chạy:
kubectl apply
vì như vậy bạn đang bypass GitOps.
Hãy kiểm tra:
Git
↓
Kustomize
↓
ArgoCD
↓
Kubernetes
Xác định trạng thái nào đang khác.
💡 27. Kinh nghiệm Production
27.1 Không copy toàn bộ manifest
Không nên:
dev/deployment.yaml
staging/deployment.yaml
production/deployment.yaml
nếu 90% nội dung giống nhau.
Nên:
base/
overlays/
27.2 Base nên chứa cấu hình chung
Ví dụ:
Deployment
Service
common labels
container ports
resource defaults
Overlay chứa:
replicas
environment-specific config
image
Ingress
resources
27.3 Không biến Kustomize thành "mê cung patch"
Khi project lớn, bạn có thể thấy:
patch-1.yaml
patch-2.yaml
patch-prod.yaml
patch-prod-v2.yaml
patch-prod-final.yaml
patch-prod-final-v2.yaml
Đây là dấu hiệu cấu trúc đang trở nên khó quản lý.
Kustomize nên giúp cấu hình dễ hiểu hơn, không phải tạo thêm một tầng phức tạp.
🧪 28. Exercise
Exercise 1 — Tạo Production Overlay
Tạo:
overlays/production/
với:
replicas = 5
namespace = todo-production
Kiểm tra:
kubectl kustomize apps/todo/overlays/production
Exercise 2 — Thay đổi Image
Thay:
nginx:1.27
thành:
nginx:1.28
chỉ trong Production.
Gợi ý sử dụng:
images:
- name: nginx
newTag: "1.28"
Sau đó:
kubectl kustomize apps/todo/overlays/production
Kiểm tra image đã thay đổi chưa.
Exercise 3 — GitOps Workflow
Thay đổi:
production replicas: 5
thành:
production replicas: 3
Sau đó:
git add .
git commit -m "chore: scale production"
git push
Quan sát ArgoCD.
Bạn nên thấy:
Git
│
│ push
▼
ArgoCD
│
│ detect change
▼
Sync
│
▼
Kubernetes
🎯 29. Tổng kết
Sau Lab này, bạn nên hình dung GitOps architecture như sau:
GitHub
│
│
▼
┌─────────────┐
│ Kustomize │
│ │
│ Base │
│ + │
│ Overlay │
└──────┬──────┘
│
▼
ArgoCD
│
│ Reconcile
▼
Kubernetes
│
▼
Application
Điều quan trọng nhất cần nhớ:
Kustomize
=
Base + Overlay
ArgoCD
=
Git → Kubernetes
Kết hợp lại:
Git
│
├── Base
│
└── Overlay
│
▼
Kustomize
│
▼
ArgoCD
│
▼
Kubernetes
Sau Lab 6, bạn đã có nền tảng để quản lý nhiều Kubernetes environment bằng GitOps mà không phải copy-paste hàng loạt YAML.
Ở Lab 7 — GitOps với Helm, chúng ta sẽ giải quyết một vấn đề khác: khi application trở nên phức tạp, có rất nhiều cấu hình và muốn đóng gói Kubernetes manifests thành một package có thể tái sử dụng.
All rights reserved