Lab 2 — GitOps Repository Structure
1. 🎯 Mục tiêu
Sau Lab này, bạn sẽ hiểu và thực hành được:
- Hiểu GitOps Repository là gì và tại sao cần một cấu trúc repository rõ ràng.
- Phân biệt Application Repository và GitOps Repository.
- Biết cách tổ chức Kubernetes manifests theo
dev,staging,production. - Hiểu vai trò của Kustomize trong việc quản lý nhiều environment.
- Tự xây dựng một GitOps repository có thể sử dụng với ArgoCD ở các Lab tiếp theo.
2. 🤔 Vấn đề thực tế
Ở các Lab Kubernetes trước, có thể bạn đã deploy application bằng:
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml
Cách này rất đơn giản.
Nhưng hãy tưởng tượng bạn có 3 environment:
Development
Staging
Production
Mỗi environment lại có:
Deployment
Service
ConfigMap
Ingress
HPA
Secret
...
Lúc này nếu quản lý bằng các file nằm rải rác trên máy cá nhân:
my-project/
├── deployment.yaml
├── service.yaml
├── deployment-prod.yaml
├── deployment-staging.yaml
├── service-prod.yaml
└── service-staging.yaml
sẽ rất nhanh trở nên khó quản lý.
Ví dụ:
Production đang chạy version
v1.5, nhưng developer không biết chính xác file nào đang mô tả trạng thái Production.
Đây chính là vấn đề GitOps muốn giải quyết.
GitOps đưa ra một nguyên tắc rất đơn giản:
Git là Source of Truth.
Nói đơn giản:
Git Repository
│
│ mô tả
▼
Desired State
│
▼
Kubernetes Cluster
Nếu Git nói:
image: todo-backend:v1.5
thì Kubernetes nên chạy:
todo-backend:v1.5
Nếu Git thay đổi thành:
image: todo-backend:v1.6
ArgoCD sẽ phát hiện sự khác biệt và đồng bộ Kubernetes.
3. 🧠 Hiểu nhanh
3.1. GitOps Repository là gì?
GitOps Repository là repository chứa các file mô tả trạng thái mong muốn của Kubernetes.
Ví dụ:
GitOps Repository
│
├── Deployment
├── Service
├── Ingress
├── ConfigMap
├── HPA
└── ...
Repository này không nhất thiết chứa source code application.
Nó chủ yếu trả lời câu hỏi:
"Kubernetes Production nên chạy như thế nào?"
3.2. Application Repository và GitOps Repository
Đây là một phân chia rất quan trọng.
Application Repository
Chứa source code:
todo-backend/
├── src/
├── package.json
├── Dockerfile
└── ...
Nó trả lời:
Application được xây dựng như thế nào?
GitOps Repository
Chứa deployment configuration:
todo-gitops/
├── apps/
├── environments/
└── ...
Nó trả lời:
Application được deploy như thế nào?
Có thể hình dung:
┌──────────────────────┐
│ Application Repo │
│ │
│ Source Code │
│ Dockerfile │
│ Tests │
└──────────┬───────────┘
│
│ CI
▼
Docker Image
│
│
▼
┌──────────────────────┐
│ GitOps Repo │
│ │
│ Kubernetes manifests │
│ Environment config │
└──────────┬───────────┘
│
│ ArgoCD
▼
┌──────────────────────┐
│ Kubernetes │
└──────────────────────┘
Tại sao tách hai repository?
Vì source code và deployment state có vòng đời khác nhau.
Ví dụ:
Developer
│
│ sửa source code
▼
Application Repo
│
│ CI build
▼
todo-backend:v1.6
│
│ update deployment
▼
GitOps Repo
│
│ ArgoCD
▼
Production
CI chịu trách nhiệm build artifact.
GitOps + ArgoCD chịu trách nhiệm deploy artifact.
4. 🏗️ Architecture
Trong Lab này, chúng ta sẽ xây dựng repository theo mô hình:
┌──────────────────────┐
│ Application Repo │
│ │
│ todo-backend │
│ todo-frontend │
└──────────┬───────────┘
│
│ CI builds image
▼
┌──────────────────────┐
│ Container Registry │
│ │
│ backend:v1.0 │
│ backend:v1.1 │
└──────────┬───────────┘
│
│ image tag
▼
┌──────────────────────┐
│ GitOps Repository │
│ │
│ environments/ │
│ ├── dev │
│ ├── staging │
│ └── production │
└──────────┬───────────┘
│
│ ArgoCD
▼
┌──────────────────────┐
│ Kubernetes Cluster │
└──────────────────────┘
5. 🗂️ Thiết kế GitOps Repository
Có nhiều cách tổ chức GitOps repository.
Trong Lab này, chúng ta sử dụng cấu trúc đơn giản nhưng có thể mở rộng:
todo-gitops/
│
├── apps/
│ ├── backend/
│ │ ├── deployment.yaml
│ │ ├── service.yaml
│ │ └── kustomization.yaml
│ │
│ └── frontend/
│ ├── deployment.yaml
│ ├── service.yaml
│ └── kustomization.yaml
│
└── environments/
├── dev/
├── staging/
└── production/
Ý tưởng:
apps/
↓
Application configuration
environments/
↓
Environment-specific configuration
6. 🧩 Tại sao cần dev, staging, production?
Trong production thực tế, bạn thường không deploy trực tiếp:
Developer → Production
Mà thường:
Developer
↓
Development
↓
Staging
↓
Production
Mỗi environment có thể có configuration khác nhau.
Ví dụ:
DEV STAGING PROD
--------------------------------------------------
Replicas 1 2 5
CPU 100m 200m 500m
Memory 256Mi 512Mi 1Gi
Domain dev.xxx staging.xxx xxx.com
Source code có thể giống nhau.
Nhưng deployment configuration khác nhau.
Đó là lý do chúng ta không nên copy toàn bộ YAML thành:
deployment-dev.yaml
deployment-staging.yaml
deployment-production.yaml
Cách đó sẽ tạo rất nhiều duplication.
Thay vào đó, chúng ta có thể dùng Kustomize.
7. 🛠️ Kustomize là gì?
Kustomize cho phép chúng ta có một cấu hình Kubernetes cơ bản và tùy chỉnh nó cho từng environment.
Ví dụ:
Base
│
├──────────► Dev
│
├──────────► Staging
│
└──────────► Production
Thay vì copy:
deployment-dev.yaml
deployment-staging.yaml
deployment-production.yaml
chúng ta có:
base/
deployment.yaml
service.yaml
overlays/
dev/
staging/
production/
Base
Chứa configuration chung.
Overlay
Chứa những thay đổi riêng của từng environment.
8. 🧪 Thực hành — Tạo GitOps Repository
8.1. Tạo repository
Tạo một repository mới:
todo-gitops
Clone repository:
git clone <your-gitops-repository>
cd todo-gitops
8.2. Tạo cấu trúc thư mục
Tạo:
mkdir -p apps/backend
mkdir -p apps/frontend
mkdir -p environments/dev
mkdir -p environments/staging
mkdir -p environments/production
Kiểm tra:
tree
Kết quả:
todo-gitops
├── apps
│ ├── backend
│ └── frontend
└── environments
├── dev
├── staging
└── production
9. 📦 Tạo Backend Base
Tạo:
apps/backend/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: backend
image: nginx:1.27
ports:
- containerPort: 80
Tạo Service:
apps/backend/service.yaml
apiVersion: v1
kind: Service
metadata:
name: todo-backend
spec:
selector:
app: todo-backend
ports:
- port: 80
targetPort: 80
Tạo:
apps/backend/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yaml
10. 🔍 See Result — Build Base
Kustomize có thể render configuration thành Kubernetes YAML.
Chạy:
kubectl kustomize apps/backend
Bạn sẽ thấy:
apiVersion: apps/v1
kind: Deployment
...
---
apiVersion: v1
kind: Service
...
Điều quan trọng ở đây:
Kustomize chưa deploy gì cả.
Nó chỉ tạo ra final Kubernetes manifests.
Có thể hình dung:
deployment.yaml
service.yaml
│
│ Kustomize
▼
Final Kubernetes YAML
11. 🌱 Tạo Environment Dev
Bây giờ chúng ta muốn dev chạy backend với:
replicas = 1
Tạo:
environments/dev/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../apps/backend
Build:
kubectl kustomize environments/dev
Kustomize sẽ lấy configuration từ:
apps/backend
và sử dụng nó cho:
environments/dev
12. 🚀 Tạo Environment Production
Production có yêu cầu khác.
Ví dụ:
replicas = 3
Tạo:
environments/production/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../apps/backend
replicas:
- name: todo-backend
count: 3
Build:
kubectl kustomize environments/production
Tìm:
replicas: 3
Trong khi Dev vẫn:
replicas: 1
13. 🧠 Hiểu bản chất
Chúng ta đang có:
Base
│
┌───────┼────────┐
│ │ │
▼ ▼ ▼
Dev Staging Prod
│ │ │
1 pod 2 pods 3 pods
Điểm quan trọng:
Chúng ta không copy Deployment 3 lần.
Chúng ta chỉ thay đổi những gì khác nhau.
Đây chính là một trong những lý do Kustomize rất phù hợp với GitOps.
14. 🏗️ Hoàn thiện Repository
Sau khi hoàn thành, repository có thể có cấu trúc:
todo-gitops/
│
├── apps/
│ │
│ ├── backend/
│ │ ├── deployment.yaml
│ │ ├── service.yaml
│ │ └── kustomization.yaml
│ │
│ └── frontend/
│ ├── deployment.yaml
│ ├── service.yaml
│ └── kustomization.yaml
│
└── environments/
│
├── dev/
│ └── kustomization.yaml
│
├── staging/
│ └── kustomization.yaml
│
└── production/
└── kustomization.yaml
Đây là cấu trúc cơ bản mà chúng ta sẽ tiếp tục sử dụng ở các Lab sau.
15. 🔄 Git Commit
Đây là bước quan trọng trong GitOps.
Commit repository:
git add .
git commit -m "feat: create gitops repository structure"
git push
Bây giờ Git repository đã chứa:
Desired State
của Kubernetes.
16. 👀 See Result — Git trở thành Source of Truth
Giả sử Production hiện tại:
replicas: 3
Bạn thay đổi Git:
count: 5
Commit:
git add .
git commit -m "scale backend to 5 replicas"
git push
Khi ArgoCD được kết nối ở các Lab sau:
Git
│
│ replicas: 5
▼
ArgoCD
│
│ Sync
▼
Kubernetes
│
└── 5 Pods
Bạn không cần SSH vào server rồi chạy kubectl scale thủ công.
Đây chính là tư duy GitOps.
17. ⚠️ Những cách tổ chức nên tránh
17.1. Copy toàn bộ YAML cho từng environment
Không nên:
deployment-dev.yaml
deployment-staging.yaml
deployment-production.yaml
Vì sau một thời gian:
100 dòng × 3 environment
= 300 dòng
Một thay đổi nhỏ có thể phải sửa ở nhiều nơi.
17.2. Trộn source code với GitOps configuration
Không nên biến repository thành:
todo-app/
├── src/
├── Dockerfile
├── package.json
├── deployment.yaml
├── service.yaml
├── production.yaml
└── staging.yaml
Repository sẽ ngày càng khó quản lý khi application lớn lên.
Tách:
todo-app
và:
todo-gitops
sẽ rõ ràng hơn.
17.3. Để secret thật trong Git
Tuyệt đối tránh:
stringData:
password: my-production-password
rồi:
git push
Git lưu lịch sử.
Ngay cả khi bạn xóa file sau đó, secret vẫn có thể tồn tại trong Git history.
Ở các Lab sau chúng ta sẽ tìm hiểu cách xử lý vấn đề này bằng:
Sealed Secrets
External Secrets
Secret Manager
18. 💡 Production Tips
Tip 1 — GitOps Repository nên dễ đọc
Khi có sự cố Production, người khác phải có thể mở repository và nhanh chóng hiểu:
Application nào?
Environment nào?
Version nào?
Configuration nào?
Tip 2 — Không nên tạo quá nhiều abstraction
Một lỗi phổ biến là biến Kustomize thành một hệ thống quá phức tạp:
base
└── common
└── shared
└── templates
└── overlays
└── ...
Nếu developer mất 30 phút chỉ để tìm:
"Production đang lấy configuration từ đâu?"
thì cấu trúc đã quá phức tạp.
GitOps tốt không phải là GitOps có nhiều file nhất.
Tip 3 — Environment nên có ownership rõ ràng
Ví dụ:
environments/dev
↓
Developer
environments/staging
↓
Development Team
environments/production
↓
Platform / DevOps Team
Trong production thực tế, bạn có thể kết hợp với:
Pull Request
Code Review
Branch Protection
Approval
để tránh việc một người vô tình thay đổi Production.
19. 🧪 Exercise
Bây giờ hãy tự thực hành mà không nhìn lại phần trên.
Exercise 1 — Tạo Backend
Tạo:
apps/backend/
bao gồm:
deployment.yaml
service.yaml
kustomization.yaml
Exercise 2 — Tạo 3 Environment
Tạo:
environments/
├── dev/
├── staging/
└── production/
Mỗi environment phải có:
kustomization.yaml
Exercise 3 — Khác biệt giữa Environment
Thiết lập:
Dev → 1 replica
Staging → 2 replicas
Production → 3 replicas
Sau đó kiểm tra:
kubectl kustomize environments/dev
kubectl kustomize environments/staging
kubectl kustomize environments/production
Xác nhận số replica khác nhau.
Exercise 4 — Git Workflow
Thực hiện:
git add .
git commit -m "feat: add environment configurations"
git push
Sau đó kiểm tra repository trên GitHub.
Bạn phải có thể trả lời:
"Nếu Kubernetes Production bị mất, GitOps Repository có đủ thông tin để mô tả lại Production hay không?"
Nếu câu trả lời là có, bạn đã bắt đầu hiểu đúng tư duy GitOps.
20. 🧠 Tổng kết
Trong Lab này, điều quan trọng nhất không phải là nhớ cú pháp Kustomize.
Bạn cần nhớ mối quan hệ giữa các thành phần:
Application Repo
│
│ source code
▼
CI / Build
│
│ Docker Image
▼
GitOps Repo
│
│ desired state
▼
ArgoCD
│
│ sync
▼
Kubernetes
Và GitOps Repository:
todo-gitops/
│
├── apps/
│ ├── backend/
│ └── frontend/
│
└── environments/
├── dev/
├── staging/
└── production/
🎯 Mental Model cần nhớ
Application Repository nói "app được viết như thế nào".
GitOps Repository nói "app phải được deploy như thế nào".
ArgoCD đảm bảo Kubernetes chạy đúng với những gì Git mô tả.
21. 🚀 Lab tiếp theo
Ở Lab 2, chúng ta mới xây dựng GitOps Repository.
Nhưng hiện tại Git chỉ đang chứa YAML.
Kubernetes vẫn chưa tự động đọc repository này.
Ở Lab 3 — Install ArgoCD, chúng ta sẽ cài ArgoCD và kết nối:
GitHub
│
│ Watch
▼
ArgoCD
│
│ Sync
▼
Kubernetes
Từ đây, chúng ta sẽ bắt đầu thấy GitOps thực sự hoạt động: thay đổi Git → ArgoCD phát hiện → Kubernetes được cập nhật.
All rights reserved