Module 20 GitOps 5 labs

GitOps với Argo CD và Flux

Áp dụng GitOps — dùng Git làm single source of truth cho Kubernetes — với Argo CD và Flux CD: cài đặt, sync ứng dụng, phát hiện drift, rollback, app-of-apps pattern và promote qua môi trường dev-staging-prod.

Công cụ thực hành argocd CLI, flux CLI, kubectl, Helm, Git
Nền tảng CLI, VS Code, Git, kubectl, Helm
Thời điểm phát hành 23/05/2026
Ngày biên soạn 23/05/2026
Người biên soạn Trần Văn Hòa — Microsoft Certified Trainer (MCT)

Mục tiêu học tập

1. Lý thuyết cốt lõi

1.1. GitOps là gì?

GitOps là phương pháp vận hành hệ thống trong đó Git là single source of truth cho toàn bộ trạng thái mong muốn của hạ tầng và ứng dụng. Thuật ngữ do Weaveworks đề xuất năm 2017. OpenGitOps (CNCF) định nghĩa 4 nguyên tắc:

4 nguyên tắc GitOps (OpenGitOps v1.0)

  • 1. Declarative: trạng thái hệ thống được mô tả khai báo (YAML/Helm/Kustomize), không dùng lệnh imperative.
  • 2. Versioned & Immutable: mọi thay đổi được commit vào Git — lịch sử đầy đủ, rollback bằng git revert.
  • 3. Pulled automatically: agent trong cluster tự pull từ Git, không cần push credentials ra ngoài (security model tốt hơn).
  • 4. Continuously reconciled: agent liên tục so sánh desired state (Git) với actual state (cluster) và tự sửa drift.

GitOps vs CI/CD truyền thống: CI/CD push-based (pipeline SSH vào cluster, chạy kubectl apply) → credentials cluster bị expose trong CI runner. GitOps pull-based: agent trong cluster kéo từ Git → cluster không cần expose ra ngoài, audit trail đầy đủ trong Git.

1.2. Argo CD — kiến trúc

Argo CD là GitOps controller cho Kubernetes, thuộc CNCF graduated project. Kiến trúc:

ComponentVai trò
argocd-serverAPI server + Web UI (gRPC/HTTP), xác thực, RBAC
argocd-repo-serverClone Git repo, render Helm/Kustomize/JSONNET manifest
argocd-application-controllerReconciliation loop: compare Git ↔ cluster, trigger sync
Application CRDĐịnh nghĩa: source (repo/path/revision) + destination (cluster/namespace)
AppProject CRDRBAC boundary: ai được deploy repo nào vào namespace nào

Argo CD hỗ trợ source: plain YAML/Kustomize/Helm/Jsonnet. Sync policy: automated (tự sync khi Git thay đổi) + selfHeal (tự sửa drift) + prune (xóa resource không còn trong Git).

1.3. Flux CD v2 — kiến trúc

Flux v2 (Flux2) là GitOps toolkit cho Kubernetes, cũng thuộc CNCF. Khác Argo CD ở chỗ Flux là tập hợp các controller độc lập (microservice), mỗi cái xử lý một loại source/kustomization:

1.4. Argo CD vs Flux CD

Tiêu chíArgo CDFlux CD v2
UIWeb UI built-in (đẹp, trực quan)Không có UI, dùng CLI/Grafana dashboard
Cài đặtSingle manifest hoặc Helm chartflux bootstrap (tự commit vào Git)
Multi-clusterArgo CD quản lý nhiều cluster từ 1 instanceMỗi cluster chạy Flux riêng
Image automationArgocd-image-updater (addon)Built-in (image-automation controller)
GitOps thuầnModerate (có thể dùng CLI push)Strict (mọi thứ qua Git)

1.5. App-of-Apps và ApplicationSet

