Deep Dive into Argo CD Core Feature Functionalities: GitOps Controller Architecture Explained
Argo CD continuously reconciles Git-stored desired state with live Kubernetes cluster state through a six-stage pipeline involving manifest generation, normalization, diff computation, and wave-based synchronization.
The argoproj/argo-cd repository implements a declarative GitOps controller that automates application deployment and lifecycle management. Understanding its Argo CD core feature functionalities requires examining the controller package and gitops-engine library that orchestrate the reconciliation loop. The controller operates by pulling source repositories, computing diffs against live cluster state, and executing synchronized deployments while respecting ignore differences and sync wave configurations.
Manifest Generation and Repository Resolution
Argo CD begins reconciliation by generating manifests from configured sources. The GetRepoObjs function in controller/state.go coordinates with the repo-server to render templates for Helm, Kustomize, or plain YAML sources.
// Simplified flow from controller/state.go
targetObjs, manifestInfos, revisionsMayHaveChanges, err :=
m.GetRepoObjs(ctx, app, sources, appLabelKey, revisions,
noCache, noRevisionCache, project.EffectiveSourceIntegrity(),
project, true)
Revision resolution occurs through ResolveRevision, which converts ambiguous references like HEAD or master into concrete commit SHAs. When projects enforce source integrity, the UpdateRevisionForPaths RPC narrows revisions to only changes affecting the application's referenced paths.
Target Normalization and Ignore Differences
Before computing diffs, Argo CD applies the ignoreDifferences specification through NormalizeTargetObjects in controller/state.go. This function:
- Removes ignored fields from live resources before diff calculation
- Copies ignored fields from live to target objects, excluding the
statussub-resource
Configuration example for ignoring deployment annotations:
spec:
ignoreDifferences:
- group: apps
kind: Deployment
jsonPointers:
- /metadata/annotations
When configured, the diff engine treats changes to metadata.annotations as in-sync, preventing false drift detection on fields managed by external systems.
Live State Retrieval and Permission Validation
The controller retrieves current cluster state via GetManagedLiveObjs from the LiveStateCache:
liveObjByKey, err := m.liveStateCache.GetManagedLiveObjs(destCluster, app, targetObjs)
Resources are filtered against project allow/deny lists through validateSyncPermissions. Any resource not explicitly permitted by the AppProject configuration is excluded from reconciliation to enforce security boundaries.
Diff Computation and Server-Side Reconciliation
Argo CD builds a diff.Config and invokes argodiff.StateDiffs to compute three-way diffs between desired and live states:
diffResults, err := argodiff.StateDiffs(ctx,
reconciliation.Live, reconciliation.Target, diffConfig)
Server-side diff activates when ServerSideDiff=true, utilizing dry-run kubectl apply operations to calculate changes without API server modification. When structured merge diff is enabled alongside ServerSideApply=true, the controller uses server-side apply mechanics for conflict resolution.
The diff configuration is constructed in controller/state.go around line 470, incorporating ignore differences, resource overrides, and comparison options.
Sync Execution and Wave Orchestration
The SyncAppState function in controller/sync.go orchestrates the actual synchronization:
syncCtx, cleanup, err := sync.NewSyncContext(
compareResult.syncStatus.Revision,
reconciliationResult,
restConfig,
rawConfig,
m.kubectl,
app.Spec.Destination.Namespace,
opts...)
Sync waves enable sequential resource application through the syncWave annotation. Resources group by wave number (default 0), applying in numerical order with configurable delays. The ARGOCD_SYNC_WAVE_DELAY environment variable controls pauses between waves (default 2 seconds):
import (
"os"
"github.com/argoproj/argo-cd/v3/util/settings"
)
// Set a 5-second delay between sync waves
os.Setenv("ARGOCD_SYNC_WAVE_DELAY", "5")
Pruning behavior respects PrunePropagationPolicy and PruneLast settings, ensuring resource deletion occurs according to dependency requirements.
Health Assessment and Status Updates
Post-sync, setApplicationHealth in controller/state.go evaluates resource conditions:
healthStatus, healthMessage, err := setApplicationHealth(
managedResources, resourceSummaries, resourceOverrides,
app, m.persistResourceHealth)
Individual resource health populates Application.Status.Resources, while aggregated application health (Healthy, Degraded, Missing, or Progressing) updates Application.Status.Health. The evaluation uses gitops-engine health rules customized through resource overrides.
Practical Configuration Examples
Server-Side Apply with Namespace Creation
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: nginx
spec:
project: default
source:
repoURL: https://github.com/example/nginx
targetRevision: HEAD
path: ./manifests
destination:
server: https://kubernetes.default.svc
namespace: nginx
syncPolicy:
syncOptions:
- ServerSideApply=true
- CreateNamespace=true
ServerSideApply=true forces the controller to use Kubernetes server-side apply during sync, while CreateNamespace=true enables automatic namespace provisioning.
Sync Waves with PostSync Hooks
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: multi-wave
spec:
source:
repoURL: https://github.com/example/multi-wave
targetRevision: main
path: .
destination:
server: https://kubernetes.default.svc
namespace: demo
syncPolicy:
syncOptions:
- PruneLast=true
- RespectIgnoreDifferences=true
hooks:
- exec:
command: ["/bin/sh", "-c", "echo Post-hook"]
type: PostSync
syncWave: 2
The PostSync hook executes after wave 2 completes, while PruneLast=true ensures orphaned resources are deleted following successful wave application.
Ignoring Container Image Changes
spec:
ignoreDifferences:
- group: apps
kind: Deployment
jsonPointers:
- /spec/template/spec/containers/0/image
This configuration prevents drift detection when container images are updated outside Git, common in CI/CD pipelines that mutate images during build processes.
Key Source Files
| File | Responsibility |
|---|---|
controller/state.go |
Manifest generation, target normalization, live state loading, diff computation, and health calculation |
controller/sync.go |
Sync operation orchestration, wave handling, server-side apply, and pruning logic |
controller/sharding/sharding.go |
Workload distribution across controller replicas |
gitops-engine/pkg/sync |
Core diff, reconciliation, and resource-level sync primitives |
util/argo/diff |
Three-way diff implementation and configuration |
util/settings |
Centralized configuration for resource overrides and feature flags |
Summary
- Argo CD core feature functionalities center on a deterministic six-stage reconciliation pipeline: manifest generation, target normalization, live state retrieval, diff computation, sync execution, and health assessment.
- The
GetRepoObjsfunction incontroller/state.gohandles repository resolution and template rendering, supporting Helm, Kustomize, and raw YAML sources. NormalizeTargetObjectsappliesignoreDifferencesconfigurations by selectively copying fields from live to target objects before diff calculation.SyncAppStateincontroller/sync.goorchestrates wave-based deployments with configurable delays throughARGOCD_SYNC_WAVE_DELAY.- Server-side diff and server-side apply provide modern Kubernetes reconciliation mechanisms for complex field ownership scenarios.
Frequently Asked Questions
What is the Argo CD reconciliation loop?
The reconciliation loop is a continuous process where Argo CD compares desired state from Git repositories against live Kubernetes cluster state. According to the argoproj/argo-cd source code, the loop executes through controller/state.go, generating manifests, normalizing targets, computing diffs via argodiff.StateDiffs, and triggering synchronization when drift is detected. The loop runs at configured intervals or when triggered by webhook events.
How does Argo CD handle sync waves?
Sync waves allow sequential resource deployment using the syncWave annotation (default 0). As implemented in controller/sync.go, Argo CD applies resources in numerical wave order, waiting for each wave to complete before proceeding to the next. The ARGOCD_SYNC_WAVE_DELAY environment variable configures pauses between waves, while PruneLast ensures resource deletion occurs after all waves complete successfully.
What is server-side diff in Argo CD?
Server-side diff is a comparison method enabled by ServerSideDiff=true that uses dry-run kubectl apply operations to calculate changes without modifying the API server. Implemented in the diff configuration logic of controller/state.go, this approach provides more accurate results for resources using server-side apply by simulating the actual merge process that would occur during synchronization.
How does ignoreDifferences prevent false drift detection?
The ignoreDifferences specification prevents specific fields from triggering out-of-sync status through NormalizeTargetObjects in controller/state.go. This function removes configured fields from live objects before diff computation and copies current values into target objects (excluding status fields), ensuring the comparison treats ignored changes as in-sync regardless of cluster state mutations.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →