argoproj/argo-cd
Application controller
The application controller is the heart of Argo CD. It watches Application and AppProject CRs, reconciles them against live Kubernetes state, drives sync operations, and publishes status into Redis.
Purpose
- Watch Application CRs across one or more namespaces and clusters.
- For each Application, retrieve rendered manifests from the repo server, compare against live state, compute diffs, and report status.
- Execute sync operations (apply, prune, hook lifecycle, retries, self-heal).
- Maintain cluster informers per destination cluster and a sharded workload distribution.
- Publish per-app cache entries that the API server reads.
Where it lives
| Path | Purpose |
|---|---|
cmd/argocd-application-controller/commands/argocd_application_controller.go |
Cobra entry point and flag wiring. |
controller/appcontroller.go |
The reconciliation loop, ~105 KB. |
controller/state.go |
Compares desired vs. live state, orchestrates the comparison pipeline. ~54 KB. |
controller/sync.go |
Sync execution: apply order, hook phases, retries, self-heal. |
controller/hook.go |
PreSync/Sync/PostSync/SyncFail hook handling. |
controller/health.go |
Application health computation from per-resource health. |
controller/sharding/ |
Sharding strategies for distributing apps across replicas. |
controller/cache/ |
Per-controller cache wrappers around Redis. |
controller/metrics/ |
Prometheus metrics. |
controller/clusterinfoupdater.go |
Periodically updates ClusterInfo Secrets. |
controller/syncid/ |
Generates unique sync operation IDs. |
controller/hydrator/ |
Manifest hydrator integration (sources → hydrated branch). |
controller/sort_delete.go |
Resource-deletion ordering helpers. |
Reconciliation loop
graph TD
Watch[Application informer] --> Q[Workqueue + rate limiter]
Q --> Refresh{Refresh?}
Refresh -->|hard or soft| Comp[CompareAppState - state.go]
Comp --> Repo[(Repo server: GenerateManifests)]
Comp --> Live[(Cluster cache: live state)]
Comp --> Diff[Compute diff + sync status]
Diff --> Status[Update Application status]
Status --> Redis[(Redis cache for API server)]
Q --> Op{Operation?}
Op -->|sync| Sync[ExecuteSyncOperation - sync.go]
Sync --> Hooks[Hook phases - hook.go]
Hooks --> Apply[Apply manifests via gitops-engine]
Apply --> StatusTwo parallel work queues are maintained: a status processor queue (refresh/compare) and an operation processor queue (active syncs). Their depths are configured by --status-processors and --operation-processors (defaults 20 each in cmd/argocd-application-controller/commands/argocd_application_controller.go).
Refresh cadence:
- Soft refresh every
--app-resyncseconds (default 180 = 120 + jitter), reusing repo-server cache. - Hard refresh every
--app-hard-resyncseconds, ignoring caches. - Webhook-driven refresh comes in via the API server.
Sync mechanics
controller/sync.go (and the underlying gitops-engine library vendored at gitops-engine/) handle:
- Apply order — namespaces first, then non-namespaced, then namespaced; with weight overrides via the
argocd.argoproj.io/sync-waveannotation. - Hook phases — PreSync → Sync → PostSync, with SyncFail on failure. See
controller/hook.go. - Retry policy — backoff/limit on the Application's
syncPolicy.retry. - Self-heal — re-sync on drift if
selfHeal: true. Exponential backoff is in--self-heal-backoff-*flags. - Sync timeout —
--sync-timeout-secondsaborts long-running operations. - Server-side diff/apply — controlled by
--server-side-diff-enabledflag and per-app annotations.
Sharding
controller/sharding/ distributes Applications across controller replicas. The strategy is configurable (legacy/round-robin/cluster). Sharding decides which controller pod owns which Application and is keyed off the destination cluster.
Cluster cache
Each registered cluster gets a long-lived informer (util/settings/cluster_informer.go) that mirrors all watchable resources into memory. The controller queries this cache for live state during diffing, avoiding API calls per refresh.
Resource customizations
Custom health and resource actions for arbitrary CRDs live under resource_customizations/<group>/<kind>/. Each may contain health.lua, actions/<verb>.lua, and actions/discovery.lua. The Lua engine is util/lua/lua.go (using gopher-lua).
Manifest hydrator integration
When --hydrator-enabled=true, the controller drives the manifest hydrator pipeline:
- Fetch dry sources via the repo server.
- Hydrate them locally (
util/hydrator/,controller/hydrator/). - Push the hydrated manifests to the commit server, which commits them to a hydrated branch.
- Sync the Application from the hydrated branch.
See Manifest hydrator.
Configuration surface (selected flags)
--repo-server,--commit-server— peer addresses.--app-resync,--app-hard-resync,--app-resync-jitter— refresh cadence.--status-processors,--operation-processors,--kubectl-parallelism-limit— concurrency.--self-heal-timeout-seconds,--self-heal-backoff-*— self-heal pacing.--application-namespaces— multi-tenant Application discovery.--server-side-diff-enabled— global server-side diff.--otlp-address— tracing.
Entry points for modification
- New comparison rule → extend
controller/state.go. - New sync semantics → extend
controller/sync.go(or the upstreamgitops-engine). - New hook annotation → extend
controller/hook.go. - New sharding strategy → add a strategy under
controller/sharding/. - New custom health or action → drop a Lua script under
resource_customizations/<group>/<kind>/.
See also: features/gitops-sync, primitives/application.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.