ArgoCD ApplicationSet — dziesiątki aplikacji z jednej definicji

W tym artykule przyjrzymy się ApplicationSet — kontrolerowi, który rozwiązuje problem znany każdemu, kto zarządza większą liczbą aplikacji w ArgoCD: mnożące się, niemal identyczne manifesty Application. Jest to naturalna kontynuacja poprzednich artykułów z tej serii: o strategiach multi-repo, zarządzaniu aplikacjami z wielu klastrów oraz ArgoCD Notifications.

Zagadnienia omawiane:

  • Czym jest ApplicationSet i jak działa (generator + szablon),
  • Przegląd dostępnych generatorów,
  • Konfiguracja prostego ApplicationSet krok po kroku,
  • Praktyczne przykłady: generator List (wiele instancji tej samej usługi) i generator Git (folder = aplikacja),
  • Przypadek użycia: dynamiczne środowiska deweloperskie tworzone przez agentów AI,
  • Nowości: templatePatch oraz Progressive Syncs (beta od Argo CD 3.3),
  • Dobre praktyki.

ArgoCD Notifications – Wprowadzenie

A więc zaczynamy…

ArgoCD ApplicationSet — Wprowadzenie

W klasycznym podejściu każda wdrażana usługa to osobny manifest Application. Przy jednej czy dwóch aplikacjach nie stanowi to problemu. Schody zaczynają się, gdy ta sama usługa ma trafić na kilka środowisk, do kilku klientów albo na kilka klastrów. Cztery środowiska i sześć usług to już dwadzieścia cztery niemal identyczne YAML-e, różniące się namespace’em, ścieżką w repozytorium i adresem klastra. Każda zmiana w polityce synchronizacji oznacza edycję wszystkich plików – a to prosta droga do literówek i rozjazdów konfiguracji.

ApplicationSet rozwiązuje ten problem na poziomie deklaratywnym. Jest to kontroler (i CRD), który na podstawie jednej definicji sam generuje manifesty Application. Projekt zaczynał jako osobne repozytorium w argoproj-labs, natomiast od wersji 2.3 jest standardową częścią instalacji ArgoCD — nie trzeba instalować niczego dodatkowego.

Mechanizm działania sprowadza się do dwóch elementów:

  • generator — produkuje zestawy parametrów (np. lista środowisk, foldery w repozytorium Git, klastry zarejestrowane w ArgoCD),
  • template — szablon manifestu Application, w którym parametry z generatora podstawiane są w miejsca oznaczone {{...}}.

Kontroler utrzymuje zbiór aplikacji zgodny z wynikiem generatorów — część źródeł obserwuje na bieżąco, a inne (np. repozytoria Git) odpytuje cyklicznie, do czego wrócimy. Istotne jest to, że działa to w obie strony: pojawienie się nowego zestawu parametrów (np. folderu w repo) tworzy obiekt Application, a jego zniknięcie powoduje, że ApplicationSet domyślnie usuwa wygenerowaną aplikację. Zasoby wdrożone przez taką aplikację kasuje wtedy finalizer ArgoCD — nie prune z syncPolicy, co bywa mylone; jeżeli chcemy je zachować, ustawiamy preserveResourcesOnDeletion: true (dokumentacja usuwania aplikacji). Sam kontroler ApplicationSet zarządza wyłącznie obiektami Application — wdrażaniem ich zasobów na klastry zajmuje się, jak zawsze, ArgoCD. ApplicationSet świetnie uzupełnia też znany wzorzec App of Apps— tam aplikacje potomne są jawnymi manifestami w repozytorium, tutaj wynikają z danych generatora.

ArgoCD ApplicationSet – Generatory

