GitOps với ArgoCD: Hướng dẫn toàn tập từ cơ bản đến nâng cao

Tìm hiểu GitOps là gì và cách triển khai ArgoCD trên Kubernetes. Hướng dẫn chi tiết cài đặt, cấu hình Application, App of Apps, RBAC và Monitoring.

GitOps với ArgoCD: Hướng dẫn toàn tập từ cơ bản đến nâng cao

GitOps là gì?

GitOps là một mô hình vận hành trong đó trạng thái mong muốn của hạ tầng và ứng dụng được khai báo và lưu trữ trong Git. Một bộ điều khiển (controller) chạy trong cluster của bạn sẽ theo dõi Git repository và đảm bảo trạng thái thực tế khớp với trạng thái đã khai báo. Nếu có bất kỳ sự sai lệch (drift) nào, controller sẽ tự động điều chỉnh lại cho đúng.

Các nguyên tắc cốt lõi của GitOps bao gồm:

  • Cấu hình khai báo (Declarative configuration): Mọi thứ được mô tả dưới dạng YAML hoặc JSON manifests trong Git. Không có các script thao tác thủ công (imperative scripts) hay các bước làm bằng tay.
  • Git là nguồn chân lý duy nhất (Single source of truth): Repository Git là nơi duy nhất mọi thay đổi được thực hiện. Những gì có trong Git chính là những gì đang chạy trong cluster.
  • Đồng bộ hóa dựa trên cơ chế Pull (Pull-based reconciliation): Thay vì hệ thống CI đẩy (push) thẳng vào cluster, một controller bên trong cluster sẽ tự động kéo (pull) trạng thái mong muốn từ Git. Cách này bảo mật hơn vì thông tin xác thực của cluster không bao giờ lọt ra ngoài.
  • Đồng bộ hóa liên tục (Continuous reconciliation): Controller không chỉ áp dụng thay đổi một lần. Nó liên tục so sánh trạng thái thực tế với trạng thái mong muốn và tự động khắc phục mọi sự sai lệch.

Điều này hoàn toàn khác biệt với mô hình CI/CD truyền thống (dựa trên Push), nơi pipeline chạy kubectl apply sau khi build. Với Push-based CD, nếu ai đó thay đổi cấu hình trực tiếp trên cluster, hệ thống CI của bạn sẽ không hề hay biết. Với GitOps, controller phát hiện sự sai lệch và sửa chữa nó tự động.

# Push-based CI/CD (truyền thống):
Developer → Git push → CI builds → CI chạy kubectl apply → Cluster
                                    (CI cần có chứng chỉ của cluster)
                                    (Sai lệch cấu hình không bị phát hiện)

# Pull-based GitOps:
Developer → Git push → Controller phát hiện thay đổi → Controller apply → Cluster
                        (Controller nằm trong cluster, liên tục theo dõi Git)
                        (Sai lệch được phát hiện và khắc phục tự động)

Kiến trúc của ArgoCD

ArgoCD là một GitOps controller phổ biến nhất dành cho Kubernetes. Đây là một dự án graduated của CNCF với một kiến trúc được thiết kế rất chặt chẽ:

  • API Server: Máy chủ gRPC/REST cung cấp sức mạnh cho giao diện web (UI), CLI và các API tích hợp bên ngoài. Nó xử lý việc xác thực, phân quyền (RBAC) và cung cấp trạng thái của ứng dụng.
  • Repository Server: Thực hiện clone các Git repositories và tạo ra các Kubernetes manifests. Nó hỗ trợ YAML thuần túy, Kustomize, Helm, Jsonnet và các plugin tùy chỉnh.
  • Application Controller: Bộ não của ArgoCD. Nó theo dõi các tài nguyên Application, so sánh trạng thái mong muốn (từ Git) với trạng thái hiện tại (từ cluster) và thực hiện các thao tác đồng bộ (sync) khi có sự khác biệt.
  • Redis: Lớp bộ nhớ đệm (caching layer) dành cho repository server và application controller.
  • ApplicationSet Controller: Quản lý tài nguyên ApplicationSet - cho phép tạo và quản lý nhiều Application từ một định nghĩa duy nhất.