App-of-Apps pattern (Argo CD): một Application "root" trỏ vào thư mục chứa nhiều Application YAML khác — Argo CD tự deploy tất cả. Phù hợp quản lý nhiều app / nhiều team từ một Git repo. ApplicationSet là CRD mạnh hơn: tự sinh Application từ template kết hợp với generator (list, git, cluster, matrix) — dùng để deploy cùng app lên nhiều cluster/môi trường với một object duy nhất.

2. Thực hành (Labs)

LAB-096

Cài Argo CD trên Kubernetes cluster

argocd CLI · kubectl · Helm

🎯 Mục tiêu: Cài Argo CD vào namespace argocd, expose UI qua port-forward, đăng nhập bằng argocd CLI, đổi admin password.

🧰 Công cụ / nền tảng: kubectl, Helm 3, argocd CLI, Git, kind hoặc k3d (local cluster).

📦 Chuẩn bị: Cluster Kubernetes local (kind/k3d/minikube) hoặc AKS/EKS/GKE. kubectl context đã được cấu hình. Cài argocd CLI:

# Cài argocd CLI (Linux/macOS)
curl -sSL -o /usr/local/bin/argocd \
  https://github.com/argoproj/argo-cd/releases/latest/download/argocd-linux-amd64
chmod +x /usr/local/bin/argocd

# Windows (PowerShell)
# winget install ArgoProj.ArgoCD

▶️ Các bước (CLI):

# 1. Tạo local cluster nếu chưa có (dùng kind)
kind create cluster --name gitops-lab

# 2. Cài Argo CD (phương pháp 1: manifest trực tiếp)
kubectl create namespace argocd
kubectl apply -n argocd \
  -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml

# Hoặc phương pháp 2: Helm chart
# helm repo add argo https://argoproj.github.io/argo-helm
# helm install argocd argo/argo-cd -n argocd --create-namespace \
#   --set configs.params."server\.insecure"=true

# 3. Chờ tất cả pod Ready
kubectl wait --for=condition=Ready pod \
  -l app.kubernetes.io/name=argocd-server \
  -n argocd --timeout=120s

kubectl get pods -n argocd

# 4. Port-forward để truy cập UI
kubectl port-forward svc/argocd-server -n argocd 8080:443 &
# Truy cập: https://localhost:8080

# 5. Lấy initial admin password
ARGOCD_PASS=$(kubectl -n argocd get secret argocd-initial-admin-secret \
  -o jsonpath="{.data.password}" | base64 -d)
echo "Initial password: $ARGOCD_PASS"

# 6. Đăng nhập bằng CLI
argocd login localhost:8080 \
  --username admin \
  --password "$ARGOCD_PASS" \
  --insecure

# 7. Đổi password
argocd account update-password \
  --current-password "$ARGOCD_PASS" \
  --new-password "GitOps@Lab2026!"

# 8. Kiểm tra cluster đã đăng ký
argocd cluster list

# 9. Xem version
argocd version

✅ Kết quả mong đợi: kubectl get pods -n argocd thấy 7 pod đều Running. argocd login thành công. argocd cluster list hiển thị in-cluster. UI tại https://localhost:8080 hiển thị dashboard trống.

🧹 Cleanup: Giữ lại cluster cho LAB-097/098/099. Xóa khi xong toàn bộ: kind delete cluster --name gitops-lab.

LAB-097

Deploy ứng dụng từ Git repo bằng Argo CD

argocd CLI · kubectl · Git

🎯 Mục tiêu: Tạo Git repo chứa Kubernetes manifest, đăng ký vào Argo CD, tạo Application và quan sát quá trình sync tự động khi push commit mới.

🧰 Công cụ / nền tảng: argocd CLI, kubectl, Git, GitHub/GitLab account.

📦 Chuẩn bị: Argo CD đã cài (LAB-096), CLI đã login. Tài khoản GitHub.

▶️ Các bước:

# 1. Tạo Git repo chứa app manifest
mkdir gitops-app-manifests && cd gitops-app-manifests
git init

# 2. Tạo manifest: Namespace, Deployment, Service
mkdir -p apps/guestbook