Aktualnie dostępnych jest dziewięć generatorów:

  • List — statyczna lista elementów klucz/wartość zdefiniowana wprost w manifeście,
  • Cluster — parametry na podstawie klastrów zarejestrowanych w ArgoCD (automatycznie reaguje na dodanie/usunięcie klastra),
  • Git — parametry na podstawie folderów lub plików (JSON/YAML) w repozytorium Git,
  • Matrix — iloczyn kartezjański parametrów dwóch generatorów (np. każda aplikacja × każdy klaster),
  • Merge — scalanie parametrów kilku generatorów po zdefiniowanych mergeKeys; kolejne generatory nadpisują wartości generatora bazowego,
  • SCM Provider — automatyczne wykrywanie repozytoriów w organizacji (GitHub, GitLab itd.),
  • Pull Request — aplikacje generowane dla otwartych pull requestów (środowiska preview),
  • Cluster Decision Resource — wybór klastrów na podstawie zewnętrznego custom resource,
  • Plugin — parametry z własnego serwisu HTTP, gdy żaden z powyższych nie wystarcza.

W praktyce zdecydowaną większość potrzeb pokrywają trzy pierwsze — i na nich się skupimy. Warto zaznaczyć, że wyniki każdego generatora można dodatkowo filtrować selektorami (post selector).

ArgoCD ApplicationSet – konfiguracja krok po kroku

Zanim przejdziemy do realnych scenariuszy, skonfigurujmy najprostszy możliwy ApplicationSet od zera — na przykładzie klasycznego guestbooka z publicznego repozytorium Argo.

Krok I. Weryfikacja kontrolera

ApplicationSet jest częścią standardowej instalacji ArgoCD, więc jedyne, co musimy zrobić, to upewnić się, że kontroler działa, a CRD jest zarejestrowane:

kubectl get deployment argocd-applicationset-controller -n argocd

kubectl get crd applicationsets.argoproj.io

Jeżeli oba polecenia zwracają zasoby — możemy działać. W przeciwnym razie warto zaktualizować instalację ArgoCD do aktualnej wersji.

Krok II. Definicja ApplicationSet

Tworzymy plik guestbook-appset.yaml z generatorem List i dwoma środowiskami:

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: guestbook
  namespace: argocd
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
    - list:
        elements:
          - env: dev
          - env: prod
  template:
    metadata:
      name: 'guestbook-{{.env}}'
    spec:
      project: default
      source:
        repoURL: <https://github.com/argoproj/argocd-example-apps.git>
        targetRevision: HEAD
        path: guestbook
      destination:
        server: <https://kubernetes.default.svc>
        namespace: 'guestbook-{{.env}}'
      syncPolicy:
        automated:
          prune: true
          selfHeal: true
        syncOptions:
          - CreateNamespace=true

Szablon wygeneruje dwie aplikacje — guestbook-dev i guestbook-prod — różniące się wyłącznie namespace’em. W realnym projekcie w tym miejscu wskażesz własne repozytorium; jeżeli jest prywatne, najpierw dodaj je w ArgoCD (opisywałem to w artykule o multi-repo).

Krok III. Wdrożenie

kubectl apply -n argocd -f guestbook-appset.yaml

Należy pamiętać, że domyślnie manifest ApplicationSet musi trafić do namespace, w którym działa ArgoCD (zwykle argocd). Od wersji 2.8 istnieje funkcja beta ApplicationSet w dowolnym namespace — wymaga jednak jawnej konfiguracji applicationsetcontroller.namespaces, włączonego „Applications in any namespace” i przemyślanego RBAC. Alternatywnie możemy użyć CLI: argocd appset create guestbook-appset.yaml — z flagą –-dry-run zobaczymy listę aplikacji, które powstaną, jeszcze przed ich utworzeniem.

Krok IV. Weryfikacja

kubectl get applicationsets -n argocd

kubectl get applications -n argocd

Po zakończeniu pierwszej synchronizacji drugie polecenie pokaże dwie aplikacje:

NAME             SYNC STATUS   HEALTH STATUS

guestbook-dev    Synced        Healthy

guestbook-prod   Synced        Healthy

Te same aplikacje pojawią się w UI ArgoCD — dzięki automated w syncPolicy zsynchronizują się bez naszego udziału. Jeżeli aplikacje się nie wygenerowały, w pierwszej kolejności sprawdzamy status i logi kontrolera:

kubectl describe applicationset guestbook -n argocd

kubectl logs deployment/argocd-applicationset-controller -n argocd

Najczęstsze przyczyny to literówka w nazwie parametru (przy missingkey=error zobaczymy ją wprost w warunkach statusu) oraz brak dostępu do repozytorium.