Vòng lặp reconciliation của ArgoCD (mặc định chạy mỗi 3 phút):

  1. Application Controller đọc Application CRD.
  2. Yêu cầu Repo Server lấy và render các manifests từ Git.
  3. Controller so sánh manifests đã render với trạng thái thực tế trên cluster.
  4. Nếu có sự khác biệt:
    • Nếu bật auto-sync: Controller tự động áp dụng các thay đổi.
    • Nếu không bật auto-sync: Controller đánh dấu ứng dụng là OutOfSync.
  5. Controller cập nhật trạng thái Application, chu kỳ lặp lại.

Hướng dẫn cài đặt ArgoCD

Cách cài đặt được khuyến nghị là sử dụng Helm. Bạn hãy tạo namespace và cài đặt bằng các lệnh sau:

kubectl create namespace argocd
helm repo add argo https://argoproj.github.io/argo-helm
helm repo update

Dưới đây là một file cấu hình values.yaml tham khảo cho môi trường production:

# argocd-values.yaml
configs:
  params:
    server.insecure: true
    timeout.reconciliation: 180s
  cm:
    statusbadge.enabled: "true"
    kustomize.buildOptions: "--enable-helm"

server:
  replicas: 2
  ingress:
    enabled: true
    ingressClassName: nginx
    hostname: argocd.example.com
    tls: true

controller:
  resources:
    requests:
      cpu: 250m
      memory: 512Mi
    limits:
      memory: 1Gi

repoServer:
  replicas: 2
  resources:
    requests:
      cpu: 100m
      memory: 256Mi
    limits:
      memory: 512Mi

Chạy lệnh cài đặt:

helm install argocd argo/argo-cd \
  --namespace argocd \
  --values argocd-values.yaml \
  --wait

# Lấy mật khẩu admin ban đầu
kubectl -n argocd get secret argocd-initial-admin-secret \
  -o jsonpath="{.data.password}" | base64 -d

# Đăng nhập và đổi mật khẩu
argocd login argocd.example.com --username admin --password <your-password>
argocd account update-password

Tìm hiểu về Application CRDs

Application CRD là thành phần cơ bản nhất trong ArgoCD. Nó xác định những gì cần triển khai, ở đâu, và làm thế nào để giữ cho hệ thống luôn đồng bộ:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: my-app
  namespace: argocd
  finalizers:
    - resources-finalizer.argocd.argoproj.io
spec:
  project: default
  source:
    repoURL: https://github.com/techcoban/my-app-manifests
    targetRevision: main
    path: overlays/production
  destination:
    server: https://kubernetes.default.svc
    namespace: my-app
  syncPolicy:
    automated:
      prune: true       # Xóa các resource không còn tồn tại trong Git
      selfHeal: true    # Tự động revert các thay đổi thủ công trên cluster
    syncOptions:
      - CreateNamespace=true
      - PruneLast=true
    retry:
      limit: 5
      backoff:
        duration: 5s
        factor: 2
        maxDuration: 3m
  ignoreDifferences:
    - group: apps
      kind: Deployment
      jsonPointers:
        - /spec/replicas   # Bỏ qua nếu có HPA đang quản lý số lượng replicas
  • source: Nơi chứa các manifests bao gồm repoURL, targetRevision (nhánh/tag), và path (thư mục trong repo).
  • destination: Nơi sẽ deploy lên với server là endpoint của Kubernetes API, và namespace là đích đến.
  • syncPolicy: Cách cấu hình đồng bộ. automated sẽ bật tính năng tự động đồng bộ (auto-sync), prune để dọn dẹp các tài nguyên đã bị xóa trên Git, selfHeal hoàn tác các thay đổi thủ công.
  • ignoreDifferences: Các trường cần bỏ qua khi so sánh (rất hữu ích với các trường được set tự động bởi cluster).

Mô hình App of Apps (Ứng dụng của các ứng dụng)

