ApplicationSet отменяет ручные изменения Application: где редактировать шаблон

Оператор отключил автосинхронизацию Application, но она включилась снова. При этом Git приложения не менялся, а selfHeal выглядит выключенным. Вероятная причина находится уровнем выше: ApplicationSet генерирует само Application и восстанавливает его спецификацию. Нужно понять, какой контроллер управляет изменяемым объектом.

Прослеживаем владельца Application

kubectl -n argocd get application api-prod -o yaml
kubectl -n argocd get applicationset
kubectl -n argocd get applicationset api-environments -o yaml

В Application проверьте ownerReferences, labels и managedFields. Имя ApplicationSet возьмите из фактических данных, а не из примера. Затем найдите generator и template, из которых получаются имя, source, destination и syncPolicy. Сам ApplicationSet тоже может управляться GitOps-приложением; в этом случае изменение его live YAML также временно.

Здесь работают два разных согласования. ApplicationSet controller поддерживает набор Application и их спецификации. Application controller применяет workload этих Application в целевые кластеры. selfHeal относится ко второму уровню. Его выключение не запрещает первому контроллеру вернуть поле spec.syncPolicy у Application.

Меняем шаблон, из которого получается поле

Пример создаёт Application для двух namespace из одного chart-каталога. Адрес Git является заполнителем. Отсутствие automated означает ручную синхронизацию созданных приложений:

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: api-environments
  namespace: argocd
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
    - list:
        elements:
          - env: test
          - env: prod
  template:
    metadata:
      name: "api-{{.env}}"
    spec:
      project: api
      source:
        repoURL: https://git.example.com/team/platform.git
        targetRevision: main
        path: apps/api
      destination:
        server: https://kubernetes.default.svc
        namespace: "{{.env}}"

Значения generator становятся входом template. Если разные окружения должны иметь разные настройки, выразите это в исходных данных и шаблоне, а не серией ручных patch каждого Application. Сначала проверьте, какие имена и destinations получатся для всех элементов. Ошибка общего шаблона затрагивает сразу несколько окружений.

Временное исключение делаем узким

Для согласованного временного изменения можно настроить ignoreApplicationDifferences. Это поле ApplicationSet, оно относится к сравнению сгенерированных Application. Следующий фрагмент позволяет не возвращать только automated у api-prod:

ignoreApplicationDifferences:
  - name: api-prod
    jsonPointers:
      - /spec/syncPolicy/automated

Фрагмент добавляется в spec ApplicationSet. Он отличается от ignoreDifferences внутри Application, которое управляет сравнением workload. Исключение не создаёт новый ручной процесс управления само по себе: запишите, кто меняет поле, зачем и когда исключение будет убрано. После его удаления генератор снова становится владельцем настройки.

Для списков sources есть ограничения MergePatch: изменение одного элемента может привести к замене списка целиком и затронуть проигнорированные поля. Не переносите один JSON Pointer с single-source Application на multi-source без отдельной проверки. Прочитайте получившийся Application после очередного reconcile, а не только успешный apply ApplicationSet.

Не путаем две политики синхронизации

spec.syncPolicy.applicationsSync у ApplicationSet определяет создание, изменение и удаление Application контроллером набора. Это не то же самое, что template.spec.syncPolicy.automated, определяющее автоматическое применение workload. Режим create-only может запретить часть изменений Application, однако его действие зависит и от глобальной policy контроллера и разрешения override. Менять глобальный режим ради одного временного исключения обычно слишком широко.

Защита от удаления Application при изменении generator также не равна защите workload при удалении самого ApplicationSet. ownerReferences и finalizers имеют отдельный жизненный цикл. Не проверяйте такую гипотезу удалением рабочего набора: сначала разберите политику и протестируйте отдельный набор без данных.

После исправления дождитесь reconcile и повторно прочитайте api-prod. Затем проверьте, что другие сгенерированные Application сохранили ожидаемые поля. Результат должен объяснять цепочку «источник данных → template → Application → workload». Когда владелец каждого уровня известен, ручное изменение больше не выглядит исчезающим само по себе.

Ещё по теме

Продолжить изучение

Хотите выстроить доставку изменений из Git в кластер? Синхронизация, окружения и восстановление после неудачного релиза — темы программы «Argo CD и GitOps: деплой в Kubernetes».

Продолжить на практике

  • Argo CD и GitOps: деплой в Kubernetes ↗

    Превратите Git в источник правды для Kubernetes. Настройте Argo CD, управляемую синхронизацию и окружения, научитесь находить drift и откатывать изменения через Git. Итог — воспроизводимый GitOps-процесс для приложения.