Skip to content

Challenge: GitOps Drift Scenario

🎮 Thử thách dành cho Senior Operator - HPN

Module này là bài thực hành hands-on để hiểu sâu về GitOps Drift DetectionSelf-Healing trong ArgoCD.

🎭 Kịch Bản: "The Naughty Junior"

Bối cảnh

Bạn là Senior Operator tại HPN. Hệ thống đang chạy ổn định với GitOps:

yaml
# Git Repository: k8s-manifests/apps/my-app/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
  namespace: production
spec:
  replicas: 3  # 👈 Đây là "Desired State" từ Git
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
        - name: app
          image: hpn/my-app:v1.2.3
          resources:
            requests:
              memory: "128Mi"
              cpu: "100m"

ArgoCD đã sync thành công. Cluster đang chạy 3 replicas.

Sự cố xảy ra

Một junior engineer mới vào công ty, chưa quen với quy trình GitOps. Vào lúc 2 giờ sáng, khi hệ thống báo high load, junior hoảng loạn và chạy:

bash
# ❌ Junior's "quick fix"
kubectl scale deployment my-app --replicas=5 -n production

📝 Câu Hỏi Cho Học Viên

Question 1: ArgoCD Status hiển thị gì?

Sau khi junior chạy kubectl scale, bạn mở ArgoCD UI. Status của Application sẽ hiển thị gì?

💡 Click để xem đáp án

Đáp án: OutOfSync ⚠️

text
Application Status:
├── Sync Status: OutOfSync
├── Health Status: Healthy
└── Summary: 
    └── Deployment my-app: Live differs from Desired
        └── spec.replicas: 5 (live) ≠ 3 (desired)

Giải thích:

  • Live State (Cluster): replicas: 5
  • Desired State (Git): replicas: 3
  • ArgoCD phát hiện sự khác biệt → OutOfSync
bash
# Kiểm tra bằng CLI
argocd app diff my-app

# Output hiển thị:
# ===== apps/Deployment production/my-app ======
# --- Desired
# +++ Live
# @@ -1,5 +1,5 @@
#  spec:
# -  replicas: 3
# +  replicas: 5

Question 2: Điều gì xảy ra nếu Self-Healing được bật?

Giả sử ArgoCD Application được cấu hình với selfHeal: true. Điều gì xảy ra ngay sau khi junior chạy lệnh scale?

💡 Click để xem đáp án

Đáp án: ArgoCD ngay lập tức "giết" 2 pods để quay về 3 replicas

Timeline thực tế:

TimeEvent
T+0sJunior runs kubectl scale --replicas=5
T+0sKubernetes creates 2 new pods
T+3sArgoCD detects drift (sync interval)
T+5sArgoCD applies desired state (replicas: 3)
T+7sKubernetes terminates 2 excess pods
T+10sJunior: "WTF?!" 😱

Log message trong ArgoCD:

text
[INFO] Detected drift in Deployment/my-app: spec.replicas 5 -> 3
[INFO] Auto-syncing due to selfHeal policy
[INFO] Successfully synced (dry run: false)

Question 3: Tại sao đây là điều tốt cho Security?

Giải thích tại sao hành vi self-healing này lại tăng cường bảo mật cho hệ thống?

💡 Click để xem đáp án

Đáp án: Ngăn chặn unauthorized changes & đảm bảo audit trail

Security BenefitGiải thích
Prevent unauthorized changesKể cả attacker có cluster access, không thể thay đổi persistent state
Immutable infrastructureCluster state luôn khớp với Git (reviewed & approved)
Audit trailMọi thay đổi hợp lệ đều có Git commit → Biết ai, khi nào, tại sao
Blast radius limitationManual changes chỉ tồn tại trong vài giây
ComplianceĐáp ứng yêu cầu SOC2, ISO27001 về change management

Kịch bản tấn công bị chặn:

Nếu không có GitOps:

  • Attacker modify → Changes persist
  • Không ai biết cho đến khi incident xảy ra
  • Không có baseline để rollback