Khi bạn có nhiều ứng dụng, việc quản lý từng resource Application riêng lẻ sẽ trở nên tẻ nhạt và khó bảo trì. Mô hình App of Apps tạo ra một Application “cha” (parent) để quản lý các manifests của các Application “con” (child).

Cấu trúc Repository ví dụ:

gitops-repo/
├── apps/                          # Ứng dụng cha sẽ trỏ về đây
│   ├── my-app.yaml               # Các file manifests của ứng dụng con
│   ├── monitoring.yaml
│   ├── cert-manager.yaml
│   └── ingress-nginx.yaml
├── my-app/
│   ├── base/
│   └── overlays/
│       ├── staging/
│       └── production/
└── monitoring/

Application “cha” sẽ có cấu trúc như sau:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: app-of-apps
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/techcoban/gitops-repo
    targetRevision: main
    path: apps
  destination:
    server: https://kubernetes.default.svc
    namespace: argocd
  syncPolicy:
    automated:
      prune: true
      selfHeal: true

Các ứng dụng con sẽ sử dụng annotationssync-wave để kiểm soát thứ tự deploy. Các thành phần hạ tầng (infrastructure) thường nằm ở wave 0, còn các workload của ứng dụng nằm ở wave 2:

# apps/cert-manager.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: cert-manager
  namespace: argocd
  annotations:
    argocd.argoproj.io/sync-wave: "0"  # Triển khai phần hạ tầng trước
spec:
  project: default
  source:
    repoURL: https://charts.jetstack.io
    chart: cert-manager
    targetRevision: v1.16.3
    helm:
      releaseName: cert-manager
      values: |
        installCRDs: true
  destination:
    server: https://kubernetes.default.svc
    namespace: cert-manager
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
      - CreateNamespace=true

Chiến lược Đồng bộ (Sync strategies)

ArgoCD cung cấp quyền kiểm soát cực kỳ chi tiết về cách thức và thời điểm đồng bộ hóa (sync) diễn ra. Một mô hình phổ biến là dùng auto-sync cho môi trường stagingmanual (thủ công) cho môi trường production:

# Auto-sync: Các thay đổi được áp dụng tự động
syncPolicy:
  automated:
    prune: true      # Xóa các resource không còn trong Git
    selfHeal: true   # Hoàn tác các thay đổi bằng tay trên cluster

# Manual sync: Chỉ cần bỏ đi phần "automated"
syncPolicy:
  syncOptions:
    - CreateNamespace=true

Các chính sách xử lý retry khi gặp lỗi mạng tạm thời:

syncPolicy:
  retry:
    limit: 5
    backoff:
      duration: 5s
      factor: 2
      maxDuration: 3m

Các cửa sổ đồng bộ (Sync windows) hạn chế thời gian ArgoCD có thể thực hiện sync (rất hữu ích để “đóng băng” hệ thống vào ban đêm hoặc các dịp lễ Tết):

# Định nghĩa trong cấu hình AppProject spec
spec:
  syncWindows:
    - kind: allow
      schedule: "0 9 * * 1-5"   # T2 - T6 vào 9 giờ sáng
      duration: 8h
      applications: ["*"]
    - kind: deny
      schedule: "0 0 20 12 *"   # Block trong dịp lễ
      duration: 336h
      applications: ["*"]
      clusters: ["production"]

Custom Health checks (Kiểm tra sức khỏe hệ thống)

ArgoCD có sẵn các tính năng health check cho các tài nguyên mặc định của Kubernetes. Đối với các tài nguyên tùy chỉnh (Custom Resources - CRDs), bạn có thể viết các script health check bằng ngôn ngữ Lua.

Các trạng thái cơ bản bao gồm:

  • Healthy: Tài nguyên đang hoạt động bình thường.
  • Progressing: Chưa sẵn sàng nhưng đang trong tiến trình xử lý.
  • Degraded: Tài nguyên gặp lỗi.
  • Suspended: Tài nguyên đang bị tạm dừng.
  • Missing: Tài nguyên không tồn tại.

Ví dụ Custom health check cho cert-manager Certificate (cấu hình trong argocd-cm ConfigMap):

