Reconcile 최적화

Reconcile 최적화 (Reconcile Optimization)

기본적으로 Argo CD Application은 그에 속한 리소스가 변경될 때마다 새로고침(refresh)돼요. Kubernetes 컨트롤러는 감시하는 리소스를 주기적으로 업데이트하는 경우가 많아서, Application에 지속적인 reconcile 작업이 발생하고 argocd-application-controller의 CPU 사용량이 높아질 수 있어요. Argo CD는 추적되는 리소스 (tracked resources)에 대해 특정 필드의 리소스 업데이트를 선택적으로 무시할 수 있게 해줘요. 추적되지 않는 리소스는 argocd.argoproj.io/ignore-resource-updates 어노테이션을 사용할 수 있어요.

출처: 문서

본문

리소스 업데이트가 무시되면, 리소스의 헬스 상태가 변경되지 않는 한 그 리소스가 속한 Application은 reconcile되지 않아요.

시스템 수준 구성 (System-Level Configuration)

기본적으로 resource.ignoreResourceUpdatesEnabledtrue로 설정되어 Argo CD가 리소스 업데이트를 무시할 수 있게 해줘요. 이 기본 설정은 불필요한 reconcile 작업을 줄여 Argo CD가 지속 가능한 성능을 유지하도록 보장해요. 이 동작을 변경해야 한다면 argocd-cm ConfigMap에서 resource.ignoreResourceUpdatesEnabled를 명시적으로 false로 설정할 수 있어요:

apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-cm
  namespace: argocd
data:
  resource.ignoreResourceUpdatesEnabled: 'false'

Argo CD는 RFC6902 JSON 패치JQ 경로 표현식을 사용해 특정 JSON 경로에서 리소스 업데이트를 무시할 수 있게 해줘요. 이것은 argocd-cm ConfigMap의 resource.customizations 키에서 특정 group과 kind에 대해 구성할 수 있어요.

다음은 ExternalSecret 리소스의 refreshTime 상태 필드를 무시하는 커스터마이즈 예시예요:

data:
  resource.customizations.ignoreResourceUpdates.external-secrets.io_ExternalSecret:
    |
    jsonPointers:
    - /status/refreshTime
    # JQ equivalent of the above:
    # jqPathExpressions:
    # - .status.refreshTime

ignoreResourceUpdates를 Argo CD 인스턴스가 관리하는 모든 Application의 모든 추적 리소스에 적용하도록 구성하는 것도 가능해요. 이를 위해 아래 예시처럼 리소스 커스터마이즈를 구성할 수 있어요:

data:
  resource.customizations.ignoreResourceUpdates.all: |
    jsonPointers:
    - /status

ignoreDifferences를 사용해 reconcile 무시하기 (Using ignoreDifferences to ignore reconcile)

기본적으로 기존 시스템 수준 ignoreDifferences 커스터마이즈도 리소스 업데이트 무시에 추가돼요. 이것은 기존 ignore differences 구성을 모두 복사하지 않아도 되므로 설정 관리를 줄여줘요.

이 동작을 비활성화하려면 ignoreDifferencesOnResourceUpdates 설정을 비활성화하면 돼요:

apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-cm
data:
  resource.compareoptions: |
    ignoreDifferencesOnResourceUpdates: false

기본 구성 (Default Configuration)

기본적으로 generation, resourceVersion, managedFields 메타데이터 필드는 모든 리소스에 대해 항상 무시돼요.

무시할 리소스 찾기 (Finding Resources to Ignore)

애플리케이션 컨트롤러는 리소스 변경이 새로고침을 트리거할 때 로그를 남겨요. 이 로그를 사용해 변경이 잦은(high-churn) 리소스 종류를 찾고, 해당 리소스를 검사해 어떤 필드를 무시할지 찾을 수 있어요.