cat > apps/guestbook/namespace.yaml << 'EOF'
apiVersion: v1
kind: Namespace
metadata:
  name: guestbook
EOF

cat > apps/guestbook/deployment.yaml << 'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
  name: guestbook-ui
  namespace: guestbook
spec:
  replicas: 2
  selector:
    matchLabels:
      app: guestbook-ui
  template:
    metadata:
      labels:
        app: guestbook-ui
    spec:
      containers:
      - name: guestbook-ui
        image: gcr.io/heptio-images/ks-guestbook-demo:0.2
        ports:
        - containerPort: 80
        resources:
          requests:
            cpu: "50m"
            memory: "64Mi"
          limits:
            cpu: "200m"
            memory: "128Mi"
EOF

cat > apps/guestbook/service.yaml << 'EOF'
apiVersion: v1
kind: Service
metadata:
  name: guestbook-ui
  namespace: guestbook
spec:
  selector:
    app: guestbook-ui
  ports:
  - port: 80
    targetPort: 80
  type: ClusterIP
EOF

# 3. Commit và push lên GitHub
git add -A
git commit -m "feat: initial guestbook manifests"
# Tạo repo trên GitHub rồi push:
# git remote add origin https://github.com//gitops-app-manifests.git
# git push -u origin main

# 4. Đăng ký repo với Argo CD (public repo không cần credential)
argocd repo add https://github.com//gitops-app-manifests.git

# Nếu repo private, thêm credential:
# argocd repo add https://github.com//repo.git \
#   --username  --password 

# 5. Tạo Application với auto-sync
argocd app create guestbook \
  --repo https://github.com//gitops-app-manifests.git \
  --path apps/guestbook \
  --dest-server https://kubernetes.default.svc \
  --dest-namespace guestbook \
  --sync-policy automated \
  --auto-prune \
  --self-heal

# Hoặc dùng YAML Application manifest:
cat > argocd-app-guestbook.yaml << 'EOF'
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: guestbook
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com//gitops-app-manifests.git
    targetRevision: HEAD
    path: apps/guestbook
  destination:
    server: https://kubernetes.default.svc
    namespace: guestbook
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
      - CreateNamespace=true
EOF
kubectl apply -f argocd-app-guestbook.yaml

# 6. Theo dõi quá trình sync
argocd app get guestbook
argocd app sync guestbook  # trigger sync thủ công nếu cần
argocd app wait guestbook --sync --timeout 60

# 7. Kiểm tra pod đã deploy
kubectl get all -n guestbook

# 8. Test GitOps: cập nhật replicas trong Git
sed -i 's/replicas: 2/replicas: 3/' apps/guestbook/deployment.yaml
git add apps/guestbook/deployment.yaml
git commit -m "scale: increase replicas to 3"
git push

# Sau ~30 giây, Argo CD tự sync
argocd app get guestbook --refresh
kubectl get pods -n guestbook  # sẽ thấy 3 pods

✅ Kết quả mong đợi: argocd app get guestbook cho thấy Sync Status: Synced, Health: Healthy. Sau khi push commit tăng replicas, trong vòng 30-60 giây cluster tự scale lên 3 pods mà không cần kubectl apply thủ công.

🧹 Cleanup: argocd app delete guestbook --cascade — xóa Application và toàn bộ resource trong namespace guestbook.

LAB-098

Drift detection, self-heal và rollback với Argo CD

argocd CLI · kubectl

🎯 Mục tiêu: Mô phỏng drift (sửa trực tiếp trên cluster), quan sát Argo CD phát hiện và tự heal; sau đó thực hiện rollback về revision cũ bằng argocd CLI.

🧰 Công cụ / nền tảng: argocd CLI, kubectl, cluster từ LAB-097.

📦 Chuẩn bị: App guestbook từ LAB-097 đang running với selfHeal=true.

▶️ Các bước:

# === PHẦN 1: Drift Detection & Self-Heal ===

