ArgoCD Kubernetes etcd

ArgoCD etcdserver: request is too large — Application przekracza limit 1 MB

Diagnoza i naprawa błędu etcdserver: request is too large w ArgoCD, gdy Application CRD przekracza limit 1 MB w etcd.

·
ArgoCD nie może zapisać stanu synchronizacji, bo Application CRD przekroczyło limit rozmiaru obiektu w etcd. Każda próba sync kończy się błędem ResourceExhausted. Ten runbook pokazuje jak zdiagnozować problem i naprawić go w kilka minut.

Ten runbook jest częścią serii o blokadach synchronizacji ArgoCD. Zobacz też: HPA OutOfSync loop i deadlock operacji. Jeśli interesuje Cię szerszy kontekst GitOps i ArgoCD, przeczytaj nasz post o GitOps i ArgoCD.

Objaw

W logach argocd-application-controller pojawia się błąd:

# Error in argocd-application-controller logs:
# rpc error: code = ResourceExhausted desc = etcdserver: request is too large

kubectl get application <APP_NAME> -n argocd -o json | wc -c
# Output > 1048576 (1 MB) = problem confirmed

Application nie przechodzi w stan Synced. Każda próba sync kończy się tym samym błędem. ArgoCD UI może wyświetlać status Unknown lub Syncing bez postępu.

Przyczyna

Każdy obiekt w Kubernetes (w tym Application CRD) jest przechowywany w etcd, który ma twardy limit 1.5 MB na pojedynczy obiekt (domyślnie konfigurowany na 1 MB w wielu dystrybucjach). ArgoCD zapisuje w Application CRD nie tylko konfigurację, ale też:

  • .status.history — pełną historię poprzednich synchronizacji (manifesty, parametry, wyniki)
  • .status.resources — listę wszystkich zarządzanych zasobów z ich stanem
  • managedFields — metadata Kubernetes śledząca, kto zmienił jakie pole

Przy dużych Helm chartach (100+ zasobów) lub przy długiej historii synchronizacji, Application CRD rośnie powyżej limitu etcd. Problem narasta z czasem — każdy sync dodaje wpis do historii. Domyślna wartość revisionHistoryLimit to 10, ale w środowiskach z częstymi deploymentami (np. kilka razy dziennie) historia kumuluje się szybko.

Dodatkowym czynnikiem jest managedFields — metadata dodawana przez Kubernetes server-side apply. Każde pole w każdym zarządzanym zasobie ma wpis o tym, kto je ostatnio zmodyfikował. Przy setkach zasobów te metadane potrafią same zająć setki kilobajtów.

Rozwiązanie

A) Ogranicz historię synchronizacji (natychmiastowa ulga):

# Check current history size
kubectl get application <APP_NAME> -n argocd \
  -o jsonpath='{.status.history}' | wc -c

# Patch: reduce history to last 3 entries
kubectl patch application <APP_NAME> -n argocd --type merge -p '
{
  "spec": {
    "revisionHistoryLimit": 3
  }
}'

# Force cleanup of existing oversized history
kubectl get application <APP_NAME> -n argocd -o json | \
  jq '.status.history = .status.history[-3:]' | \
  kubectl apply -f -

B) Skonfiguruj resource.customizations w argocd-cm ConfigMap:

# argocd-cm ConfigMap patch — strip managedFields from tracked resources
apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-cm
  namespace: argocd
data:
  resource.customizations.ignoreDifferences.all: |
    managedFields:
      - manager: "*"
  resource.compareoptions: |
    ignoreResourceStatusField: all
# Apply and restart repo-server to pick up changes
kubectl apply -f argocd-cm-patch.yaml
kubectl rollout restart deployment argocd-repo-server -n argocd

C) Podziel dużą aplikację na mniejsze Applications (ApplicationSet):

Jeśli Twój Helm chart zarządza ponad 100 zasobami, rozważ podział na logiczne grupy. ApplicationSet pozwala generować wiele Applications z jednego szablonu:

# Instead of one monolithic Application with 200+ resources,
# split into logical groups using ApplicationSet
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: platform-components
  namespace: argocd
spec:
  generators:
    - list:
        elements:
          - chart: networking
            path: charts/networking
          - chart: monitoring
            path: charts/monitoring
          - chart: workloads
            path: charts/workloads
  template:
    metadata:
      name: "platform-"
    spec:
      project: default
      source:
        repoURL: https://github.com/org/infra.git
        targetRevision: main
        path: ""
      destination:
        server: https://kubernetes.default.svc
        namespace: ""
      syncPolicy:
        automated:
          prune: true
          selfHeal: true

Podział na mniejsze Applications ma dodatkową zaletę — poszczególne grupy zasobów synchronizują się niezależnie, co skraca czas pojedynczej operacji sync i poprawia metryki DORA (deployment frequency, lead time for changes).

Walidacja

# 1. Verify Application resource size is under 1 MB
kubectl get application <APP_NAME> -n argocd -o json | wc -c
# Expected: < 1048576

# 2. Verify sync status is Synced
argocd app get <APP_NAME> --output json | jq '.status.sync.status'
# Expected: "Synced"

# 3. Verify health status
argocd app get <APP_NAME> --output json | jq '.status.health.status'
# Expected: "Healthy"

# 4. Check controller logs for recurring errors
kubectl logs statefulset/argocd-application-controller -n argocd \
  --since=5m | grep -c "error"
# Expected: 0 or minimal

Jeśli rozmiar Application spada poniżej 1 MB i sync przechodzi bez błędów, problem jest rozwiązany. Monitoruj przez kilka cykli reconciliation (3-5 minut), aby upewnić się, że obiekt nie rośnie z powrotem.

Jerzy Kopaczewski

Pipeline CI/CD blokuje Twój zespół?

Umów bezpłatną 30-minutową rozmowę. Przejrzymy konfigurację ArgoCD i wskażemy, co naprawić od razu.