이 로그를 찾으려면 "Requesting app refresh caused by object update"를 검색하세요. 로그에는 api-versionkind에 대한 구조화된 필드가 포함돼요. api-version/kind별로 트리거된 새로고침 수를 세면 변경이 잦은 리소스 종류가 드러날 거예요.

[!NOTE] 이 로그는 GitOps 관리 리소스에 대해 info 레벨이고, orphan 및 dependent 리소스에 대해서는 debug 레벨이에요. 가장 자세한 정보를 보려면 application-controller의 로그 레벨을 debug로 구성하고, comparison-level 필드로 해당 리소스 업데이트의 중요도를 파악하세요.

자주 변경되는 리소스를 식별했다면 어떤 필드가 변경되는지 확인해볼 수 있어요. 한 가지 방법은 다음과 같아요:

kubectl get <resource> -o yaml > /tmp/before.yaml
# Wait a minute or two.
kubectl get <resource> -o yaml > /tmp/after.yaml
diff /tmp/before.yaml /tmp/after.yaml

diff를 보면 어떤 필드가 변경되고 있고 어쩌면 무시해야 하는지 감을 잡을 수 있어요.

리소스 업데이트가 무시되는지 확인 (Checking Whether Resource Updates are Ignored)

Argo CD가 무시된 리소스 업데이트 때문에 새로고침을 건너뛸 때마다 컨트롤러는 다음 줄을 기록해요: "Ignoring change of object because none of the watched resource fields have changed".

리스ource ignore 규칙이 적용되고 있는지 확인하려면 application-controller 로그에서 이 줄을 검색하세요.

[!NOTE] 이 로그는 debug 레벨이에요. application-controller의 로그 레벨을 debug로 구성하세요.

예시 (Examples)

argoproj.io/Application

apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-cm
data:
  resource.customizations.ignoreResourceUpdates.argoproj.io_Application: |
    jsonPointers:
    # Ignore when ownerReferences change, for example when a parent ApplicationSet changes often.
    - /metadata/ownerReferences
    # Ignore reconciledAt, since by itself it doesn't indicate any important change.
    - /status/reconciledAt
    jqPathExpressions:
    # Ignore lastTransitionTime for conditions; helpful when SharedResourceWarnings are being regularly updated but not
    # actually changing in content.
    - .status?.conditions[]?.lastTransitionTime

추적되지 않는 리소스의 업데이트 무시 (Ignoring updates for untracked resources)

ArgoCD는 ignoreResourceUpdates 구성을 애플리케이션의 추적되는 리소스에만 적용해요. 즉, Deployment가 만든 ReplicaSetPod 같은 dependent 리소스는 업데이트를 무시하지 않으며, 변경 사항이 있으면 애플리케이션의 reconcile을 트리거해요.

ignoreResourceUpdates 구성을 추적되지 않는 리소스에 적용하고 싶다면 dependent 리소스 매니페스트에 argocd.argoproj.io/ignore-resource-updates=true 어노테이션을 추가할 수 있어요.

예시 (Example)

CronJob

apiVersion: batch/v1
kind: CronJob
metadata:
  name: hello
  namespace: test-cronjob
spec:
  schedule: '* * * * *'
  jobTemplate:
    metadata:
      annotations:
        argocd.argoproj.io/ignore-resource-updates: 'true'
    spec:
      template:
        metadata:
          annotations:
            argocd.argoproj.io/ignore-resource-updates: 'true'
        spec:
          containers:
            - name: hello
              image: busybox:1.28
              imagePullPolicy: IfNotPresent
              command:
                - /bin/sh
                - -c
                - date; echo Hello from the Kubernetes cluster
          restartPolicy: OnFailure

리소스 업데이트는 argocd-cm configMap의 ignoreResourceUpdates 구성에 따라 무시돼요:

argocd-cm:

resource.customizations.ignoreResourceUpdates.batch_Job: |
  jsonPointers:
    - /status
resource.customizations.ignoreResourceUpdates.Pod: |
  jsonPointers:
    - /status

더 알아보기 (Learn more)