0

Banking Demo -- Phase 2 : ArgoCD và GitOps — Deploy Helm chart từ Git

Bài 5/11: ArgoCD và GitOps — Deploy Helm chart từ Git


Mở đầu

bài 4, chúng ta đã chuyển toàn bộ manifest sang Helm chart trong phase2-helm-chart/banking-demo/. Cài đặt và nâng cấp đều dùng helm install / helm upgrade với nhiều file values. Điều đó vẫn đòi hỏi mỗi môi trường phải có người (hoặc script) chạy Helm tay; thay đổi từ Git chưa tự động phản ánh lên cluster.

GitOps đưa Git làm nơi quản lý: cấu hình (chart + values) nằm trong repo; một công cụ đọc Git và đồng bộ lên Kubernetes. ArgoCD là công cụ phổ biến nhất cho việc này: nó clone repo, render Helm (hoặc Kustomize), so sánh với cluster và apply khi bạn sync.

Bài này giải thích cách deploy chart banking-demo bằng ArgoCD: Application trỏ tới repo + path chart, valueFiles theo môi trường, sync policy, sync waves và lưu ý khi dùng Helm hooks. REPO : https://github.com/kevinram164/banking-demo.git


GitOps và ArgoCD trong một phút

Khái niệm Ý nghĩa
GitOps Git là nguồn chân lý; mọi thay đổi cấu hình qua Git, không sửa tay trên cluster.
ArgoCD Controller đọc Git (Helm/Kustomize/plain YAML), so sánh với cluster, apply khi sync.
Application Một resource ArgoCD mô tả “lấy gì từ đâu, deploy vào đâu” (repo, path, namespace).
Sync Hành động “áp dụng state từ Git lên cluster” (ArgoCD chạy helm template + kubectl apply).

Với Banking Demo: chart và values nằm trong repo; ArgoCD trỏ tới phase2-helm-chart/banking-demo, dùng danh sách valueFiles (common + từng service). Khi bạn sync, ArgoCD render Helm với các file đó và apply lên namespace banking. Không cần cài Helm trên máy hay trong CI; chỉ cần push Git và sync (thủ công hoặc auto).

image.png


Hai cách deploy chart với ArgoCD

Trong repo có hai hướng tiếp cận:

