Skip to content

Introduction to GitOps với ArgoCD

🏛️ Góc nhìn Lead Platform Engineer - HPN

Module này được viết với tầm nhìn kiến trúc và chiến lược. Mục tiêu: Biến Git thành nguồn sự thật duy nhất cho toàn bộ hạ tầng Kubernetes.

🎯 Triết Lý: "Git is the Single Source of Truth"

Nguyên tắc cốt lõi

text
📜 GITOPS MANIFESTO

1. Nếu nó không có trong Git → Nó không tồn tại
2. Nếu ai đó sửa trực tiếp trên Cluster → Git sẽ hoàn tác ngay lập tức
3. Mọi thay đổi phải qua Pull Request → Review, Approve, Merge
4. Cluster tự động sync với Git → No manual intervention

🚫 ANTI-PATTERN: "ClickOps"

bash
# ❌ SAI: SSH vào server rồi sửa trực tiếp
kubectl edit deployment myapp
kubectl set image deployment/myapp app=myapp:v2

# Hậu quả:
# - Không ai biết ai đã sửa gì
# - Không có audit trail
# - Không thể rollback dễ dàng
# - "Production drift" - Cluster khác với Git

Self-Healing: Sức mạnh của GitOps

📊Self-Healing: Sức mạnh của GitOps
📂Git Repository
manifests/
replicas: 3
ArgoCD monitors
🎯Kubernetes Cluster
Deployment
replicas: 3
👤Human (Incident)
kubectl scale --replicas=5
Manual change
🔄ArgoCD
⚠️ Drift detected!
Auto-sync: replicas=3

Kịch bản:

  1. Git định nghĩa replicas: 3
  2. Developer lỡ tay chạy kubectl scale --replicas=5
  3. ArgoCD phát hiện drift (Live ≠ Desired)
  4. ArgoCD tự động sync về replicas: 3
  5. Developer: "Tại sao nó cứ quay về 3?" → That's the point!

🔐 Push vs Pull Model: Security Deep Dive

Push Model (Cách cũ - Jenkins, GitLab CI)

Xem diagram so sánh bên dưới

⚠️ RỦI RO CỦA PUSH MODEL

Vấn đềMô tả
Credentials exposureCI Server cần lưu kubeconfig với quyền admin
Blast radiusNếu CI bị hack → Attacker có toàn quyền cluster
Network exposureCI phải có network access đến K8s API
No self-healingChỉ apply khi có pipeline chạy

Pull Model (GitOps - ArgoCD, Flux)

Xem diagram so sánh bên dưới

✅ ƯU ĐIỂM CỦA PULL MODEL

Lợi íchMô tả
No credentials leakKhông có secret nào rời khỏi cluster
Minimal exposureArgoCD chỉ cần READ access đến Git
Continuous syncTự động detect và apply changes
Self-healingDrift được correct ngay lập tức
Audit trailMọi thay đổi đều có Git commit history

So sánh trực quan

📊Push vs Pull Model: Security Comparison
❌ Push Model (Rủi ro cao)
👨‍💻Developer
🔧CI Server
Jenkins/GitLab
kubectl apply
(needs admin creds)
☸️K8s API Server
VS
✅ Pull Model (An toàn)
👨‍💻Developer
📂Git Repository
Poll every 3m
🔄ArgoCD
Inside Cluster
Tiêu chíPush ModelPull Model
CredentialsCI cần admin accessAgent trong cluster
DirectionCI → ClusterCluster ← Git
Self-healing❌ Không✅ Có
AuditCI logs (dễ mất)Git history (vĩnh viễn)
Security⚠️ High risk✅ Minimal attack surface

⚙️ ArgoCD: How It Works

Core Concept: Desired State vs Live State

📊ArgoCD Sync Cycle
📂Desired State (Git)
/manifests/production/
1Fetch
🔄ArgoCD Controller
2Compare
✅ In Sync
⚠️ Out of Sync
3Sync
☸️Live State (Cluster)

Application Custom Resource

ArgoCD quản lý deployments qua Application CRD:

yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: myapp-production
  namespace: argocd
spec:
  project: default
  
  # SOURCE: Lấy manifests từ đâu?
  source:
    repoURL: https://github.com/hpn/k8s-manifests.git
    targetRevision: main
    path: apps/myapp/overlays/production
  
  # DESTINATION: Deploy đến đâu?
  destination:
    server: https://kubernetes.default.svc
    namespace: production
  
  # SYNC POLICY: Tự động hay manual?
  syncPolicy:
    automated:
      prune: true       # Xóa resources không còn trong Git
      selfHeal: true    # Tự động fix drift
    syncOptions:
      - CreateNamespace=true

Sync Status

StatusÝ nghĩaAction
SyncedLive = DesiredKhông cần làm gì
OutOfSync ⚠️Live ≠ DesiredSync để apply changes
UnknownKhông thể fetch GitKiểm tra credentials/network
Progressing 🔄Đang syncChờ hoàn tất
DegradedResources unhealthyDebug application