# 1. Xem trạng thái hiện tại
argocd app get guestbook
kubectl get deployment guestbook-ui -n guestbook -o yaml | grep replicas

# 2. Mô phỏng drift: scale deployment trực tiếp (bypass Git)
kubectl scale deployment guestbook-ui -n guestbook --replicas=1
echo "Drift introduced: replicas manually changed to 1"

# 3. Xem Argo CD phát hiện drift ngay lập tức
argocd app get guestbook
# OutOfSync: deployment.apps guestbook-ui (replicas mismatch)

# 4. Chờ self-heal tự động (nếu selfHeal=true)
sleep 30
kubectl get deployment guestbook-ui -n guestbook -o jsonpath='{.spec.replicas}'
# Sẽ tự trở về 3 (giá trị trong Git)

# 5. Xem lịch sử sync events
argocd app history guestbook

# === PHẦN 2: Tắt selfHeal, test drift thủ công ===

# 6. Tắt selfHeal để test manual sync
argocd app set guestbook --self-heal=false

# 7. Tạo drift lại
kubectl scale deployment guestbook-ui -n guestbook --replicas=1

# 8. Kiểm tra: Argo CD biết drift nhưng KHÔNG tự sửa
argocd app get guestbook
# Status: OutOfSync (nhưng không tự fix vì selfHeal=false)

# 9. Sync thủ công
argocd app sync guestbook
kubectl get deployment guestbook-ui -n guestbook -o jsonpath='{.spec.replicas}'
# Trở về 3

# === PHẦN 3: Rollback ===

# 10. Push một thay đổi "xấu" vào Git
# (Giả sử dùng image tag sai)
# Trong repo:
# image: gcr.io/heptio-images/ks-guestbook-demo:BROKEN
# git add . && git commit -m "bug: wrong image tag" && git push

# Nếu không muốn thật sự dùng broken image, simulate bằng cách
# dùng history để xem revision IDs:
argocd app history guestbook
# Output ví dụ:
# ID  DATE                           REVISION
# 0   2026-05-23 10:00:00 +0000 UTC  abc1234 (HEAD)
# 1   2026-05-23 09:50:00 +0000 UTC  def5678

# 11. Rollback về revision trước (ID=1)
argocd app rollback guestbook 1
# Argo CD deploy lại manifest từ revision def5678

# 12. Kiểm tra
argocd app get guestbook
# Note: sau rollback, app sẽ ở trạng thái OutOfSync
# vì cluster state != HEAD của Git
# Đây là expected behavior — cần fix Git để sync lại

# 13. Bật lại selfHeal
argocd app set guestbook --self-heal=true

# 14. Xem diff giữa Git và cluster
argocd app diff guestbook

✅ Kết quả mong đợi: Drift (replicas=1) bị phát hiện trong vòng <5 giây. Với selfHeal=true, cluster tự heal về 3 replicas trong 30 giây mà không cần thao tác. argocd app rollback thành công, pod chạy đúng image của revision cũ. argocd app diff hiển thị rõ difference.

🧹 Cleanup: argocd app set guestbook --self-heal=true, đảm bảo app synced. Giữ lại cho LAB-099.

LAB-099

App-of-Apps pattern với ApplicationSet

argocd CLI · kubectl · ApplicationSet

🎯 Mục tiêu: Tổ chức nhiều Application bằng App-of-Apps pattern (root app → child apps), sau đó nâng cấp lên ApplicationSet để tự sinh app theo generator.

🧰 Công cụ / nền tảng: argocd CLI, kubectl, Git repo từ LAB-097.

📦 Chuẩn bị: Argo CD running, CLI logged in, Git repo đã có apps/guestbook.

▶️ Các bước:

# === PHẦN 1: App-of-Apps Pattern ===

# 1. Cấu trúc repo cho app-of-apps:
# gitops-app-manifests/
# ├── apps/                     (child app manifests)
# │   ├── guestbook/
# │   └── metrics-server/
# └── app-of-apps/              (root app — chứa Application CRDs)
#     ├── guestbook-app.yaml
#     └── metrics-server-app.yaml