Cách Mô tả File Ưu / Nhược
Một Application Một Application deploy cả chart với đủ valueFiles (common + tất cả services). argocd/application.yaml Đơn giản, một dashboard; sync/rollback ảnh hưởng cả stack.
Per-service Applications Mỗi thành phần (namespace, postgres, redis, kong, từng service, frontend, ingress) một Application riêng. argocd/applications/*.yaml Dễ quản lý từng phần, sync/rollback độc lập; cần nhiều Application và sync waves.

Bài này mô tả cả hai; thực tế bạn có thể chọn một trong hai tùy nhu cầu (demo nhanh vs quản lý từng service).


Cấu trúc ArgoCD trong repo

phase2-helm-chart/
├── argocd/
│   ├── project.yaml              # AppProject: gom nhóm, giới hạn repo/namespace
│   ├── application.yaml          # Một Application deploy cả chart (đơn giản)
│   ├── applications/            # Per-service (chuyên nghiệp)
│   │   ├── namespace.yaml        # Namespace + Secret (wave -1)
│   │   ├── postgres.yaml
│   │   ├── redis.yaml
│   │   ├── kong.yaml
│   │   ├── auth-service.yaml
│   │   ├── account-service.yaml
│   │   ├── transfer-service.yaml
│   │   ├── notification-service.yaml
│   │   ├── frontend.yaml
│   │   └── ingress.yaml
│   └── ARGOCD.md                 # Hướng dẫn chi tiết, troubleshooting
└── banking-demo/                 # Helm chart (bài 4)
    ├── Chart.yaml
    ├── values.yaml
    ├── templates/
    └── charts/                    # valueFiles trỏ tới đây

AppProject (project.yaml) khai báo project banking-demo: cho phép repo nào, deploy vào namespace nào. Application (một hoặc nhiều) thuộc project đó, trỏ source.path tới phase2-helm-chart/banking-demo và dùng helm.valueFiles (và có thể parameters) để merge values.


Application: repo, path, valueFiles

Một Application ArgoCD cho Helm chart cần:

  • source.repoURL: URL Git (vd: https://github.com/kevinram164/banking-demo.git).
  • source.targetRevision: Branch hoặc tag (vd: main).
  • source.path: Đường dẫn tới thư mục chứa chart (vd: phase2-helm-chart/banking-demo).
  • source.helm.releaseName: Tên release Helm (hiển thị trong ArgoCD, dùng cho history).
  • source.helm.valueFiles: Danh sách file values (đường dẫn trong repo), merge theo thứ tự.
  • destination.server: Cluster (thường https://kubernetes.default.svc).
  • destination.namespace: Namespace đích (vd: banking).

Ví dụ một Application deploy cả stack (trích từ application.yaml):

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: banking-demo
  namespace: argocd
spec:
  project: banking-demo
  source:
    repoURL: https://github.com/kevinram164/banking-demo.git
    targetRevision: main
    path: phase2-helm-chart/banking-demo
    helm:
      releaseName: banking-demo
      valueFiles:
        - charts/common/values.yaml
        - charts/postgres/values.yaml
        - charts/redis/values.yaml
        - charts/kong/values.yaml
        - charts/auth-service/values.yaml
        - charts/account-service/values.yaml
        - charts/transfer-service/values.yaml
        - charts/notification-service/values.yaml
        - charts/frontend/values.yaml
  destination:
    server: https://kubernetes.default.svc
    namespace: banking

ArgoCD sẽ clone repo, vào path, chạy tương đương helm template release-name . -f charts/common/values.yaml -f charts/postgres/values.yaml ... và apply kết quả lên namespace banking. Đổi image, port hay env chỉ cần sửa trong charts/<service>/values.yaml, push Git rồi sync Application.

image.png image.png


ValueFiles theo môi trường (staging / production)

Cùng một chart, khác môi trường thường chỉ khác values (namespace, host ingress, image tag, replica, tài nguyên…). Có hai cách:

Cách 1: Nhiều file values trong repo, Application chọn danh sách

Trong repo giữ:

  • charts/common/values.yaml — giá trị chung.
  • charts/<service>/values.yaml — giá trị mặc định từng service.
  • (Tùy chọn) charts/common/values-staging.yaml, charts/common/values-production.yaml — override theo env.

Application staging dùng valueFiles:

valueFiles:
  - charts/common/values.yaml
  - charts/common/values-staging.yaml
  - charts/postgres/values.yaml
  # ... các service

Application production dùng:

valueFiles:
  - charts/common/values.yaml
  - charts/common/values-production.yaml
  - charts/postgres/values.yaml
  # ...

File sau override file trước; chỉ cần định nghĩa trong values-staging.yaml / values-production.yaml những key khác (vd global.namespace, ingress.host, auth-service.image.tag).

Cách 2: ApplicationSet sinh nhiều Application theo môi trường

Dùng ApplicationSet (controller riêng, thường cài kèm ArgoCD) để từ một template sinh ra nhiều Application, mỗi env một cái (vd banking-demo-staging, banking-demo-production). Mỗi Application có destination.namespace và valueFiles khác nhau (vd values-staging.yaml vs values-production.yaml). Chi tiết cấu hình ApplicationSet xem tài liệu ArgoCD; ý tưởng là “một lần khai báo, nhiều môi trường”.

Trong Banking Demo hiện tại, một Application dùng đủ valueFiles (common + từng service); khi cần staging/prod bạn chỉ cần thêm file override và (hoặc) thêm Application/ApplicationSet trỏ tới file đó.


Sync policy: automated, prune, selfHeal, syncOptions

syncPolicy:
  automated: null    # Hoặc bỏ; khi null = không auto sync
  syncOptions:
    - CreateNamespace=true
    - ApplyOutOfSyncOnly=true
  retry:
    limit: 3
    backoff:
      duration: 5s
      factor: 2
      maxDuration: 1m
Mục Ý nghĩa
automated null hoặc không khai báo: chỉ sync khi bạn bấm Sync (UI/CLI). Đặt automated: { prune: true, selfHeal: true } thì ArgoCD tự sync theo chu kỳ (vd 3 phút).
prune true: xóa resource trên cluster nếu không còn trong manifest Git. Nguy hiểm nếu nhầm branch/path; nhiều team chọn false và prune thủ công.
selfHeal true: khi có người/script sửa tay trên cluster, ArgoCD sẽ revert theo Git. An toàn “drift = 0” nhưng dễ gây bất ngờ nếu có thay đổi ngoài ý muốn.
CreateNamespace=true Tự tạo namespace đích nếu chưa có. Với “một Application” thường bật; với per-service chỉ bật ở Application tạo namespace (wave -1).
ApplyOutOfSyncOnly=true Chỉ apply resource đang OutOfSync, giảm restart không cần thiết (vd không động vào Postgres/Redis khi chỉ đổi image app).
retry Khi sync lỗi, ArgoCD retry với backoff; hạn chế số lần và thời gian tối đa.

Trong repo, application.yaml (một Application) đặt automated: null — sync thủ công. Các Application per-service trong applications/*.yaml dùng prune: false, selfHeal: false để tránh xóa/sửa drift tự động; bạn chủ động sync khi đã kiểm tra.


Sync Waves (khi dùng per-service Applications)

Khi mỗi service một Application, thứ tự deploy quan trọng: namespace và secret trước, sau đó postgres/redis, rồi Kong, microservices, frontend, cuối cùng ingress. ArgoCD hỗ trợ sync wave qua annotation:

metadata:
  annotations:
    argocd.argoproj.io/sync-wave: "-1"

Wave nhỏ hơn chạy trước. Trong repo:

Wave Application Vai trò
-1 banking-demo-namespace Namespace + Secret — chạy đầu tiên
0 banking-demo-postgres, banking-demo-redis Hạ tầng
1 banking-demo-kong API Gateway
2 auth, account, transfer, notification Microservices (có thể song song)
3 banking-demo-frontend Frontend
4 banking-demo-ingress Ingress

Khi bạn sync tất cả Application cùng lúc (vd argocd app sync -l app.kubernetes.io/name=banking-demo), ArgoCD sẽ tôn trọng thứ tự wave: wave -1 xong mới tới 0, 0 xong mới tới 1, …


Per-service: valueFiles và parameters

Mỗi Application per-service trỏ cùng path (phase2-helm-chart/banking-demo) nhưng chỉ bật đúng một thành phần, tắt hết phần còn lại để Helm chỉ render đúng Deployment/Service (và resource liên quan) của service đó.

Ví dụ auth-service:

source:
  path: phase2-helm-chart/banking-demo
  helm:
    releaseName: banking-demo-auth-service
    valueFiles:
      - charts/common/values.yaml
      - charts/auth-service/values.yaml
    parameters:
      - name: namespace.enabled
        value: "false"
      - name: secret.enabled
        value: "false"
      - name: postgres.enabled
        value: "false"
      - name: redis.enabled
        value: "false"
      - name: kong.enabled
        value: "false"
      - name: auth-service.enabled
        value: "true"
      - name: account-service.enabled
        value: "false"
      # ... tắt hết service khác, frontend, ingress

valueFiles đưa common + auth-service; parameters override *.enabled để chỉ có auth-service được render. Namespace và secret không tạo lại (đã có từ Application wave -1), tránh conflict và SharedResourceWarning.


AppProject: gom nhóm và giới hạn

AppProject dùng để:

  • Gom nhóm Application theo product/app (trong UI, RBAC).
  • Giới hạn repo và namespace mà Application trong project được phép dùng.

Ví dụ project.yaml:

apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
  name: banking-demo
  namespace: argocd
spec:
  description: "Banking Demo - Helm chart and per-service apps"
  sourceRepos:
    - https://github.com/kevinram164/banking-demo.git
  destinations:
    - namespace: banking
      server: https://kubernetes.default.svc
  clusterResourceWhitelist:
    - group: ""
      kind: Namespace
  namespaceResourceWhitelist:
    - group: ""
      kind: "*"
    - group: apps
      kind: "*"
    # ...

Application phải có spec.project: banking-demo và chỉ được dùng repo trong sourceRepos, deploy vào destination đã khai báo. Áp dụng Project trước khi tạo Application:

kubectl apply -f phase2-helm-chart/argocd/project.yaml -n argocd

Helm hooks và ArgoCD

Chart banking-demo có thể dùng Helm hooks (vd pre-install cho secret, postgres). Khi ArgoCD sync, nó thực chất chạy Helm (install/upgrade), nên hooks vẫn được thực thi theo thứ tự Helm. Lưu ý:

  • ArgoCD mặc định không “chờ” hook xong theo cách bạn mong đợi nếu sync nhiều resource cùng lúc; với per-service + sync waves, thứ tự đã được điều khiển (namespace → infra → app) nên thường đủ.
  • Nếu dùng hook có Job (vd migration), cần đảm bảo hook weight và wave để Job chạy đúng lúc; xem tài liệu ArgoCD về Helm hooks.

Trong repo, phần lớn thứ tự deploy được giải quyết bằng sync waves và bật/tắt component qua parameters, không phụ thuộc nặng vào hooks.


Thực hành nhanh: từ cài ArgoCD đến sync

1. Cài ArgoCD (nếu chưa có)

kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
kubectl wait --for=condition=Ready pods -l app.kubernetes.io/name=argocd-server -n argocd --timeout=300s

Lấy mật khẩu admin: kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d. Port-forward UI: kubectl port-forward svc/argocd-server -n argocd 8080:443, mở https://localhost:8080.

2. Sửa repo URL

Sửa repoURL (và nếu cần targetRevision) trong argocd/project.yaml và trong argocd/application.yaml hoặc từng file trong argocd/applications/ thành repo Git của bạn.

3. Deploy một Application (cách đơn giản)

kubectl apply -f phase2-helm-chart/argocd/project.yaml -n argocd
kubectl apply -f phase2-helm-chart/argocd/application.yaml -n argocd

Vào ArgoCD UI → Application banking-demoSync. Sau khi Synced & Healthy, kiểm tra: kubectl get pods -n banking.

4. Hoặc deploy per-service

kubectl apply -f phase2-helm-chart/argocd/project.yaml -n argocd
kubectl apply -f phase2-helm-chart/argocd/applications/ -n argocd
argocd app sync -l app.kubernetes.io/name=banking-demo

ArgoCD sẽ sync theo sync wave; đợi tất cả Synced rồi kiểm tra namespace banking.

5. Repo private

Nếu repo private: ArgoCD UI → Settings → Repositories → Connect Repo (URL + credential). Hoặc tạo Secret trong argocd chứa username/password hoặc SSH key và cấu hình theo tài liệu ArgoCD. Đảm bảo AppProject sourceRepos có repo đó.


Mapping nhanh: Helm tay vs ArgoCD

Helm tay (bài 4) ArgoCD
helm template ... -f charts/common/values.yaml -f ... ArgoCD đọc source.path + helm.valueFiles và render tương đương
helm install/upgrade Sync = ArgoCD apply kết quả render lên cluster
Đổi values rồi chạy lại helm upgrade Sửa values trong Git → Sync Application
Nhiều env = nhiều file values, gọi helm với -f khác nhau Nhiều Application (hoặc ApplicationSet) với valueFiles/parameters khác nhau

Lưu ý khi dùng

  • Mật khẩu: Không commit mật khẩu production vào Git. Có thể dùng ArgoCD Helm parameters trỏ tới Secret, hoặc External Secrets / Sealed Secrets.
  • Sync policy: Với production nhiều team, nên giữ sync thủ công hoặc auto với prune: false / selfHeal: false đến khi đã quen quy trình.
  • CreateNamespace: Chỉ cần một Application có CreateNamespace=true (trong repo là banking-demo-namespace); các Application khác không cần để tránh conflict.
  • Shared resource: Per-service dùng chung chart, mỗi app bật một phần; nhớ tắt namespace/secret ở mọi Application trừ namespace (tránh nhiều app cùng quản lý một Namespace/Secret).

Chi tiết troubleshooting (namespace stuck, postgres/redis không render, Payload Too Large khi xóa app…) xem trong repo: phase2-helm-chart/argocd/ARGOCD.md.


Tóm tắt

  • GitOps: Git là nguồn chân lý; ArgoCD đọc Git (chart + values) và đồng bộ lên cluster khi sync.
  • Application: Khai báo repo, path chart, valueFiles (và parameters); destination namespace; sync policy.
  • Hai cách: Một Application deploy cả chart (đơn giản) hoặc per-service Applications với sync waves (dễ quản lý từng phần).
  • ValueFiles: Merge theo thứ tự; có thể thêm file theo môi trường (staging/production) hoặc dùng ApplicationSet.
  • Sync policy: automated / prune / selfHeal tùy nhu cầu; CreateNamespace và ApplyOutOfSyncOnly hữu ích cho banking-demo.
  • AppProject: Gom nhóm và giới hạn repo/namespace cho Application.

Bài tiếp theo sẽ đi vào CI/CD: pipeline build image, push registry, và (tùy chọn) cập nhật Helm values hoặc trigger ArgoCD sync khi có tag/commit mới.


Bài tiếp theo

Bài 6: Monitoring và Auto Scale (Phase 3)

  • Prometheus, Grafana, Loki, Tempo
  • KEDA: scale theo Prometheus (RPS)
  • Load test (k6) kiểm chứng scale

Tags: #argocd #gitops #helm #kubernetes #devops #microservices


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.