resource.customizations.health.cert-manager.io_Certificate: |
  hs = {}
  if obj.status ~= nil then
    if obj.status.conditions ~= nil then
      for i, condition in ipairs(obj.status.conditions) do
        if condition.type == "Ready" and condition.status == "False" then
          hs.status = "Degraded"
          hs.message = condition.message
          return hs
        end
        if condition.type == "Ready" and condition.status == "True" then
          hs.status = "Healthy"
          hs.message = condition.message
          return hs
        end
      end
    end
  end
  hs.status = "Progressing"
  hs.message = "Waiting for certificate"
  return hs

Các mô hình Rollback

Một trong những ưu điểm lớn nhất của GitOps là việc rollback đơn giản chỉ là thực hiện một thao tác git revert.

1. Cách chuẩn GitOps: revert commit trên Git

git revert HEAD --no-edit
git push
# ArgoCD sẽ tự động phát hiện sự thay đổi này và đồng bộ lại trạng thái cũ

2. Rollback sử dụng tính năng History của ArgoCD (Trường hợp khẩn cấp)

argocd app history my-app
argocd app rollback my-app 2
# LƯU Ý: Lệnh này KHÔNG revert code trên Git, nên nếu auto-sync đang bật nó sẽ tự động ghi đè lại.
# Bạn cần vô hiệu hóa tính năng auto-sync trước hoặc là đồng thời revert luôn trên Git.

Quản lý đa cụm (Multi-cluster) với ApplicationSets

ApplicationSets giúp bạn tạo ra nhiều Applications từ một template mẫu duy nhất bằng cách sử dụng các Generators (Bộ tạo). Thay vì phải tạo thủ công một Application cho từng cluster riêng biệt, bạn định nghĩa một template chung và một generator để sản sinh ra các biến thể tương ứng.

List generator: Cung cấp danh sách parameters cụ thể cho từng môi trường:

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: my-app
  namespace: argocd
spec:
  generators:
    - list:
        elements:
          - cluster: staging
            url: https://staging-api.example.com
          - cluster: production
            url: https://production-api.example.com
  template:
    metadata:
      name: "my-app-{{cluster}}"
    spec:
      project: default
      source:
        repoURL: https://github.com/techcoban/gitops-repo
        targetRevision: main
        path: "my-app/overlays/{{cluster}}"
      destination:
        server: "{{url}}"
        namespace: my-app
      syncPolicy:
        automated:
          prune: true
          selfHeal: true

Cluster generator: Tự động tạo ra các Applications cho mọi cluster thỏa mãn điều kiện matchLabels:

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: monitoring-stack
  namespace: argocd
spec:
  generators:
    - clusters:
        selector:
          matchLabels:
            environment: production
  template:
    metadata:
      name: "monitoring-{{name}}"
    spec:
      project: monitoring
      source:
        repoURL: https://github.com/techcoban/gitops-repo
        targetRevision: main
        path: monitoring
      destination:
        server: "{{server}}"
        namespace: monitoring

Git generator: Tạo Applications dựa trên cấu trúc thư mục (directory structure) hoặc theo file cấu hình:

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: team-apps
  namespace: argocd
spec:
  generators:
    - git:
        repoURL: https://github.com/techcoban/gitops-repo
        revision: main
        directories:
          - path: "teams/*/apps/*"
  template:
    metadata:
      name: "{{path.basename}}"
    spec:
      project: default
      source:
        repoURL: https://github.com/techcoban/gitops-repo
        targetRevision: main
        path: "{{path}}"
      destination:
        server: https://kubernetes.default.svc
        namespace: "{{path.basename}}"

Tích hợp Kustomize và Helm

ArgoCD hỗ trợ gốc (native support) cho cả KustomizeHelm. Nó sẽ tự động biên dịch (render) các manifests tại thời điểm sync, vì vậy bạn hoàn toàn không cần phải chạy lại các công cụ này trong các pipeline CI của mình nữa.

Đối với Kustomize, bạn chỉ cần trỏ thư mục source trong Application đến thư mục overlay mong muốn:

