iT邦幫忙

2026 iThome 鐵人賽

DAY 8
0
IT Operation

寫完微服務然後呢?走向平台工程的黃金路徑系列 第 8 篇

Day 08 - 用 Argo CD ApplicationSet 管理多個服務與環境

  • 分享至 

  • xImage
  •  

前篇的 Application 已經能把一個 Git 路徑同步到固定的叢集與 Namespace。這個做法從一個服務開始很直覺:todo-api 在 Dev 有一份 Application,到了 Staging 和 Production,就再各自建立一份。

當服務與環境數量增加時,這套做法的維護成本就會浮現。假設每個服務都有三個環境,十個服務就需要維護三十份 Application。它們大多只差服務名稱、Git 路徑和目的地,卻都要重複填寫 project、repository、同步政策與 finalizer。少改一份,或在其中一份寫錯 Namespace,都可能讓部署行為悄悄分岔。

Argo CD 的 ApplicationSet 用來管理這類有固定規則的重複。它先取得服務或環境的清單,再依 template 產生多個 Application,並持續讓產物與清單一致。

ApplicationSet 管理的是 Application

ApplicationSet 不會直接建立 Deployment 或 Service。它的 controller 先根據 generator 產生 child Application,再由每個 Application 各自讀取 Git、同步資源並評估健康狀態。

服務目錄或環境清單
        │
        ▼
ApplicationSet generator
        │
        ▼
多個 Argo CD Application
        │
        ▼
各 Application 同步 Kubernetes 資源

流程如下圖,Git Generator 和 List Generator 分別提供服務與環境的變數,ApplicationSet controller 再將這些變數套入 template,產生對應的 child Application。child Application 是這個流程的產物,不是另一份要手動維護的設定。

Git 與 List Generator 提供變數,ApplicationSet template 產生多個 child Application

舉例來說, todo-api-dev  不是要手動一份份維護的  Application ,而是  ApplicationSet  依照 template 自動產生的結果。就算你直接改了它的部署位置或同步設定,ApplicationSet controller 下一次執行  reconcile  時,還是會按照 template 的內容把它改回來。

所以,所有 Application 都共用的設定,要改  ApplicationSet ;
想新增、移除服務或環境,則修改 generator 讀取的服務目錄或環境清單。

Git Generator:以目錄結構列出要部署的服務

Day 04 使用 apps/<service>/overlays/<environment> 區分服務與環境。這個目錄結構除了整理 Kustomize 設定,也可以成為部署清單:只要某個 overlay 目錄符合約定,Git Generator 就能為它建立一個 Application。

以下範例假設設定 repository 具有這樣的目錄:

apps/
  todo-api/
    overlays/
      dev/
      staging/
  web/
    overlays/
      dev/
      staging/

directories.path 找出所有 overlay 目錄;template 則從路徑取出服務名稱與環境名稱,組成 Application 的名稱、來源路徑和 Namespace。

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: todo-applications
  namespace: argocd