🔄 GitOps Workflow

Developer Flow

📊Developer GitOps Workflow
👨‍💻
Developer
📂
Git
🔄
ArgoCD
☸️
K8s
1Git commit (Update image tag)
2PR Review & Merge
3Poll for changes (every 3m)
4Detect OutOfSync
5kubectl apply
6Report health status
7Mark as Synced ✅

CI/CD Pipeline Integration

📊CI/CD Pipeline with GitOps
CI Pipeline
📝App Code Repo
🔨Build & Test
📦Push Image
myapp:v1.2.3
CD via GitOps
📝Update Manifests
📂Git Manifests
🔄ArgoCD
☸️Kubernetes

Quy trình:

  1. CI: Build app → Run tests → Push image myapp:v1.2.3
  2. CI: Update values.yaml trong manifests repo với tag mới
  3. GitOps: ArgoCD detect change → Sync → Deploy

🛡️ HPN Production Standard

🚨 QUY ĐỊNH BẮT BUỘC TẠI HPN

text
╔═══════════════════════════════════════════════════════════════╗
║  TỪ NAY, BẠN BỊ CẤM DÙNG `kubectl apply -f` TRONG PRODUCTION  ║
║                   HÃY ĐỂ ROBOT (ArgoCD) LÀM VIỆC ĐÓ            ║
╚═══════════════════════════════════════════════════════════════╝

Tại sao?

Câu hỏikubectl applyGitOps
"Ai sửa cái này?"Không biếtGit commit author
"Sửa lúc nào?"Không biếtGit timestamp
"Tại sao sửa?"Không biếtCommit message
"Rollback về version trước?"Tìm file backup đâu?git revert
"Review trước khi deploy?"Không cóPull Request

Quick Start với ArgoCD

bash
# 1. Cài ArgoCD
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml

# 2. Lấy admin password
kubectl -n argocd get secret argocd-initial-admin-secret \
  -o jsonpath="{.data.password}" | base64 -d

# 3. Port-forward UI
kubectl port-forward svc/argocd-server -n argocd 8080:443

# 4. Tạo Application
kubectl apply -f - <<EOF
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: myapp
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/hpn/manifests.git
    path: apps/myapp
    targetRevision: HEAD
  destination:
    server: https://kubernetes.default.svc
    namespace: production
  syncPolicy:
    automated:
      selfHeal: true
EOF

🚀 Advanced Patterns

App of Apps: Bootstrap Pattern

💡 APP OF APPS LÀ GÌ?

Một "Root Application" quản lý nhiều Applications khác. Chỉ cần deploy 1 app, tự động tạo ra toàn bộ infrastructure.

Root Application YAML:

yaml
# apps/root-app.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: root-app
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/hpn/k8s-manifests.git
    path: apps  # 👈 Thư mục chứa các Application YAML
    targetRevision: main
  destination:
    server: https://kubernetes.default.svc
    namespace: argocd
  syncPolicy:
    automated:
      prune: true
      selfHeal: true

Directory Structure:

text
k8s-manifests/
├── apps/                      # 👈 Root App trỏ đến đây
│   ├── frontend.yaml          # Application cho frontend
│   ├── backend.yaml           # Application cho backend
│   ├── database.yaml          # Application cho database
│   └── monitoring.yaml        # Application cho monitoring
├── services/
│   ├── frontend/
│   │   ├── deployment.yaml
│   │   └── service.yaml
│   ├── backend/
│   │   ├── deployment.yaml
│   │   ├── service.yaml
│   │   └── configmap.yaml
│   └── ...

ApplicationSets: Dynamic Application Generation

💡 APPLICATIONSETS LÀ GÌ?

ApplicationSet tự động tạo nhiều Applications từ template + generator. Thay vì viết 10 Application YAML giống nhau, viết 1 ApplicationSet.

Generator Types:

GeneratorUse Case
ListExplicit list of clusters/apps
Git DirectoryMỗi folder trong repo = 1 app
Git FileConfig file định nghĩa apps
ClusterMỗi cluster = 1 app
MatrixCombine multiple generators

Example: Git Directory Generator

yaml
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: cluster-apps
  namespace: argocd