# overlays/production/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - ../../base
patches:
  - target:
      kind: Deployment
      name: my-app
    patch: |
      - op: replace
        path: /spec/replicas
        value: 3
images:
  - name: techcoban/my-app
    newTag: v1.2.3

Đối với các Helm charts từ một Helm chart repository:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: prometheus
  namespace: argocd
spec:
  source:
    repoURL: https://prometheus-community.github.io/helm-charts
    chart: kube-prometheus-stack
    targetRevision: 67.9.0
    helm:
      releaseName: prometheus
      values: |
        prometheus:
          prometheusSpec:
            retention: 30d
            storageSpec:
              volumeClaimTemplate:
                spec:
                  resources:
                    requests:
                      storage: 50Gi
        grafana:
          enabled: true
  destination:
    server: https://kubernetes.default.svc
    namespace: monitoring
  syncPolicy:
    syncOptions:
      - ServerSideApply=true

Phân quyền RBAC và SSO

Projects là cơ chế quan trọng nhất để giới hạn các quyền truy cập trong ArgoCD. Mỗi project sẽ xác định chính xác repository, cluster và namespace nào mà một ứng dụng được phép sử dụng:

apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
  name: payments-team
  namespace: argocd
spec:
  description: "Dự án của team Payments"
  sourceRepos:
    - "https://github.com/techcoban/payments-*"
  destinations:
    - server: https://kubernetes.default.svc
      namespace: "payments-*"
  namespaceResourceWhitelist:
    - group: "apps"
      kind: Deployment
    - group: ""
      kind: Service
    - group: ""
      kind: ConfigMap
    - group: ""
      kind: Secret
  roles:
    - name: developer
      policies:
        - p, proj:payments-team:developer, applications, get, payments-team/*, allow
        - p, proj:payments-team:developer, applications, sync, payments-team/*, allow
      groups:
        - payments-developers
    - name: admin
      policies:
        - p, proj:payments-team:admin, applications, *, payments-team/*, allow
      groups:
        - payments-admins

Để thiết lập SSO với OIDC:

# Trong file argocd-cm ConfigMap
oidc.config: |
  name: Keycloak
  issuer: https://keycloak.example.com/realms/engineering
  clientID: argocd
  clientSecret: $oidc.keycloak.clientSecret
  requestedScopes: ["openid", "profile", "email", "groups"]

# Trong file argocd-rbac-cm ConfigMap
policy.default: role:readonly
policy.csv: |
  g, platform-admins, role:admin
  g, payments-developers, proj:payments-team:developer
  p, role:readonly, applications, get, */*, allow

Thiết lập Notifications

ArgoCD Notifications gửi các thông báo hoặc cảnh báo cho hệ thống dựa trên các sự kiện sync. Tính năng này đã được tích hợp sẵn mặc định trong bản Helm chart kể từ ArgoCD bản 2.6 trở lên.

# argocd-notifications-cm ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-notifications-cm
  namespace: argocd
data:
  service.slack: |
    token: $slack-token

  template.app-sync-succeeded: |
    slack:
      attachments: |
        [{"color": "#18be52", "title": "{{.app.metadata.name}} đã sync thành công!",
          "fields": [
            {"title": "Revision", "value": "{{.app.status.sync.revision}}", "short": true},
            {"title": "Namespace", "value": "{{.app.spec.destination.namespace}}", "short": true}
          ]}]

  template.app-sync-failed: |
    slack:
      attachments: |
        [{"color": "#E96D76", "title": "{{.app.metadata.name}} sync THẤT BẠI",
          "fields": [
            {"title": "Error", "value": "{{range .app.status.conditions}}{{.message}}{{end}}"}
          ]}]

  trigger.on-sync-succeeded: |
    - when: app.status.operationState.phase in ['Succeeded']
      send: [app-sync-succeeded]
  trigger.on-sync-failed: |
    - when: app.status.operationState.phase in ['Error', 'Failed']
      send: [app-sync-failed]