Krok V. Test cyklu życia

Na koniec najważniejsza próba — dopiszmy trzecie środowisko do listy:

- env: staging

Po kubectl apply niemal natychmiast pojawi się aplikacja guestbook-staging — przy generatorze List reakcja jest natychmiastowa, bo zmieniamy sam manifest ApplicationSet (generatory sięgające do zewnętrznych źródeł, jak Git, mają swój interwał odpytywania). Gdy usuniemy ten wpis i zaaplikujemy manifest ponownie — ApplicationSet usunie aplikację, a finalizer ArgoCD skasuje jej zasoby. Dokładnie tak ApplicationSet zarządza pełnym cyklem życia aplikacji i właśnie ta właściwość napędza wszystkie scenariusze, które omówimy dalej.

ArgoCD ApplicationSet – Przykład I: generator List

Zacznijmy od scenariusza, który znam z własnego podwórka. W jednym z moich projektów telekomunikacyjnych ta sama platforma obsługuje dwie marki operatora — każda z nich ma produkcję na współdzielonym klastrze w chmurze oraz środowisko deweloperskie na klastrze lokalnym. Cztery instancje tej samej aplikacji, różniące się namespace’em, klastrem docelowym i ścieżką konfiguracji w repozytorium.

Zamiast czterech manifestów Application wystarczy jeden ApplicationSet:

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: tele
  namespace: argocd
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
    - list:
        elements:
          - cluster: marka-a-prod
            server: '<https://prod.k8s.example.com>'
            namespace: tele-marka-a-prod
          - cluster: marka-b-prod
            server: '<https://prod.k8s.example.com>'
            namespace: tele-marka-b-prod
          - cluster: marka-a-dev
            server: '<https://kubernetes.default.svc>'
            namespace: tele-marka-a-dev
          - cluster: marka-b-dev
            server: '<https://kubernetes.default.svc>'
            namespace: tele-marka-b-dev
  template:
    metadata:
      name: 'tele-{{.cluster}}'
    spec:
      project: default
      source:
        repoURL: <https://github.com/twoja-organizacja/tele-deploy>
        targetRevision: HEAD
        path: 'envs/{{.cluster}}'
      destination:
        server: '{{.server}}'
        namespace: '{{.namespace}}'
      syncPolicy:
        automated:
          prune: true
          selfHeal: true
        syncOptions:
          - CreateNamespace=true

Kilka rzeczy wartych omówienia:

  • goTemplate: true włącza składnię szablonów Go (stąd {{.cluster}} zamiast {{cluster}}). Daje dostęp do funkcji sprig, np. lower i trunc (ze względów bezpieczeństwa wyłączone są env, expandenv i getHostByName), do dodatkowych funkcji ApplicationSet — normalize i slugify — oraz do warunków if z języka szablonów Go. Przyda się nam to później.
  • goTemplateOptions: ["missingkey=error"] to opcja, którą ustawiam zawsze. Jeżeli w szablonie odwołamy się do parametru, którego generator nie dostarczył, renderowanie zakończy się błędem zamiast po cichu podstawić pustą wartość.
  • każdy element listy staje się osobną aplikacją: tele-marka-a-prod, tele-marka-b-prod itd.,
  • konfiguracja środowisk trzymana jest w jednym repozytorium w podziale na katalogi envs/<nazwa> — dokładnie w duchu strategii opisanych w artykule o multi-repo.

Warto zaznaczyć, że wartość server musi dokładnie odpowiadać adresowi klastra zarejestrowanego w ArgoCD — często czytelniejszą alternatywą jest wskazywanie klastrów po nazwie polem destination.name.

Dzięki temu możemy dodać kolejną markę operatora jednym wpisem na liście. Onboarding nowej instancji to pull request zmieniający kilka linii, a nie kopiowanie całego manifestu.

ArgoCD ApplicationSet – Przykład II: generator Git (folder = aplikacja)

Generator List ma jedną wadę: listę trzeba utrzymywać ręcznie. Kolejny poziom automatyzacji to generator Git, w którym źródłem prawdy o tym, co ma istnieć, jest struktura repozytorium.