spec:
  goTemplate: true
  generators:
    - git:
        repoURL: https://github.com/example/todo-platform-config.git
        revision: main
        directories:
          - path: apps/*/overlays/*
  template:
    metadata:
      name: '{{ index .path.segments 1 }}-{{ .path.basename }}'
    spec:
      project: todo
      source:
        repoURL: https://github.com/example/todo-platform-config.git
        targetRevision: main
        path: '{{ .path.path }}'
      destination:
        server: https://kubernetes.default.svc
        namespace: 'todo-{{ .path.basename }}'
      syncPolicy:
        automated:
          prune: true
          selfHeal: true

在上述 YAML 中,我們啟用了 goTemplate: true,這讓我們能使用 index 語法來精準抓取目錄層級。以 apps/todo-api/overlays/dev 這個路徑為例,Argo CD 會用斜線將其切分為陣列(索引從 0 開始計數):

  • {{ index .path.segments 0 }}:apps
  • {{ index .path.segments 1 }}:todo-api(取出服務名稱)
  • {{ index .path.segments 2 }}:overlays

此外,Argo CD 提供了 .path.basename 變數,它永遠代表路徑的最後一個資料夾,也就是 dev。

因此,透過 {{ index .path.segments 1 }}-{{ .path.basename }},我們就能自動且精準地將 Application 命名為 todo-api-dev,來源路徑指向該 overlay,目標 Namespace 則為 todo-dev。

這也表示目錄命名是一份合約。把 prod 改名為 production,不只是搬動資料夾;Application 名稱與 Namespace 都會跟著改變。開始讓 generator 依路徑推導設定前,先固定命名規則,並把目錄異動放進 code review。

List Generator:明確列出受控的部署目的地

Git 路徑很適合提供「有哪些服務設定」的資訊,但它不一定適合決定要部署到哪個叢集。多叢集情境中,cluster API server、region 與 Namespace 通常是平台需要明確控管的資料,而非讓任意資料夾名稱推導。

List Generator 可以將這些目的地直接列在 ApplicationSet 裡:

generators:
  - list:
      elements:
        - environment: dev
          cluster: https://kubernetes.default.svc
          namespace: todo-dev
        - environment: staging
          cluster: https://staging.example.internal
          namespace: todo-staging

template 可使用 {{ .environment }}、{{ .cluster }} 與 {{ .namespace }} 填入對應欄位。服務設定仍放在 Git;List Generator 只是將受審查的環境清單提供給 template。實務上若要將 Git 目錄(服務來源)與 List(環境目的地)交叉比對來產生 Application,會使用 Matrix Generator 將兩者組合,以確保產出的每一筆資料都有明確的來源與目的地。

目的地資料不能因為自動生成就放寬限制。Day 07 的 AppProject 仍應限制允許的 server、Namespace 與 Git repository。否則一筆環境清單的變更,就可能讓同一套設定被同步到不該操作的叢集。

劃清職責邊界:ApplicationSet 管派發,Kustomize 管內容

ApplicationSet 適合處理每個服務都遵循相同部署合約的情況,但不適合把所有差異塞進 template。不同服務的 rollout 策略、資料 migration 順序,或需要額外權限的工作負載,若在 template 內依賴大量的巢狀條件判斷(if-else)來處理特例,最後會很難預測一個目錄到底會產生什麼設定。

在設計時,我們應該明確劃分 ApplicationSet 與 Kustomize 的職責邊界:

ApplicationSet 負責「派發規則」:它只關心「哪些服務」要部署到「哪些環境」。例如:Git 的來源路徑在哪裡、目標的叢集與 Namespace 是什麼、以及 Argo CD 的同步政策(Sync Policy)。

Kustomize 負責「資源規格」:它關心的是「服務本身」長什麼樣子。例如:Deployment 的 Replicas 數量、要使用哪個 Image tag、特定環境的 ConfigMap 與 Secret、以及資源的 Limit。

一個簡單的判斷方式是:Reviewer 只看某個服務的 overlay 與環境資料,能不能立刻說出它會產生哪個 Application、讀取哪個路徑、部署到哪裡?若答案是否定的(例如還需要考量一堆 if-else 特例),就代表設計越界了。這時應該把專屬於該服務的差異(如特殊的 Volume 掛載或環境變數)退回 Kustomize overlay 去處理;若是派發邏輯真的不同,則應該拆分成另一個 ApplicationSet,或是先重新對齊團隊的部署合約。

結語

前面的 YAML 用來說明欄位關係,不能直接套用。導入時,應先在非正式環境檢查 controller 實際產生的 child Application,再啟用自動同步。

驗收時至少確認下列結果:

  • 新增一個符合規則的 apps/todo-api/overlays/staging 後,只產生 todo-api-staging。
  • 產生的 Application 指向預期的 Git 路徑、叢集與 Namespace。
  • 不符合目錄約定的路徑不會被納入。
  • 移除 overlay 前,先確認 prune 是否會刪除對應資源,以及這是否符合團隊預期。
  • 除錯提示:若套用後發現 Application 沒有如預期產生,可透過 kubectl describe applicationset <name> -n argocd 檢查 controller 的錯誤事件(Events),通常能快速找出 template 渲染失敗或 Git 路徑對不上的原因。

ApplicationSet 減少的是重複維護;服務同步到叢集後,團隊仍需要知道它是否正常運作、異常發生在哪裡。下一篇會從 Metrics、Logs 與 Traces 建立這條調查路徑。


上一篇
Day 07 - 用 Argo CD 將 Git 的 YAML 同步到 Kubernetes
下一篇
Day 09 - Metrics、Logs、Traces:可觀測性怎麼用
系列文
寫完微服務然後呢?走向平台工程的黃金路徑 共 15 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言