Để đăng ký nhận thông báo cụ thể cho một ứng dụng, bạn thêm cấu hình annotations:

metadata:
  annotations:
    notifications.argoproj.io/subscribe.on-sync-succeeded.slack: deployments
    notifications.argoproj.io/subscribe.on-sync-failed.slack: deployments-alerts

Theo dõi hệ thống (Monitoring) nội bộ của ArgoCD

ArgoCD public sẵn các số liệu Prometheus (Prometheus metrics) ra ngoài (out-of-the-box). Dưới đây là các metrics quan trọng nhất mà bạn nên theo dõi:

  • argocd_app_info: Cung cấp trạng thái sync (đồng bộ) và health (sức khỏe) cho từng ứng dụng.
  • argocd_app_sync_total: Tổng số lượt sync operations.
  • argocd_app_reconcile_bucket: Theo dõi thời gian xử lý quá trình reconciliation.
  • argocd_git_request_total: Tổng số lượt Git requests (Nếu có lỗi nghĩa là ArgoCD không truy cập được vào Git repository của bạn).
  • argocd_cluster_api_resource_objects: Theo dõi số object API trên mỗi cluster (Hữu ích khi bạn lên kế hoạch sử dụng memory).

Ví dụ tạo một file rule cảnh báo dựa trên metrics:

apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: argocd-alerts
  namespace: monitoring
spec:
  groups:
    - name: argocd.rules
      rules:
        - alert: ArgoCDAppOutOfSync
          expr: argocd_app_info{sync_status="OutOfSync"} == 1
          for: 30m
          labels:
            severity: warning
          annotations:
            summary: "ArgoCD app {{ $labels.name }} bị mất đồng bộ (out of sync) quá 30 phút!"

        - alert: ArgoCDAppUnhealthy
          expr: argocd_app_info{health_status!~"Healthy|Progressing"} == 1
          for: 15m
          labels:
            severity: critical
          annotations:
            summary: "ArgoCD app {{ $labels.name }} đang ở trạng thái {{ $labels.health_status }}"

        - alert: ArgoCDSyncFailing
          expr: increase(argocd_app_sync_total{phase!="Succeeded"}[1h]) > 3
          labels:
            severity: critical
          annotations:
            summary: "Có nhiều hơn 3 lượt sync thất bại trong vòng 1 giờ cho ứng dụng {{ $labels.name }}"

        - alert: ArgoCDGitFetchErrors
          expr: increase(argocd_git_request_total{request_type="fetch", result="error"}[10m]) > 5
          labels:
            severity: warning
          annotations:
            summary: "ArgoCD không thể fetch source code từ các Git repositories"

Bạn cũng đừng quên thiết lập cho Prometheus thu thập (scrape) metrics bằng một ServiceMonitor:

apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: argocd-metrics
  namespace: monitoring
spec:
  selector:
    matchLabels:
      app.kubernetes.io/part-of: argocd
  namespaceSelector:
    matchNames: [argocd]
  endpoints:
    - port: metrics
      interval: 30s

Lời kết

GitOps với ArgoCD cung cấp cho bạn một luồng quy trình triển khai có khả năng kiểm soát, có thể lặp lại chính xác và hoàn toàn có thể tự phục hồi. Bằng cách coi Git là Nguồn chân lý duy nhất và cho phép controller của hệ thống tự động quá trình reconciliation, bạn đã loại bỏ đi toàn bộ các nguy cơ liên quan đến việc sai lệch cấu hình và các bước deploy thủ công rườm rà.

Sự kết hợp hoàn hảo giữa Application CRDs, mô hình App of Apps, ApplicationSets và khả năng phân quyền RBAC tuyệt vời của ArgoCD tạo nên một nền tảng vững chắc để giúp bạn quản lý tất cả, từ việc làm chủ một cụm (cluster) Kubernetes đơn lẻ cho đến cả một hạm đội các clusters trong nhiều môi trường khác nhau. Hy vọng bài viết này mang lại cho bạn những kiến thức bổ ích. Chúc các bạn thực hành thành công!

Bình luận

Bài viết liên quan