mkdir -p app-of-apps

# 2. Root app manifest cho guestbook
cat > app-of-apps/guestbook-app.yaml << 'EOF'
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: guestbook
  namespace: argocd
  finalizers:
    - resources-finalizer.argocd.argoproj.io
spec:
  project: default
  source:
    repoURL: https://github.com//gitops-app-manifests.git
    targetRevision: HEAD
    path: apps/guestbook
  destination:
    server: https://kubernetes.default.svc
    namespace: guestbook
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
      - CreateNamespace=true
EOF

# 3. Thêm metrics-server app
mkdir -p apps/metrics-server
cat > apps/metrics-server/install.yaml << 'EOF'
apiVersion: v1
kind: Namespace
metadata:
  name: metrics-server
EOF

cat > app-of-apps/metrics-server-app.yaml << 'EOF'
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: metrics-server
  namespace: argocd
  finalizers:
    - resources-finalizer.argocd.argoproj.io
spec:
  project: default
  source:
    repoURL: https://kubernetes-sigs.github.io/metrics-server/
    chart: metrics-server
    targetRevision: "3.12.1"
    helm:
      values: |
        args:
          - --kubelet-insecure-tls
  destination:
    server: https://kubernetes.default.svc
    namespace: metrics-server
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
      - CreateNamespace=true
EOF

# 4. Commit
git add app-of-apps/ apps/metrics-server/
git commit -m "feat: add app-of-apps structure"
git push

# 5. Tạo Root Application (quản lý tất cả child apps)
argocd app create root-apps \
  --repo https://github.com//gitops-app-manifests.git \
  --path app-of-apps \
  --dest-server https://kubernetes.default.svc \
  --dest-namespace argocd \
  --sync-policy automated \
  --self-heal

argocd app sync root-apps
argocd app list
# Sẽ thấy: root-apps, guestbook, metrics-server

# === PHẦN 2: ApplicationSet với List Generator ===

# 6. Tạo ApplicationSet deploy guestbook lên nhiều namespace (simulate môi trường)
cat > app-of-apps/guestbook-appset.yaml << 'EOF'
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: guestbook-envs
  namespace: argocd
spec:
  generators:
    - list:
        elements:
          - env: dev
            namespace: guestbook-dev
            replicas: "1"
          - env: staging
            namespace: guestbook-staging
            replicas: "2"
  template:
    metadata:
      name: "guestbook-{{env}}"
    spec:
      project: default
      source:
        repoURL: https://github.com//gitops-app-manifests.git
        targetRevision: HEAD
        path: apps/guestbook
        kustomize:
          patches:
            - target:
                kind: Deployment
                name: guestbook-ui
              patch: |-
                - op: replace
                  path: /spec/replicas
                  value: {{replicas}}
            - target:
                kind: Deployment
                name: guestbook-ui
              patch: |-
                - op: replace
                  path: /metadata/namespace
                  value: {{namespace}}
      destination:
        server: https://kubernetes.default.svc
        namespace: "{{namespace}}"
      syncPolicy:
        automated:
          prune: true
          selfHeal: true
        syncOptions:
          - CreateNamespace=true
EOF

git add app-of-apps/guestbook-appset.yaml
git commit -m "feat: add ApplicationSet for multi-env guestbook"
git push

# 7. Sync root-apps để pick up ApplicationSet mới
argocd app sync root-apps
sleep 10
argocd app list
# Sẽ thấy guestbook-dev, guestbook-staging được tạo tự động

kubectl get pods -n guestbook-dev      # 1 pod
kubectl get pods -n guestbook-staging  # 2 pods

✅ Kết quả mong đợi: argocd app list hiển thị: root-apps, guestbook, metrics-server, guestbook-dev, guestbook-staging — tất cả Synced/Healthy. guestbook-dev có 1 pod, guestbook-staging có 2 pod. Khi thêm một entry mới vào list generator và push Git, Argo CD tự tạo Application mới mà không cần thao tác thủ công.

