Blog chia sẻ về công nghệ ...
Published on

Triển khai GitOps và có cấu trúc với Kro, Kargo, Argo CD và RGD

Authors

🚀 From Kro RGD to Full GitOps: How I Built a Clean Deployment Flow with Argo CD

Nếu bạn từng phải sửa ba file YAML chỉ để đổi version Docker image, thì bài viết này chính là dành cho bạn.


📑 Mục lục

  1. Tại sao tôi cần RGD
  2. Giới thiệu Kro và RGD là gì
  3. Viết RGD đầu tiên
  4. Template hóa tài nguyên Kubernetes
  5. Tạo file instance.yaml
  6. Tích hợp với Argo CD và Kargo
  7. Vấn đề thực tế và cách tôi xử lý
  8. Vị trí của Kro trong kiến trúc GitOps
  9. Bonus: Setup theo môi trường
  10. Tiếp theo: Cấu trúc GitOps repo clean

🧩 Tại sao tôi cần RGD

Trước đây, tôi phải:

  • Sửa 3 file YAML để cập nhật một tag image.
  • Mỗi lần sửa lại phải mở PR, review, merge, Argo CD mới sync.

Tôi muốn một cách đơn giản hơn:

✅ Chỉ cần chỉnh 1 file, mọi thứ còn lại tự render.
✅ Không còn cảnh copy-paste cấu hình giữa các dự án.


🧠 Giới thiệu Kro và RGD là gì

Kro là một GitOps templating engine đơn giản nhưng mạnh mẽ.

Khác với Helm:

  • Không có values.yaml lồng nhau rối rắm.
  • Không có _helpers.tpl khó đọc.
  • Không cần đóng gói chart.

👉 Cốt lõi của Kro là ResourceGraphDefinition (RGD).
RGD định nghĩa:

  • Cấu trúc schema
  • Template tạo ra gì (Deployment, Service,...)
  • Giá trị lấy từ đâu (instance.yaml)

🛠 Viết RGD đầu tiên

Tôi bắt đầu với một service frontend đơn giản:

  • 1 ConfigMap (chứa API URL)
  • 1 Deployment (image, replicas)
  • 1 Service (port)

Schema mẫu:

spec:
  name: string | default=frontend
  namespace: string | default=develop
  values:
    configMap:
      data:
        API_HTTP_URL: string
        TIME_ZONE: string | default="XXX/XXX"
    deployment:
      image: string
      tag: string
      replicas: integer | default=1
    service:
      port: integer | default=3000
      targetPort: integer | default=3000

📄 Template hoá tài nguyên Kubernetes

Sau khi có schema, tôi định nghĩa các template mà nó sẽ sinh ra.

Ví dụ với Deployment:

- id: deploy
  template:
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: ${schema.spec.name}
      namespace: ${schema.spec.namespace}
    spec:
      replicas: ${schema.spec.values.deployment.replicas}
      template:
        spec:
          containers:
            - image: ${schema.spec.values.deployment.image}:${schema.spec.values.deployment.tag}

✅ Không có logic phức tạp.
✅ Không có templating kiểu Helm.
✅ Chỉ là tham chiếu trực tiếp đến schema.


📦 Tạo file instance.yaml

instance.yaml là nơi cung cấp giá trị thực tế để Kro render manifests.

apiVersion: kro.run/v1alpha1
kind: FrontendAppV2
metadata:
  name: wsp-frontend
  namespace: develop
spec:
  name: wsp-frontend
  namespace: develop
  values:
    configMap:
      data:
        API_HTTP_URL: https://example.com/api
        TIME_ZONE: Asia/Bangkok
    deployment:
      image: docker.io/wsp-frontend
      tag: "1.0.1"
      replicas: 1
    service:
      port: 3000
      targetPort: 3000

Tôi commit file này vào Git. Argo CD tự sync.


🔁 Tích hợp với Argo CD và Kargo

Workflow GitOps hoàn chỉnh:

  1. Push image mới lên registry
  2. Kargo detect → tạo Freight
  3. Stage thực hiện yaml-update lên instance.yaml
  4. Commit thay đổi vào Git
  5. Argo CD sync cluster
  6. Kro detect instance mới → apply

yaml-update snippet:

- key: spec.values.deployment.tag
  value: ${{ quote(imageFrom(vars.imageRepo, warehouse(vars.warehouseName)).Tag) }}

Tự động hoàn toàn từ image tag → cluster update.


💥 Vấn đề thực tế và cách tôi xử lý

1️⃣ Resource không apply, không báo lỗi
→ Do thiếu type trong schema.

2️⃣ Tag bị biến thành số (1.0.1 → 1)
→ Dùng quote() trong Kargo để ép về chuỗi.

3️⃣ Kro không apply vì không khác biệt
→ Log: Skipping update due to unchanged generation

4️⃣ Debug phải xem log controller
→ Kro không có giao diện UI mạnh, nên cần xem log để biết có apply hay không.


🧭 Vị trí của Kro trong kiến trúc GitOps

Docker push → Kargo → Git commit (instance.yaml) → Argo CD → Kro render → K8s apply

Kro cho phép:

  • Schema hoá rõ ràng
  • Template hoá chuẩn
  • Instance control qua Git

Tôi không cần Helm, không cần values.yaml, không cần overlay Kustomize.


🔎 Bonus: Setup theo môi trường

  • Mỗi env có 1 instance.yaml riêng
  • Dùng ApplicationSet cho Argo CD
  • develop/, staging/, production/ là các path Git tách biệt

🔜 Tiếp theo: Cấu trúc GitOps repo clean

Ở phần tiếp theo, tôi sẽ:

  • Chia sẻ layout Git cho GitOps (theo env + service)
  • Cách dùng ApplicationSet
  • Tạo automation pipeline từ image push → cluster sync