Với GitOps + Self-Heal:

  • Attacker modify → ArgoCD revert trong < 10 giây
  • Alert được trigger
  • Git = trusted state, không bị compromise

🛠️ Challenge Code: Cấu hình ArgoCD Application

Yêu cầu

Viết một ArgoCD Application CRD với các tính năng:

  1. Automated Sync - Tự động deploy khi Git thay đổi
  2. Self-Healing - Tự động fix drift
  3. Prune - Xóa resources không còn trong Git
  4. Create Namespace - Tự tạo namespace nếu chưa có

Template

yaml
# Điền vào chỗ trống (???)
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: my-app-production
  namespace: argocd
spec:
  project: default
  
  source:
    repoURL: https://github.com/hpn/k8s-manifests.git
    targetRevision: main
    path: apps/my-app/overlays/production
  
  destination:
    server: https://kubernetes.default.svc
    namespace: production
  
  syncPolicy:
    ???
💡 Click để xem Solution
yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: my-app-production
  namespace: argocd
  # Thêm finalizer để an toàn khi xóa Application
  finalizers:
    - resources-finalizer.argocd.argoproj.io
spec:
  project: default
  
  source:
    repoURL: https://github.com/hpn/k8s-manifests.git
    targetRevision: main
    path: apps/my-app/overlays/production
  
  destination:
    server: https://kubernetes.default.svc
    namespace: production
  
  # ⚡ SYNC POLICY - Đây là phần quan trọng nhất!
  syncPolicy:
    # Tự động sync khi có thay đổi
    automated:
      # Xóa resources không còn trong Git
      prune: true
      # TỰ ĐỘNG FIX DRIFT - Self-healing!
      selfHeal: true
      # Cho phép sync nếu có resource đang OutOfSync
      allowEmpty: false
    
    # Sync options bổ sung
    syncOptions:
      # Tự tạo namespace nếu chưa tồn tại
      - CreateNamespace=true
      # Validate YAML trước khi apply
      - Validate=true
      # Sử dụng server-side apply (K8s 1.22+)
      - ServerSideApply=true
    
    # Retry policy cho trường hợp sync fail
    retry:
      limit: 5
      backoff:
        duration: 5s
        factor: 2
        maxDuration: 3m

Giải thích các config quan trọng:

ConfigGiá trịÝ nghĩa
automated.prunetrueXóa resource khi bị remove khỏi Git
automated.selfHealtrueTự động revert manual changes
syncOptions.CreateNamespacetrueTự tạo namespace
retry.limit5Retry tối đa 5 lần nếu sync fail

📊 Kiến Thức Bổ Sung

Sync Waves & Hooks

Trong production, bạn có thể cần kiểm soát thứ tự sync:

yaml
# ConfigMap phải được tạo TRƯỚC Deployment
apiVersion: v1
kind: ConfigMap
metadata:
  name: my-app-config
  annotations:
    argocd.argoproj.io/sync-wave: "-1"  # Sync trước

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
  annotations:
    argocd.argoproj.io/sync-wave: "0"   # Sync sau

Health Checks Custom

yaml
# argocd-cm ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-cm
  namespace: argocd
data:
  resource.customizations.health.mycrd.example.com_MyResource: |
    hs = {}
    if obj.status ~= nil then
      if obj.status.phase == "Running" then
        hs.status = "Healthy"
      else
        hs.status = "Progressing"
      end
    end
    return hs

Checklist Hoàn Thành

Học viên đã hoàn thành challenge khi:

  • [ ] Hiểu được OutOfSync status nghĩa là gì
  • [ ] Giải thích được cơ chế Self-Healing của ArgoCD
  • [ ] Liệt kê được ít nhất 3 lợi ích security của GitOps
  • [ ] Viết được ArgoCD Application CRD đầy đủ tính năng
  • [ ] Hiểu được tại sao không nên dùng kubectl apply trực tiếp

🔗 Liên kết