🧹 Cleanup: argocd app delete root-apps --cascade — xóa root app và tất cả child apps cascade. kubectl delete ns guestbook guestbook-dev guestbook-staging metrics-server.

LAB-100

Promotion dev → staging → prod với Flux image automation

flux CLI · kubectl · GitHub

🎯 Mục tiêu: Cài Flux v2, bootstrap với GitHub, cấu hình image automation tự update image tag trong Git khi có image mới, thực hiện promotion thủ công qua PR từ dev → staging → prod.

🧰 Công cụ / nền tảng: flux CLI, kubectl, GitHub account + Personal Access Token (PAT), cluster Kubernetes.

📦 Chuẩn bị: Cài flux CLI. GitHub PAT với quyền repo read/write.

# Cài flux CLI (Linux)
curl -s https://fluxcd.io/install.sh | sudo bash

# Windows (PowerShell)
# winget install fluxcd.flux

flux version

▶️ Các bước:

# === PHẦN 1: Bootstrap Flux vào GitHub ===

export GITHUB_TOKEN=
export GITHUB_USER=
export GITHUB_REPO=flux-gitops-lab

# 1. Bootstrap: Flux tự tạo repo (nếu chưa có), commit config vào đó, cài controller vào cluster
flux bootstrap github \
  --owner=$GITHUB_USER \
  --repository=$GITHUB_REPO \
  --branch=main \
  --path=clusters/dev \
  --personal \
  --token-auth

# 2. Kiểm tra Flux controllers
flux check
kubectl get pods -n flux-system
# source-controller, kustomize-controller, helm-controller, notification-controller

# 3. Clone repo Flux vừa tạo
git clone https://github.com/$GITHUB_USER/$GITHUB_REPO.git
cd $GITHUB_REPO

# === PHẦN 2: Deploy app qua Flux ===

# 4. Tạo GitRepository source
flux create source git podinfo \
  --url=https://github.com/stefanprodan/podinfo \
  --branch=master \
  --interval=1m \
  --export > clusters/dev/podinfo-source.yaml

# 5. Tạo Kustomization (deploy app)
flux create kustomization podinfo \
  --target-namespace=default \
  --source=podinfo \
  --path="./kustomize" \
  --prune=true \
  --interval=5m \
  --export > clusters/dev/podinfo-kustomization.yaml

git add clusters/
git commit -m "feat: add podinfo app via Flux"
git push

# 6. Theo dõi reconciliation
flux get kustomizations --watch
# podinfo    True    Applied revision: master/...

kubectl get pods -n default | grep podinfo

# === PHẦN 3: Image Automation ===

# 7. Thêm image-reflector và image-automation controller
flux bootstrap github \
  --owner=$GITHUB_USER \
  --repository=$GITHUB_REPO \
  --branch=main \
  --path=clusters/dev \
  --personal \
  --token-auth \
  --components-extra=image-reflector-controller,image-automation-controller

# 8. Tạo ImageRepository (scan Docker Hub cho podinfo)
flux create image repository podinfo \
  --image=ghcr.io/stefanprodan/podinfo \
  --interval=1m \
  --export > clusters/dev/podinfo-registry.yaml

# 9. Tạo ImagePolicy (chọn tag semver tăng dần)
flux create image policy podinfo \
  --image-ref=podinfo \
  --select-semver=">=6.0.0 <7.0.0" \
  --export > clusters/dev/podinfo-policy.yaml

# 10. Sửa deployment để Flux biết chỗ nào update image tag
# Trong file kustomize/deployment.yaml của repo podinfo, thêm marker:
# image: ghcr.io/stefanprodan/podinfo:6.0.0 # {"$imagepolicy": "flux-system:podinfo"}
# (Flux sẽ tìm marker này và replace tag)