W moim scenariuszu użycia utrzymuję kilkanaście portali muzealnych. Każdy portal to katalog sites/<nazwa> w repozytorium wdrożeniowym, zawierający komplet manifestów. ApplicationSet skanuje te katalogi i dla każdego z nich wystawia aplikację:

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: sites
  namespace: argocd
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
    - git:
        repoURL: <https://github.com/twoja-organizacja/sites-deploy.git>
        revision: main
        directories:
          - path: sites/*
          - path: sites/_example
            exclude: true
  template:
    metadata:
      name: 'site-{{.path.basename}}'
      annotations:
        notifications.argoproj.io/subscribe.on-health-degraded.make-webhook: ""
        notifications.argoproj.io/subscribe.sync-operation-change.make-webhook: ""
    spec:
      project: default
      source:
        repoURL: <https://github.com/twoja-organizacja/sites-deploy.git>
        targetRevision: main
        path: '{{.path.path}}'
      destination:
        server: <https://kubernetes.default.svc>
        namespace: '{{.path.basename}}'
      syncPolicy:
        automated:
          prune: true
          selfHeal: true
        syncOptions:
          - CreateNamespace=true

Jak widzimy, generator Git dostarcza parametry ścieżkowe: {{.path.path}} to pełna ścieżka katalogu (trafia do source.path), a {{.path.basename}} to nazwa samego folderu — używam jej zarówno w nazwie aplikacji, jak i namespace. Dobrą praktyką jest trzymanie w repozytorium katalogu wzorcowego (u mnie sites/_example) i jawne wykluczenie go regułą exclude: true — reguły wykluczające mają priorytet nad włączającymi.

Uruchomienie portalu dla nowego klienta sprowadza się do skopiowania _example, dostosowania wartości i merge do main. Nikt nie dotyka konfiguracji ArgoCD. Nowy folder nie pojawi się jednak w ArgoCD w tej samej sekundzie — generator Git odpytuje repozytorium domyślnie co 3 minuty (parametr requeueAfterSeconds); szybszą reakcję zapewni webhook ApplicationSet. Warto też zwrócić uwagę na adnotacje notifications.argoproj.io/... w szablonie — subskrypcje powiadomień (opisane szerzej w artykule o ArgoCD Notifications) dziedziczy automatycznie każda wygenerowana aplikacja, więc status zdrowia każdego portalu od razu trafia na webhook. Warunkiem jest oczywiście wcześniejsze zdefiniowanie użytych triggerów i usług w argocd-notifications-cm.

Przypadek użycia: środowiska deweloperskie tworzone przez agentów AI

Najciekawsze zastosowanie ApplicationSet w moich projektach pojawiło się jednak przy automatyzacji pracy z agentami AI. Problem polegał na tym, że agent pracujący nad zadaniem potrzebuje własnego, odizolowanego środowiska w klastrze — a środowiska te powstają i znikają wielokrotnie w ciągu dnia, więc ręczne zarządzanie nimi nie wchodzi w grę.

Rozwiązanie okazało się zaskakująco proste. Pipeline (GitHub Actions), który uruchamia agenta do zadania FRA-201, commituje do repozytorium folder apps/FRA-201/ z manifestami środowiska. Resztą zajmuje się ApplicationSet:

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: dev-containers
  namespace: argocd
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
    - git:
        repoURL: <https://github.com/twoja-organizacja/dev-environments.git>
        revision: main
        directories:
          - path: apps/*
          - path: apps/_example
            exclude: true
  template:
    metadata:
      # path.basename = "FRA-201"; normalize sprowadza wartość do postaci
      # dozwolonej w metadata.name aplikacji → dev-fra-201
      name: 'dev-{{.path.basename | normalize}}'
    spec:
      project: default
      source:
        repoURL: <https://github.com/twoja-organizacja/dev-environments.git>
        targetRevision: main
        path: '{{.path.path}}'
      destination:
        server: <https://kubernetes.default.svc>
        namespace: dev-containers
      syncPolicy:
        automated:
          prune: true      # podczas sync usuwa zasoby wykasowane z repo
          selfHeal: true   # revert ręcznego driftu do stanu z Git
        syncOptions:
          - CreateNamespace=false   # namespace tworzony raz, ręcznie (sekrety + certyfikat)
          - ApplyOutOfSyncOnly=true

Po wprowadzeniu tego mechanizmu proces jest w pełni zautomatyzowany: commit folderu tworzy środowisko dev-fra-201(Deployment, Service, Ingress), a workflow sprzątający po zamknięciu zadania po prostu usuwa folder. Parametr znika wtedy z wyniku generatora, ApplicationSet usuwa obiekt Application, a jego zasoby sprząta finalizer ArgoCD. Ustawiony w syncPolicy prune działa na innym, niższym poziomie — usuwa pojedyncze zasoby wykasowane z repozytorium podczas synchronizacji wciąż istniejącej aplikacji. Cykl życia środowiska jest w stu procentach opisany w Git, zgodnie z ideą GitOps.

Dwa detale z tego przykładu, o których warto pamiętać:

  • funkcja normalize (dostępna dzięki goTemplate) sprowadza wartość do postaci dozwolonej w metadata.name aplikacji: małe litery, znaki alfanumeryczne oraz – i ., maksymalnie 253 znaki. Samo lower rozwiązuje wyłącznie problem wielkich liter — nie poradzi sobie np. z podkreśleniem w nazwie folderu; alternatywą jest slugify z inteligentnym skracaniem,
  • CreateNamespace=false to świadoma decyzja: wspólny namespace przygotowuje raz administrator (wraz z sekretami i certyfikatami), a dynamiczne aplikacje tylko z niego korzystają.

Ten sam wzorzec realizuje zresztą dedykowany generator Pull Request — potrafi tworzyć środowiska preview dla każdego otwartego PR-a i usuwać je po merge, bez commitowania folderów.

ArgoCD ApplicationSet – wiele klastrów: generatory Cluster i Matrix

W artykule o zarządzaniu wieloma klastrami pokazywałem, jak zarejestrować dodatkowe klastry w jednej instancji ArgoCD. ApplicationSet domyka ten temat: generator Cluster tworzy parametry ({{.name}}, {{.server}}) dla każdego zarejestrowanego klastra, więc wdrożenie usługi „wszędzie” wygląda tak:

spec:
  goTemplate: true
  generators:
    - clusters: {}   # wszystkie klastry zarejestrowane w ArgoCD
  template:
    metadata:
      name: '{{.name | normalize}}-monitoring'
    spec:
      project: default
      source:
        repoURL: <https://github.com/twoja-organizacja/platform-config.git>
        targetRevision: HEAD
        path: monitoring
      destination:
        server: '{{.server}}'
        namespace: monitoring

Rejestracja nowego klastra (argocd cluster add) automatycznie wywołuje wdrożenie — bez żadnej zmiany w konfiguracji. Klastry można też filtrować selektorem po etykietach (np. tylko env: prod).

Prawdziwa siła pojawia się w połączeniu z generatorem Matrix, który łączy parametry dwóch generatorów. Klasyczny scenariusz: każdy dodatek platformowy (folder w repo) × każdy klaster:

spec:
  generators:
    - matrix:
        generators:
          - git:
              repoURL: <https://github.com/twoja-organizacja/cluster-addons.git>
              revision: HEAD
              directories:
                - path: addons/*
          - clusters:
              selector:
                matchLabels:
                  argocd.argoproj.io/secret-type: cluster

Trzy dodatki i cztery klastry dają dwanaście aplikacji z jednej definicji. Drobna uwaga praktyczna: selektor po etykiecie argocd.argoproj.io/secret-type: cluster obejmie klastry reprezentowane sekretami — lokalny klaster in-cluster domyślnie takiego sekretu nie ma. Należy pamiętać, że liczba wygenerowanych aplikacji rośnie tu multiplikatywnie — warto kontrolować ją selektorami, zanim kontroler wystawi nam kilkaset aplikacji.

ArgoCD ApplicationSet – nowości, które warto znać

Ekosystem ApplicationSet rozwija się bardzo dynamicznie. Poniżej funkcjonalności, które w ostatnich wydaniach ArgoCD realnie zmieniają sposób pracy.

templatePatch — szablon poza ograniczeniami stringów

Klasyczny template pozwala podstawiać parametry wyłącznie w polach tekstowych. Pole templatePatch (dostępne od ArgoCD 2.10) zdejmuje to ograniczenie — możemy szablonować całe fragmenty YAML, w tym pola logiczne, listy i obiekty, a także stosować warunki:

spec:
  goTemplate: true
  # zakładamy, że generator dostarcza m.in. parametr "env"
  templatePatch: |
    spec:
      syncPolicy:
        {{- if eq .env "dev" }}
        automated:
          prune: true
          selfHeal: true
        {{- end }}

W powyższym przykładzie automatyczna synchronizacja włączana jest tylko dla środowisk deweloperskich — produkcja synchronizowana jest manualnie. Ta sama technika pozwala warunkowo dodawać komponenty Kustomize czy listy plików wartości Helm per środowisko.

Należy pamiętać, że templatePatch jest nakładany jako patch na wyrenderowany wcześniej szablon: pusty obiekt w gałęzi warunku może wyczyścić istniejące pola aplikacji, a listy są zastępowane w całości, nie scalane element po elemencie. Wymaga też goTemplate: true i nie pozwala modyfikować spec.project (ze względów bezpieczeństwa). Rozszerzenie tematu znajdziesz w dokumentacji szablonów ApplicationSet.

Progressive Syncs — kontrolowane wdrażanie falami (beta od 3.3)

Do niedawna ApplicationSet aktualizował wszystkie wygenerowane aplikacje naraz. Przy kilkudziesięciu instancjach produkcyjnych to spore ryzyko — błędna zmiana trafia wszędzie jednocześnie. Progressive Syncs — rozwijane wcześniej jako funkcja eksperymentalna, a od ArgoCD 3.3 (luty 2026) dostępne w statusie beta — wprowadzają strategię RollingSync: aplikacje synchronizowane są etapami, a kolejny etap rusza dopiero, gdy poprzedni jest zdrowy:

spec:
  strategy:
    type: RollingSync
    rollingSync:
      steps:
        - matchExpressions:
            - key: envLabel
              operator: In
              values:
                - env-dev
        - matchExpressions:
            - key: envLabel
              operator: In
              values:
                - env-prod
          maxUpdate: 25%   # maksymalnie 25% aplikacji prod naraz

Etapy dopasowują aplikacje po etykietach nadanych w szablonie, a maxUpdate ogranicza liczbę równocześnie synchronizowanych aplikacji w ramach etapu. Funkcja wymaga jawnego włączenia — np. applicationsetcontroller.enable.progressive.syncs: "true" w ConfigMap argocd-cmd-params-cm — a po jej aktywacji kontroler przejmuje kontrolę nad synchronizacją i wyłącza autosync na wygenerowanych aplikacjach. Aplikacje, które nie pasują do żadnego etapu, nie będą synchronizowane automatycznie — o czym łatwo się boleśnie przekonać. Pełny opis strategii znajdziesz w dokumentacji Progressive Syncs.

Mechanizmy kontroli i inne zmiany warte uwagi

  • kontrola nad wygenerowanymi aplikacjami (mechanizmy dostępne od dawna, a wciąż zaskakująco mało znane) — polityka applicationsSync (domyślne sync oraz create-only, create-update, create-delete) i pola preservedFields oraz ignoreApplicationDifferences pozwalają dopuścić kontrolowane, ręczne różnice w wygenerowanych aplikacjach (np. tymczasowe wyłączenie autosync podczas incydentu). Dwa zastrzeżenia: polityki create-* nie chronią aplikacji przy kasowaniu całego ApplicationSet (zadziała mechanizm ownerReferences), a zignorowana różnica nie jest trwałą „pauzą” — aktualizacja szablonu może przywrócić wartości. Szczegóły: Controlling Resource Modification,
  • wydajność — ArgoCD 3.3 dodał endpointy pprof dla kontrolera ApplicationSet, co ułatwia diagnozowanie problemów wydajnościowych przy setkach aplikacji; zoptymalizowano też renderowanie szablonów — nowości w 3.3 (upgrade notes),
  • UI — w 3.3 dodano warstwę abstrakcji pod pełnoprawną obsługę ApplicationSet w interfejsie, a kolejne wydania stopniowo ją rozwijają; niezależnie od wersji ApplicationSet zarządzamy deklaratywnie przez Git lub poleceniami argocd appset, traktując UI przede wszystkim jako podgląd wygenerowanych aplikacji.

ArgoCD ApplicationSet – dobre praktyki

Na koniec zbiór zasad, które wypracowałem, utrzymując opisane wyżej konfiguracje w warunkach produkcyjnych:

  • zawsze włączaj goTemplate: true z missingkey=error — literówka w nazwie parametru ma wysypać renderowanie, a nie generować aplikację z pustym polem,
  • trzymaj folder wzorcowy z exclude: true — szablon _example w repozytorium przyspiesza onboarding i nigdy nie zostanie wdrożony,
  • rozróżniaj dwa poziomy sprzątaniaautomated.prune usuwa podczas synchronizacji zasoby wykasowane z repozytorium, natomiast zniknięcie elementu generatora sprawia, że ApplicationSet usuwa całą aplikację, a jej zasoby kasuje finalizer ArgoCD. To ogromna zaleta (sprzątanie „za darmo”), ale przy danych stanowych warto rozważyć preserveResourcesOnDeletion: true albo politykę create-only/create-update,
  • nie edytuj wygenerowanych Application ręcznie — kontroler i tak nadpisze zmiany; jedynym źródłem prawdy jest ApplicationSet (a wyjątki opisuj przez ignoreApplicationDifferences),
  • pamiętaj o poprawnych nazwach aplikacji — parametry trafiające do metadata.name przepuszczaj przez normalize(albo slugify), które sprowadzą wartość do dozwolonych znaków i długości; samo lower załatwi tylko wielkie litery,
  • dodawaj adnotacje notyfikacji w szablonie — subskrypcje ArgoCD Notifications zdefiniowane raz w template.metadata.annotations obejmują automatycznie każdą wygenerowaną aplikację,
  • zacznij od List, potem Git, potem Matrix — statyczna lista jest najłatwiejsza do zrozumienia i debugowania; po bardziej złożone generatory sięgaj, gdy faktycznie ich potrzebujesz.

Podsumowanie

ApplicationSet zamienia zarządzanie dziesiątkami aplikacji ArgoCD z żmudnego kopiowania manifestów w utrzymywanie jednej, zwięzłej definicji. Generator List porządkuje przewidywalny zestaw środowisk, generator Git czyni strukturę repozytorium źródłem prawdy o tym, co działa w klastrze, a generatory Cluster i Matrix domykają scenariusze multi-cluster. W połączeniu z templatePatch i Progressive Syncs otrzymujemy mechanizm, który skaluje się od kilku aplikacji do setek — bez utraty kontroli nad tym, co i w jakiej kolejności trafia na produkcję.

W praktyce, wykorzystanie tego rozwiązania prowadzi do sytuacji, w której dodanie nowego klienta, środowiska czy klastra przestaje być „zadaniem dla DevOpsa”, a staje się zwykłym pull requestem. I właśnie o to w GitOps chodzi.

Przydatne linki:


Autor

Emil Juchnikowski - autor artykułu DevOps + GitOps przy użyciu Gitlab i ArgoCD - część I (CI)

Emil Juchnikowski — pracuje jako Architekt Oprogramowania. Swoją karierę rozpoczął jako .NET Developer ponad 10 lat temu. Teraz już z technologią .NET ma bardzo mało wspólnego. Rozwija się w technologiach JS, w różnych kierunkach: frontend Angular i Ionic, backend NodeJS i NestJS, bazy danych MongoDB. Poza tym zajmuje się też zagadnieniami DevOps, GitOps opartymi o konteneryzację w Kubernetes. Poza pracą lubi biegać na długie dystanse oraz trenuje boks. Jego motto to: Jedynym ograniczeniem jest nasza wyobraźnia… a niektórzy twierdzą, że jeszcze czas i pieniądze.







.

Leave a Comment

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *