Argo CD снова показывает OutOfSync после синхронизации: как прочитать diff
Оператор нажимает Sync, операция завершается без ошибки, а через несколько секунд приложение опять OutOfSync. Повторение операции не даёт устойчивого результата. Возможны разные ситуации: Kubernetes отбросил неизвестное поле, другой контроллер изменил объект, генератор манифестов выдал новое значение либо в кластере остался ресурс, удалённый из Git. Начинать нужно с конкретного diff.
Сравниваем одну ревизию и один объект
argocd app get demo-api --refresh argocd app diff demo-api argocd app manifests demo-api
Команды предполагают настроенный Argo CD CLI и доступ к приложению demo-api. В get посмотрите отслеживаемую ревизию и результат последней операции. Запишите commit, с которым сравниваете кластер. Пока ветка продолжает двигаться, две последовательные проверки могут относиться к разным версиям. В manifests видны сгенерированные желаемые объекты: при использовании Helm это уже результат шаблонов, а не исходный values.yaml.
В diff сначала определите вид расхождения. Если отличается поле существующего Deployment, исследуйте его значение и владельца. Если ресурс есть только в live, выясните, должен ли он быть удалён при синхронизации. Выключенный prune оставляет такой объект и может сохранять OutOfSync даже после успешного применения остальных манифестов. Настройка ignoreDifferences для replicas эту ситуацию не исправит.
Прослеживаем, кто меняет значение
kubectl -n demo get deployment api -o yaml --show-managed-fields
kubectl -n demo get hpa
kubectl -n demo describe hpa apiПредположим, Git задаёт replicas: 2, а HorizontalPodAutoscaler поднимает число реплик до четырёх. Оба компонента исправно выполняют свои задачи, но желаемое число владельцев поля оказалось больше одного. В managedFields можно увидеть менеджеров, записывавших поля. Это подсказка о происхождении изменений, которую нужно сопоставить с настройкой HPA и временем события; одного имени менеджера недостаточно для решения скрыть весь его diff.
Другой пример — неизвестный ключ в манифесте. После применения API может отвергнуть или отбросить поле в зависимости от схемы и режима проверки. В live его нет, а генератор продолжает возвращать ключ при каждой синхронизации. Здесь нужно исправить шаблон. Если Helm использует случайную генерацию значения при каждом рендере, стабилизируйте источник этого значения или способ управления Secret. Исключение сравнения маскирует симптом, но оставляет повторную генерацию.
Узкое исключение для согласованного владельца
Если принято решение, что число реплик определяет HPA, исключение можно ограничить одним Deployment. Следующий фрагмент добавляется в spec Application, а не в Deployment. Значения name и namespace обозначают целевой объект приложения:
ignoreDifferences:
- group: apps
kind: Deployment
name: api
namespace: demo
jsonPointers:
- /spec/replicasТакое правило исключает replicas из сравнения. Оно не означает, что Argo CD перестал передавать поле при Sync. Для учёта исключения во время применения существует syncOptions: RespectIgnoreDifferences=true. Его поведение зависит и от существования live-ресурса: при первом создании отсутствует текущее значение, которое можно сохранить. Эти две настройки решают связанные, но разные задачи.
syncPolicy:
syncOptions:
- RespectIgnoreDifferences=trueОба фрагмента относятся к одному уровню spec Application. До добавления опции проверьте, зачем replicas вообще присутствует в генераторе и какое значение требуется при первом создании. Команде стоит явно записать, что HPA управляет масштабом, а Git — образом, портами и другими параметрами. Тогда исключение имеет понятную границу. Не переносите правило на все Deployment всех приложений ради одного спорного поля.
Проверяем, что сравнение осталось полезным
После изменения обновите приложение и заново прочитайте diff. Ожидается исчезновение только согласованного расхождения. Изменение image или переменной окружения должно по-прежнему обнаруживаться. Если исключение построено через managedFieldsManagers, проверьте, какие ещё поля принадлежат этому менеджеру. Широкая маска способна скрыть реальное отклонение вместе с техническим шумом.
Отдельно посмотрите Health. Synced говорит о соответствии желаемой конфигурации правилам сравнения; Healthy отражает состояние ресурсов. Можно получить совпадающие манифесты и падающие Pod. И наоборот, работающий сервис может оставаться OutOfSync из-за лишнего ConfigMap. Не используйте зелёный Sync как замену проверке обработки запросов.
Если желаемое значение меняется между двумя обновлениями без нового commit, сравните результаты повторного рендера. Для Helm причину ищите в функциях генерации и входных параметрах; для плагина — также в его внешних источниках. Зафиксированный Git commit не делает произвольный генератор детерминированным. При расследовании полезно сохранить два результата manifests с временем получения: это отделит изменяющийся desired от контроллера, который переписывает только live.
Когда diff показывает поле с именем, содержащим косую черту, учтите правила JSON Pointer: внутри сегмента / записывается как ~1, а ~ как ~0. Ошибка экранирования может оставить исключение без эффекта. После изменения правила проверьте именно исходное расхождение, а не только успешное сохранение Application в Kubernetes.
Завершите расследование коротким описанием: какое поле отличалось, кто менял его после применения и почему выбран исправленный шаблон либо исключение. Такой порядок сохраняет diff инструментом контроля, а не списком раздражающих уведомлений.
Ещё по теме
- Argo CD запрещает destination или ресурс: ограничения AppProject
- Argo CD и Helm: где искать values, которые реально попали в релиз
Продолжить изучение
Хотите выстроить доставку изменений из Git в кластер? Синхронизация, окружения и восстановление после неудачного релиза — темы программы «Argo CD и GitOps: деплой в Kubernetes».
Продолжить на практике
- Argo CD и GitOps: деплой в Kubernetes ↗
Превратите Git в источник правды для Kubernetes. Настройте Argo CD, управляемую синхронизацию и окружения, научитесь находить drift и откатывать изменения через Git. Итог — воспроизводимый GitOps-процесс для приложения.