# 11. Tạo ImageUpdateAutomation
flux create image update flux-system \
  --git-repo-ref=flux-system \
  --git-repo-path=./clusters/dev \
  --checkout-branch=main \
  --push-branch=main \
  --author-name=flux-bot \
  [email protected] \
  --commit-template="chore: update image tag to {{range .Updated.Images}}{{.}}{{end}}" \
  --export > clusters/dev/image-update-automation.yaml

git add clusters/
git commit -m "feat: enable image automation for podinfo"
git push

# 12. Xem kết quả automation
flux get images repository podinfo   # scan status
flux get images policy podinfo       # latest tag detected

# Kiểm tra commit do flux-bot tạo trong repo
git log --oneline | head -5
# sẽ thấy commit "chore: update image tag to ..."

# === PHẦN 4: Manual Promotion dev → staging ===

# 13. Tạo branch staging, copy manifest từ dev và chỉnh replicas
git checkout -b staging
cp -r clusters/dev clusters/staging

# Sửa replicas cho staging
cat > clusters/staging/podinfo-kustomization.yaml << 'EOF'
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
  name: podinfo
  namespace: flux-system
spec:
  interval: 5m0s
  path: ./kustomize
  prune: true
  sourceRef:
    kind: GitRepository
    name: podinfo
  targetNamespace: staging
  patches:
    - patch: |
        - op: replace
          path: /spec/replicas
          value: 3
      target:
        kind: Deployment
        name: podinfo
EOF

git add clusters/staging/
git commit -m "feat: add staging environment config"
git push -u origin staging

# 14. Tạo Pull Request từ staging → main (promotion)
# gh pr create --base main --head staging \
#   --title "promote: podinfo staging → main" \
#   --body "Promotes latest image tag from dev to staging"

# 15. Sau merge PR, Flux tự deploy lên staging
flux get kustomizations

✅ Kết quả mong đợi: flux check all OK. kubectl get pods thấy podinfo running. Image automation tự tạo commit với tag mới khi có release mới trên registry. Promotion qua PR đảm bảo toàn bộ lịch sử thay đổi nằm trong Git — mọi team member đều thấy ai promote gì khi nào.

🧹 Cleanup: flux uninstall --silent — xóa toàn bộ Flux khỏi cluster. Xóa repo GitHub nếu muốn: gh repo delete $GITHUB_USER/$GITHUB_REPO --yes. kind delete cluster --name gitops-lab.

3. Tình huống doanh nghiệp thực tế

Bối cảnh

Một công ty e-commerce có 3 cluster Kubernetes (dev/staging/prod) và 15 microservice. CI/CD cũ: Jenkins pipeline SSH vào cluster chạy kubectl apply — credentials bị lưu trong Jenkins, audit trail không rõ ràng, và 2 lần deploy nhầm lên prod gây incident. Sau một incident nghiêm trọng (deploy thiếu configmap lên prod), họ quyết định chuyển sang GitOps.

Cách xử lý (GitOps với Argo CD)

  • Repo structure: Mono-repo GitOps với cấu trúc clusters/{dev,staging,prod}/; mỗi môi trường là Kustomize overlay. Branch protection trên prod/: yêu cầu 2 approval trước khi merge.
  • Argo CD multi-cluster: 1 Argo CD instance quản lý cả 3 cluster. ApplicationSet với cluster generator tự sinh app cho từng cluster theo label.
  • CI chỉ build & push image, không deploy: sau khi image mới lên registry, Argo CD Image Updater tự commit tag vào repo dev. Để lên staging/prod phải qua PR + approval.
  • Self-healing: Mọi thay đổi trực tiếp trên cluster (dù vô tình hay cố ý) bị revert trong 60 giây — loại bỏ "works on my kubectl" problem.
  • Kết quả: Incident rate giảm 80%; mỗi deploy có full audit trail trong Git; rollback từ 20 phút (restore backup) xuống 30 giây (argocd app rollback).

📚 Nguồn tham khảo

Module 19: Configuration Management Module 21: Release Engineering
Zalo