spec:
  generators:
  # 👇 Mỗi folder trong 'services/' = 1 Application
  - git:
      repoURL: https://github.com/hpn/k8s-manifests.git
      revision: main
      directories:
      - path: services/*
  
  template:
    metadata:
      # {{path.basename}} = tên folder (frontend, backend, ...)
      name: '{{path.basename}}'
    spec:
      project: default
      source:
        repoURL: https://github.com/hpn/k8s-manifests.git
        path: '{{path}}'
        targetRevision: main
      destination:
        server: https://kubernetes.default.svc
        namespace: '{{path.basename}}'
      syncPolicy:
        automated:
          prune: true
          selfHeal: true
        syncOptions:
        - CreateNamespace=true

Result: Nếu có 5 folders trong services/, ApplicationSet tự động tạo 5 Applications!

Sync Waves & Hooks

📊 SYNC WAVES

Điều khiển thứ tự deploy - resources với wave thấp deploy trước.

yaml
# Wave -1: Namespace và RBAC (deploy ĐẦU TIÊN)
apiVersion: v1
kind: Namespace
metadata:
  name: production
  annotations:
    argocd.argoproj.io/sync-wave: "-1"

---
# Wave 0: ConfigMaps và Secrets (mặc định)
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
  annotations:
    argocd.argoproj.io/sync-wave: "0"

---
# Wave 1: Database (deploy TRƯỚC app)
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: postgres
  annotations:
    argocd.argoproj.io/sync-wave: "1"

---
# Wave 2: Application (deploy SAU database)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
  annotations:
    argocd.argoproj.io/sync-wave: "2"

Sync Hooks:

yaml
# Pre-sync hook: Chạy TRƯỚC khi sync
apiVersion: batch/v1
kind: Job
metadata:
  name: db-migration
  annotations:
    argocd.argoproj.io/hook: PreSync
    argocd.argoproj.io/hook-delete-policy: HookSucceeded
spec:
  template:
    spec:
      containers:
      - name: migrate
        image: myapp:migrate
        command: ["./migrate.sh"]
      restartPolicy: Never
HookWhen
PreSyncTrước khi sync bắt đầu
SyncCùng lúc với resources
PostSyncSau khi sync thành công
SyncFailKhi sync fail

⚠️ ArgoCD Production Pitfalls

⚠️ NHỮNG LỖI THƯỜNG GẶP

1. Auto-prune xóa resources quan trọng

yaml
# ❌ NGUY HIỂM: Prune xóa mọi thứ không có trong Git
syncPolicy:
  automated:
    prune: true  # Nếu bạn quên commit PVC → BỊ XÓA!

# ✅ AN TOÀN: Protect specific resources
syncOptions:
- PrunePropagationPolicy=foreground
- PruneLast=true

2. SelfHeal undo emergency fixes

text
Scenario: 
  - Production incident, bạn cần patch nhanh
  - kubectl patch deployment/myapp ...
  - selfHeal=true → ArgoCD revert lại ngay lập tức!

Giải pháp:
  - Tạm disable selfHeal khi incident
  - Hoặc commit fix vào Git (đúng cách)

3. ApplicationSet tạo infinite Applications

yaml
# ❌ NGUY HIỂM: Không có filter
generators:
- git:
    directories:
    - path: '*'  # Bao gồm cả .git, node_modules, ...!

# ✅ AN TOÀN: Explicit paths
generators:
- git:
    directories:
    - path: 'services/*'
    - path: 'infrastructure/*'

4. Secrets trong Git (ngay cả encrypted)

text
Vấn đề: Commit secrets vào Git repo
  - Ngay cả khi dùng SealedSecrets, nếu key bị leak → tất cả secrets exposed

Giải pháp:
  - Dùng External Secrets Operator
  - Hoặc HashiCorp Vault
  - KHÔNG bao giờ commit raw secrets

ArgoCD Production Checklist

✅ CHECKLIST TRƯỚC KHI PRODUCTION

Security:

  • [ ] RBAC configured - không dùng admin account
  • [ ] SSO/OIDC enabled (không dùng local users)
  • [ ] Secrets KHÔNG được commit vào Git
  • [ ] Network policies cho ArgoCD namespace

Reliability:

  • [ ] HA mode enabled (3 replicas)
  • [ ] Redis cluster cho application controller
  • [ ] PodDisruptionBudget configured
  • [ ] Resource limits set

Operations:

  • [ ] Backup strategy cho ArgoCD (Applications CRDs)
  • [ ] Monitoring dashboard (Prometheus/Grafana)
  • [ ] Alert rules cho sync failures
  • [ ] Disaster recovery plan documented

Best Practices:

  • [ ] App of Apps pattern cho organization
  • [ ] Sync waves cho complex deployments
  • [ ] Health checks customized per app
  • [ ] Notification configured (Slack/Teams)

📊 Tổng Kết

Khái niệmMô tả
GitOpsPhương pháp dùng Git làm source of truth cho infrastructure
Pull ModelAgent trong cluster kéo changes từ Git (an toàn hơn Push)
App of AppsRoot Application quản lý nhiều Applications
ApplicationSetsTemplate + Generator = Dynamic Application creation
Sync WavesĐiều khiển thứ tự deploy resources
Self-HealTự động fix khi có drift

⚠️ KEY TAKEAWAYS

  1. Git là vua - Mọi thay đổi phải qua Git commit
  2. Pull > Push - ArgoCD trong cluster an toàn hơn CI bên ngoài
  3. App of Apps - Bootstrap pattern cho multi-app environments
  4. ApplicationSets - Scale với many clusters/apps
  5. Beware auto-prune - Có thể xóa resources quan trọng
  6. No more kubectl apply - Trong Production, hãy để ArgoCD làm

🔗 Liên kết