Maven / ArgoCD interview questions
ArgoCD is a declarative, GitOps-based continuous delivery tool for Kubernetes. It automates the deployment of applications to Kubernetes clusters by continuously syncing the cluster state to match the desired state defined in a Git repository.
Before ArgoCD, teams often relied on push-based CI/CD pipelines where a CI server would apply manifests to the cluster after a build. This meant credentials to the cluster had to live inside the CI system, rollbacks required re-running pipelines, and there was no single source of truth for what was actually deployed. ArgoCD flips this to a pull-based model: an agent running inside the cluster watches Git and applies changes itself, removing the need to expose cluster credentials externally.
It solves three concrete problems: drift detection (it continuously compares live state vs Git state and reports or auto-corrects differences), auditability (every change is a Git commit with author, timestamp, and message), and multi-cluster management (a single ArgoCD instance can deploy to many clusters from one control plane).
GitOps is an operational framework that uses Git as the single source of truth for infrastructure and application configuration. All desired states are stored as code in a Git repository, and automated agents continuously reconcile the live system to match what is in Git. Changes are made exclusively through Git operations (commits, pull requests, merges) rather than direct cluster access.
ArgoCD implements GitOps through its Application CRD and reconciliation loop. You define an Application that points to a Git repository path (Helm chart, Kustomize overlay, plain YAML, or Jsonnet) and a target cluster/namespace. The ArgoCD controller runs a continuous reconciliation loop — by default every 3 minutes, or immediately on Git webhook — comparing the rendered manifests from Git against the live cluster resources.
When differences are found, ArgoCD marks the application as OutOfSync. With automated sync enabled (syncPolicy.automated), it applies the Git state to the cluster automatically. With manual sync, an operator triggers the sync explicitly. Either way, the Git repo remains the authoritative record: to roll back, you revert the Git commit and ArgoCD reconciles back to the previous state.
The four GitOps principles ArgoCD satisfies are: declarative configuration, versioned and immutable state, pulled automatically by software agents, and continuously reconciled.
ArgoCD is composed of several distinct components that work together to deliver GitOps continuous delivery:
API Server — Exposes the gRPC and REST API consumed by the ArgoCD UI, CLI (argocd), and any external tooling. It handles authentication, authorization (RBAC), and surfaces application status and operations.
Repository Server — Responsible for cloning Git repositories and rendering manifests. It supports Helm, Kustomize, Jsonnet, and plain YAML. It caches rendered manifests to reduce load on Git and templating engines. All manifest generation happens here in isolation from the rest of the system.
Application Controller — The core reconciliation engine. It continuously compares the live cluster state (via the Kubernetes API) against the desired state (rendered by the repo server) and determines sync status (Synced, OutOfSync, Unknown). It triggers sync operations and manages application health assessment.
ApplicationSet Controller — A separate controller that manages ApplicationSet CRDs, automatically generating and maintaining multiple Application resources from a single template and generator definition.
Dex (optional) — An identity provider proxy bundled with ArgoCD for SSO integration (GitHub, LDAP, SAML, OIDC). Can be replaced by an external OIDC provider.
Redis — Used as a caching layer for application state, reducing repeated calls to the Kubernetes API server and Git repositories. Not a persistent store — ArgoCD can rebuild its state from the cluster.
An ArgoCD Application is a Kubernetes Custom Resource (CRD) that represents a deployed application managed by ArgoCD. It is the fundamental unit of work in ArgoCD — one Application tracks one source (a Git repo path, Helm chart, or OCI artifact) and deploys it to one destination (a cluster and namespace).
The essential fields in an Application manifest are:
- source: defines
repoURL(the Git or Helm repo),targetRevision(branch, tag, or commit SHA), andpath(directory within the repo) orchart(for Helm repos). - destination: specifies
server(the cluster API URL; usehttps://kubernetes.default.svcfor in-cluster) andnamespace. - project: the ArgoCD Project this Application belongs to (controls source/destination whitelist and RBAC).
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: my-app
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/my-org/my-app
targetRevision: HEAD
path: k8s/overlays/production
destination:
server: https://kubernetes.default.svc
namespace: production
syncPolicy:
automated:
prune: true
selfHeal: trueOptional but commonly used: syncPolicy (automated sync, prune, selfHeal), ignoreDifferences (fields to exclude from diff), and info (free-form metadata displayed in the UI).
ArgoCD reports two orthogonal status dimensions for every application: Sync Status and Health Status. Understanding both is essential for diagnosing application state.
Sync Status
| Status | Meaning |
|---|---|
| Synced | Live cluster state matches the desired state in Git exactly. |
| OutOfSync | One or more resources differ between Git and the cluster. Could be a new commit in Git not yet applied, or manual changes to the cluster (drift). |
| Unknown | ArgoCD cannot determine sync status, typically due to cluster connectivity issues or RBAC permissions preventing resource reads. |
Health Status
| Status | Meaning |
|---|---|
| Healthy | All resources pass their health checks (Deployments at desired replicas, Services with endpoints, etc.). |
| Progressing | Resources are being updated and not yet stable (e.g., a Deployment rollout in progress). |
| Degraded | Resources have failed health checks (e.g., a pod in CrashLoopBackOff, or a Deployment with 0 available replicas). |
| Suspended | The resource is intentionally paused (e.g., a suspended CronJob). |
| Missing | The resource is defined in Git but does not exist in the cluster at all. |
| Unknown | ArgoCD does not have a health check rule for this resource type. |
An application can be Synced but Degraded — meaning the Git state was applied correctly but the workload is unhealthy. These two axes must be evaluated independently.
The standard installation uses the official ArgoCD manifest published in the ArgoCD GitHub repository. There are two variants: non-HA (single replica, suitable for development) and HA (multiple replicas for the API server and application controller, for production).
# Create the argocd namespace
kubectl create namespace argocd
# Install ArgoCD (non-HA)
kubectl apply -n argocd -f \
https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yamlAfter applying, verify all pods reach Running state:
kubectl get pods -n argocdBy default, the argocd-server Service is of type ClusterIP. To access the UI locally, use port-forwarding:
kubectl port-forward svc/argocd-server -n argocd 8080:443The initial admin password is auto-generated and stored in the secret argocd-initial-admin-secret. Retrieve it with:
kubectl -n argocd get secret argocd-initial-admin-secret \
-o jsonpath={.data.password}" | base64 -dLog in via CLI:
argocd login localhost:8080 --username admin --password <password> --insecureFor production expose argocd-server via an Ingress or LoadBalancer Service with a valid TLS certificate. The Helm chart (argo/argo-cd) is an alternative installation method that provides easier configuration management.
An ArgoCD Project (AppProject CRD) is a logical grouping and access control boundary within ArgoCD itself. It is entirely separate from Kubernetes namespaces — a Project does not correspond to any Kubernetes object but rather enforces policies on which source repositories, destination clusters, and destination namespaces ArgoCD Applications within that Project are permitted to use.
Key things an AppProject controls:
- sourceRepos: whitelist of Git/Helm repositories Applications may source from. Use
*for any. - destinations: whitelist of cluster + namespace combinations the Applications may deploy to.
- clusterResourceWhitelist / namespaceResourceBlacklist: restrict which Kubernetes resource kinds can be created (e.g., prevent Applications in a dev Project from creating ClusterRoles).
- roles: Project-scoped RBAC roles that can be assigned to users/groups independently of the global ArgoCD RBAC.
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
name: team-payments
namespace: argocd
spec:
sourceRepos:
- https://github.com/my-org/payments-*
destinations:
- namespace: payments-*
server: https://kubernetes.default.svc
clusterResourceWhitelist:
- group: ''
kind: NamespaceA Kubernetes namespace, by contrast, is a runtime isolation boundary within the cluster that separates resource names and applies ResourceQuotas/NetworkPolicies. An ArgoCD Project can deploy to multiple namespaces, and multiple Projects can target the same namespace — they operate at different abstraction layers.
ArgoCD has first-class support for Helm and can render Helm charts as part of its manifest generation pipeline inside the Repository Server. There are two ways to use Helm with ArgoCD:
1. Helm repository as source — You specify a Helm chart repository URL and chart name directly in the Application's source. ArgoCD fetches and renders the chart at the specified version.
source:
repoURL: https://charts.bitnami.com/bitnami
chart: postgresql
targetRevision: 12.5.6
helm:
values: |
auth:
postgresPassword: "{{ .Values.dbPassword }}" 2. Helm chart in a Git repository — A Chart.yaml exists at the specified path within a Git repo. ArgoCD detects Helm automatically and renders it.
Common Helm-specific fields in the Application spec:
helm.values/helm.valuesFiles: inline values or references to values files in the repo.helm.parameters: individual key=value overrides (equivalent to--set).helm.releaseName: override the Helm release name (defaults to the Application name).helm.version: force Helm v2 or v3 (v3 is default).
Importantly, ArgoCD uses Helm purely as a templating engine — it renders the chart to Kubernetes manifests and then applies them with kubectl apply. The Helm release is not stored in a Helm Secret in the cluster; this means helm list won't show ArgoCD-managed charts, and helm upgrade/rollback commands should not be used alongside ArgoCD.
ArgoCD has native Kustomize support built into its Repository Server. When ArgoCD detects a kustomization.yaml (or kustomization.yml / Kustomization) file at the specified path, it automatically runs kustomize build to render the manifests before applying them to the cluster.
No extra configuration is needed beyond pointing the Application's source.path at a Kustomize directory:
source:
repoURL: https://github.com/my-org/app
targetRevision: HEAD
path: k8s/overlays/productionKustomize-specific overrides available in the Application spec:
kustomize.images: override image names and tags without modifying the repo (useful with ArgoCD Image Updater).kustomize.namePrefix/nameSuffix: prepend or append a string to all resource names.kustomize.commonLabels: inject labels into all resources at sync time.kustomize.version: pin the Kustomize binary version used for rendering.
A typical project structure with Kustomize and ArgoCD uses a base/ directory containing shared manifests and overlays/ directories per environment. Each overlay's kustomization.yaml references the base and applies environment-specific patches. ArgoCD Applications target the overlay path, so each environment gets its own Application pointing to its own overlay — giving full environment isolation with shared base configuration.
Self-healing in ArgoCD means that when the live cluster state drifts from the desired Git state — due to manual changes, operator mistakes, or other controllers modifying resources — ArgoCD automatically detects the drift and re-applies the Git state to bring the cluster back into sync, without any human intervention.
Self-healing is distinct from simply enabling automated sync. Automated sync fires when Git changes (a new commit is detected). Self-healing fires when the cluster changes while Git stays the same. Together they cover both directions of drift.
Enable self-healing in the Application's syncPolicy:
syncPolicy:
automated:
selfHeal: true
prune: true # also enable pruning if you want deleted Git resources removedWith selfHeal: true, the Application Controller compares live state against Git state every time a watch event fires from the Kubernetes API (near-real-time). When it detects OutOfSync, it immediately triggers a sync to restore the desired state.
A practical example: if an engineer runs kubectl scale deployment my-app --replicas=0 in production, ArgoCD with selfHeal enabled will detect the replica count change within seconds and restore replicas to the count defined in Git.
Self-healing should be combined with Sync Windows if you want to restrict when auto-corrections can occur (e.g., only during business hours or excluding a maintenance window).
ArgoCD's automated sync and self-healing are related but address different triggers for bringing a cluster into alignment with Git. They are configured together under syncPolicy.automated but serve distinct purposes.
| Aspect | Automated Sync | Self-Healing |
|---|---|---|
| Trigger | A new commit is detected in the tracked Git branch | The live cluster state changes while Git stays the same (drift) |
| Direction of change | Git changed → apply to cluster | Cluster changed → revert to Git |
| Config field | automated: {} (just enabling automated is enough) | automated: { selfHeal: true } |
| Typical scenario | Developer pushes a new image tag to Git; ArgoCD deploys it automatically | Operator manually scales a Deployment; ArgoCD restores the original replica count |
If you enable automated sync without selfHeal, ArgoCD will deploy new Git commits automatically but will ignore manual cluster changes until the next Git commit triggers a re-sync. With selfHeal added, both directions of drift are continuously corrected.
In practice, most production teams enable both together: automated: { prune: true, selfHeal: true }. The exception might be a team that wants operators to be able to temporarily scale resources manually without ArgoCD overriding them — in that case, selfHeal should remain disabled.
Resource pruning in ArgoCD refers to the automatic deletion of Kubernetes resources that exist in the cluster but are no longer present in the Git repository. When you sync an application with pruning enabled, ArgoCD compares the live cluster state against the desired Git state and removes any resources that have been deleted from Git.
By default, pruning is disabled. You enable it per sync operation via the CLI (argocd app sync <app> --prune) or by setting syncPolicy.automated.prune: true in the Application manifest for fully automated flows.
| Aspect | Detail |
|---|---|
| Accidental deletion | A mistaken removal from Git triggers permanent cluster deletion; rollback requires re-adding the resource and syncing. |
| Out-of-band resources | Resources created manually or by other controllers outside Git are pruned if ArgoCD tracks the namespace. |
| Cascading deletes | Pruning a parent resource (e.g., a Namespace) can cascade-delete child resources even if the children are still needed. |
| Finalizer loops | Resources with deletion finalizers may block sync and leave the application in a degraded state. |
To mitigate risk, use the argocd.argoproj.io/managed-by label carefully and consider combining pruning with Sync Windows to limit when automated pruning can fire. The PruneLast=true sync option instructs ArgoCD to delete resources only after all other sync steps complete successfully, reducing mid-sync inconsistency.
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- PruneLast=true
The App of Apps pattern is an ArgoCD design where one root Application manifest manages a collection of child Application manifests stored in Git. The root app syncs a directory of Application CRDs into the cluster; ArgoCD then picks up each child Application and reconciles it independently.
Structurally, the root application points to a Git path containing files like apps/frontend.yaml, apps/backend.yaml, each of which is itself an ArgoCD Application resource targeting its own source repo and destination namespace.
# root-app.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: root-app
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/my-org/infra
targetRevision: HEAD
path: apps/
destination:
server: https://kubernetes.default.svc
namespace: argocd
syncPolicy:
automated:
prune: true
selfHeal: trueWhen to use it: App of Apps is ideal for platform teams that want to onboard new services by simply adding a file to the apps/ directory in Git without touching ArgoCD UI or CLI. It also works well for multi-tenant setups where each tenant gets a dedicated child Application with its own project and RBAC.
Compared to ApplicationSets, App of Apps gives finer manual control over each child application but requires more boilerplate per application. ApplicationSets are preferred when child applications follow a repeatable template (e.g., one per cluster or one per Git directory). App of Apps shines when each child needs unique configuration that cannot be easily templated.
ArgoCD provides two complementary mechanisms for controlling the order of resource application during a sync: Sync Waves control the sequence of resource groups, and Sync Hooks inject one-off Jobs at specific lifecycle phases.
Sync Waves
Every resource can be assigned an integer wave via the annotation argocd.argoproj.io/sync-wave. Resources with lower wave numbers are applied first; ArgoCD waits for all resources in wave N to become healthy before advancing to wave N+1. The default wave is 0. Negative waves are useful for CRDs or Namespaces that must exist before other resources reference them.
metadata:
annotations:
argocd.argoproj.io/sync-wave: "-1" # Namespace first
---
metadata:
annotations:
argocd.argoproj.io/sync-wave: "0" # Default: Deployments, Services
---
metadata:
annotations:
argocd.argoproj.io/sync-wave: "1" # Last: Ingress or smoke-test JobSync Hooks
Hooks are Kubernetes resources (usually Jobs) annotated with argocd.argoproj.io/hook. Available hook phases:
| Hook Phase | When it runs |
|---|---|
| PreSync | Before any resources are applied (e.g., database migrations) |
| Sync | During the sync alongside other resources |
| PostSync | After all resources are healthy (e.g., smoke tests, notifications) |
| SyncFail | Only when the sync fails (e.g., rollback alerting job) |
Waves and hooks compose naturally: a PreSync hook runs before wave -1, and a PostSync hook runs after the highest wave reaches healthy. Use argocd.argoproj.io/hook-delete-policy to clean up completed hook Jobs automatically.
An ApplicationSet is an ArgoCD CRD that automates the creation, update, and deletion of multiple Application resources from a single template. Instead of manually writing one Application manifest per environment or cluster, you define a template once and pair it with a generator that produces parameter sets used to fill the template. The ApplicationSet controller manages these generated Applications automatically.
Git Generator
The Git generator has two modes:
- Directories mode: scans a repo for directories matching a glob; each matching directory becomes one Application with
pathset to that directory. - Files mode: reads JSON/YAML config files matching a pattern; each file's key-value pairs are passed as parameters into the template.
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: cluster-apps
namespace: argocd
spec:
generators:
- git:
repoURL: https://github.com/my-org/infra
revision: HEAD
directories:
- path: apps/*
template:
metadata:
name: "{{path.basename}}"
spec:
project: default
source:
repoURL: https://github.com/my-org/infra
targetRevision: HEAD
path: "{{path}}"
destination:
server: https://kubernetes.default.svc
namespace: "{{path.basename}}"
syncPolicy:
automated:
prune: trueWhen a new directory apps/payments is pushed to Git, the controller automatically creates an Application named payments — no manual ArgoCD intervention needed. Removing the directory triggers deletion of the generated Application when pruning is enabled on the ApplicationSet.
ArgoCD deliberately does not manage secrets natively — it stores no sensitive values and recommends keeping plaintext secrets out of Git. Two widely adopted patterns bridge ArgoCD with secret management:
1. Sealed Secrets (Bitnami)
Sealed Secrets encrypts a Kubernetes Secret into a SealedSecret CRD safe to commit to Git. The sealed-secrets-controller decrypts it back into a standard Secret using a cluster-side private key. From ArgoCD's perspective, a SealedSecret is just another manifest to sync.
kubeseal --fetch-cert > pub-cert.pem
kubectl create secret generic db-pass --from-literal=password=s3cr3t \
--dry-run=client -o yaml | kubeseal --cert pub-cert.pem -o yaml > sealed-db-pass.yaml
# Commit sealed-db-pass.yaml to Git; ArgoCD syncs it; controller decrypts2. External Secrets Operator (ESO)
ESO introduces ExternalSecret and SecretStore CRDs. You commit these CRDs (which contain no secret values — only references like Vault paths or AWS Secrets Manager ARNs) to Git. ArgoCD syncs them; ESO fetches actual values from the external provider and creates a native Kubernetes Secret.
| Dimension | Sealed Secrets | ESO |
|---|---|---|
| Secret storage | Encrypted ciphertext in Git | External vault; only references in Git |
| Rotation support | Manual re-seal required | Automatic via refreshInterval |
| Multi-provider | No (cluster key only) | Yes (Vault, AWS, GCP, Azure, etc.) |
ArgoCD's RBAC is configured via the argocd-rbac-cm ConfigMap in the argocd namespace. Policies are written in Casbin CSV format and map subjects (users, groups, SSO claims) to resources and actions.
Built-in Roles
| Role | Permissions |
|---|---|
role:readonly | Read-only access to all resources: applications, clusters, repositories, and logs. Cannot sync, create, update, or delete. |
role:admin | Full access to all resources and actions across all projects. |
Custom Policy Syntax
Policy lines follow: p, <subject>, <resource>, <action>, <object>, allow|deny. Group-to-role bindings use: g, <group>, <role>.
# argocd-rbac-cm data
policy.default: role:readonly
policy.csv: |
p, role:dev-team, applications, sync, staging/*, allow
p, role:dev-team, applications, sync, production/*, deny
p, role:dev-team, applications, get, */*, allow
g, my-org:developers, role:dev-teamResources include: applications, clusters, repositories, projects, accounts, logs. Actions include get, create, update, delete, sync, override, action.
ArgoCD Projects add a second scoping layer — RBAC controls who can do what, while Projects control what Applications are allowed to target (repos, clusters, namespaces).
ArgoCD Image Updater is an optional add-on controller that monitors container registries for new image tags and automatically updates the image tag references used by ArgoCD Applications — without requiring a CI pipeline to commit changes back to Git manually.
Image Updater watches Applications annotated with argocd-image-updater.argoproj.io/image-list. On each poll cycle it queries the container registry, determines the newest tag satisfying the configured update strategy, then updates the Application's image either by writing a commit back to Git (git write-back mode) or patching the Application's parameter overrides directly in ArgoCD (in-cluster mode).
| Strategy | Behavior |
|---|---|
| semver | Picks the highest tag satisfying a semver constraint (e.g., ~1.2) |
| latest | Picks the most recently pushed tag by registry timestamp |
| digest | Tracks a mutable tag (e.g., latest) by its immutable SHA digest |
| name | Picks the lexicographically greatest tag name |
metadata:
annotations:
argocd-image-updater.argoproj.io/image-list: myapp=docker.io/myorg/myapp
argocd-image-updater.argoproj.io/myapp.update-strategy: semver
argocd-image-updater.argoproj.io/myapp.allow-tags: regexp:^v[0-9]+\.[0-9]+\.[0-9]+$
argocd-image-updater.argoproj.io/write-back-method: gitIn git write-back mode, Image Updater commits the updated image tag to a dedicated branch or the tracked branch, creating a full audit trail in Git. ArgoCD then detects the commit and syncs normally, preserving GitOps principles.
ArgoCD is designed to manage applications across multiple Kubernetes clusters from a single control plane. Each cluster is registered with the ArgoCD API server and stored as a Secret in the argocd namespace with the label argocd.argoproj.io/secret-type: cluster.
Two Methods for Registering Clusters
1. CLI (argocd cluster add) — The most common method. The CLI reads your local kubeconfig, creates a ServiceAccount and ClusterRoleBinding in the target cluster, then stores the credentials as a Secret in ArgoCD:
kubectl config use-context my-prod-cluster
argocd cluster add my-prod-cluster --name production2. Declarative (Secret manifest) — For GitOps-managed ArgoCD deployments, you can commit a cluster Secret directly:
apiVersion: v1
kind: Secret
metadata:
name: prod-cluster-secret
namespace: argocd
labels:
argocd.argoproj.io/secret-type: cluster
type: Opaque
stringData:
name: production
server: https://prod-k8s-api.example.com
config: |
{
"bearerToken": "<token>",
"tlsClientConfig": { "insecure": false, "caData": "<base64-ca>" }
}The in-cluster cluster (https://kubernetes.default.svc) is always available without registration — ArgoCD uses its own service account to access it. For external clusters, the ArgoCD application controller makes API calls to the registered cluster endpoint using the stored credentials.
In practice, tools like the ArgoCD Cluster Generator (part of ApplicationSets) can dynamically register and manage Applications across all clusters registered as Secrets.
ArgoCD Sync Windows are time-based rules that allow or deny automated sync operations during specific time periods. They give platform teams the ability to prevent ArgoCD from automatically deploying changes during critical periods (e.g., business hours for production, or during a maintenance freeze) or to restrict deployments to specific allowed windows (e.g., only during off-peak hours).
Sync Windows are configured at the AppProject level and apply to all Applications in that Project. Each window has four properties:
- kind:
allowordeny— whether this window permits or blocks sync. - schedule: a cron expression (e.g.,
0 22 * * *for 10 PM daily). - duration: how long the window lasts (e.g.,
2h). - applications / namespaces / clusters: optional filters to apply the window to specific targets.
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
name: production
namespace: argocd
spec:
syncWindows:
- kind: deny
schedule: "* * * * 1-5" # deny all day Mon-Fri
duration: 24h
applications:
- "*"
- kind: allow
schedule: "0 22 * * 5" # allow Friday at 10 PM
duration: 4h
applications:
- "*"When a deny window is active, ArgoCD marks the Application as SyncWindowDenied and automated sync is blocked. Manual sync is also blocked unless the Application has the manualSync flag enabled in the window definition, which lets operators override in emergencies.
The ignoreDifferences field in an ArgoCD Application spec tells ArgoCD to exclude specific fields from the diff calculation between the desired Git state and the live cluster state. Without it, any field that differs — even one managed by Kubernetes controllers or admission webhooks — causes the Application to show as OutOfSync.
Common scenarios requiring ignoreDifferences:
- Kubernetes controllers that mutate resources after creation (e.g., the HPA controller adding
status, or the API server injectingcreationTimestamp: null). - Admission webhooks that inject sidecar containers or default annotations.
- Fields deliberately managed outside Git (e.g.,
replicaswhen using an HPA — you don't want ArgoCD overwriting the HPA-managed replica count with the static Git value).
ignoreDifferences:
- group: apps
kind: Deployment
jsonPointers:
- /spec/replicas # HPA manages this; ignore Git's static value
- group: "*"
kind: "*"
managedFieldsManagers:
- kube-controller-manager
- helm-operatorYou can scope ignoreDifferences to specific resource groups/kinds and use JSON pointers for field-level precision, or use managedFieldsManagers to ignore all fields last-written by a specific field manager. The RespectIgnoreDifferences sync option extends this further — not only does ArgoCD ignore the diff, it also skips overwriting those fields during sync, letting external controllers retain full ownership.
ArgoCD evaluates the health of every managed Kubernetes resource using health check scripts written in Lua. For built-in resource types (Deployments, StatefulSets, DaemonSets, Services, Ingresses, PVCs, Jobs, CronJobs, etc.), ArgoCD ships with health checks out of the box. For Custom Resource Definitions (CRDs), ArgoCD returns Unknown health unless you provide a custom Lua script.
A Lua health check script receives the live resource object and must return a hs table with at least two fields: status (one of Healthy, Progressing, Degraded, Suspended) and message (a human-readable explanation).
Custom health checks are registered in the argocd-cm ConfigMap under the resource.customizations.health key:
# argocd-cm ConfigMap
data:
resource.customizations.health: |
certmanager.k8s.io/Certificate: |
hs = {}
if obj.status ~= nil then
if obj.status.conditions ~= nil then
for i, condition in ipairs(obj.status.conditions) do
if condition.type == "Ready" and condition.status == "True" then
hs.status = "Healthy"
hs.message = "Certificate is ready"
return hs
end
end
end
end
hs.status = "Progressing"
hs.message = "Waiting for certificate to become ready"
return hsThe Lua sandbox in ArgoCD is restricted — it has no network access, file I/O, or most standard library functions. You work with the resource object (as a Lua table) and the hs return table only. This makes health checks fast and safe but requires understanding Lua table syntax for navigating nested JSON-like structures.
ArgoCD supports Single Sign-On (SSO) through two integration paths: built-in Dex (bundled OpenID Connect identity broker) and external OIDC providers (configured directly in argocd-cm without Dex).
Built-in Dex
Dex acts as an OIDC proxy that federates authentication to upstream identity providers. You configure connectors in the argocd-cm ConfigMap under the dex.config key. Dex supports: GitHub/GitHub Enterprise (OAuth), GitLab, LDAP, SAML 2.0, Microsoft (Azure AD), Google, and any generic OIDC provider.
# argocd-cm
data:
dex.config: |
connectors:
- type: github
id: github
name: GitHub
config:
clientID: $dex-github-client-id
clientSecret: $dex-github-client-secret
orgs:
- name: my-orgExternal OIDC
If you already have an OIDC provider (Okta, Auth0, Keycloak, Azure AD with OIDC), you can bypass Dex entirely by configuring ArgoCD to accept tokens directly:
data:
oidc.config: |
name: Okta
issuer: https://my-org.okta.com
clientID: <client-id>
clientSecret: $oidc-client-secret
requestedScopes: [openid, profile, email, groups]After SSO is configured, groups from the identity provider are mapped to ArgoCD roles in the RBAC policy using g, <group-name>, <argocd-role> lines. This means managing ArgoCD access becomes a matter of IdP group membership rather than per-user ArgoCD configuration.
The ArgoCD CLI (argocd) is a command-line tool for interacting with the ArgoCD API Server. It is the primary interface for operators who prefer the terminal over the UI and is also used in CI/CD pipelines for triggering or waiting on syncs.
Before using the CLI, you must log in:
argocd login <argocd-server> --username admin --password <password>
# Use --grpc-web if behind an HTTP proxy or load balancerCommon day-to-day commands:
| Command | Purpose |
|---|---|
argocd app list | List all Applications with sync and health status |
argocd app get <app> | Show detailed status, sync info, and resource tree for an Application |
argocd app sync <app> | Trigger a sync; add --prune to allow pruning, --dry-run to preview |
argocd app wait <app> | Block until the Application reaches a target health/sync state (useful in CI) |
argocd app diff <app> | Show the diff between live cluster state and Git desired state |
argocd app rollback <app> <id> | Roll back to a specific sync history revision |
argocd app set <app> --helm-set key=val | Override Helm values at the Application level without changing Git |
argocd cluster list | List all registered clusters |
argocd proj list | List all AppProjects |
In CI/CD pipelines, the typical pattern is: build image → push image → update Git tag → argocd app wait <app> --health to block the pipeline until ArgoCD confirms the deployment is healthy.
ArgoCD and Flux are the two most popular GitOps tools for Kubernetes, and both implement the GitOps principles well. The key differences come down to architecture, UX, and ecosystem fit.
| Dimension | ArgoCD | Flux |
|---|---|---|
| Architecture | Centralized: one ArgoCD instance can manage multiple clusters from a control-plane cluster | Distributed: Flux agents run inside each managed cluster |
| UI | Rich web UI showing resource trees, sync status, diffs, and logs | No built-in UI; relies on CLI and external dashboards (Weave GitOps) |
| Multi-tenancy | AppProjects + RBAC built-in | Requires additional tooling or Flux Tenancy controllers |
| Notification system | ArgoCD Notifications (separate controller) | Flux Notification controller (built-in) |
| Image automation | ArgoCD Image Updater (separate add-on) | Flux Image Reflector + Automation controllers (built-in) |
| OCI artifacts | Supported (Application source) | Supported (OCIRepository source) |
| Secret management | External tools (Sealed Secrets, ESO) | External tools (SOPS native support built-in) |
Choose ArgoCD when: you want a rich UI, centralized multi-cluster management from a single pane, and strong built-in RBAC with AppProjects. It is often preferred by platform teams managing many teams and clusters through one control plane.
Choose Flux when: you prefer a CLI-first, lightweight approach with no central control-plane dependency, want native SOPS secret encryption, or are building a distributed multi-cluster setup where each cluster is fully self-contained.
Server-side apply (SSA) is a Kubernetes API feature (GA since Kubernetes 1.22) where the API server — rather than the client — merges resource updates and tracks field ownership via managed fields. ArgoCD can use SSA instead of its default client-side apply (kubectl apply) by setting the ServerSideApply=true sync option.
With the default client-side apply, ArgoCD computes the three-way merge on the client using the last-applied-configuration annotation. This can cause conflicts when multiple tools (e.g., ArgoCD and a Helm operator) modify the same resource, or when large resources exceed the annotation size limit (generally ~256KB).
Benefits of enabling SSA in ArgoCD:
- Field ownership tracking: The API server knows which field manager last set each field, enabling clean conflict detection and resolution without the last-applied annotation hack.
- No annotation size limits: Large resources (e.g., CRDs with huge schemas, ConfigMaps with large data) no longer hit the 256KB annotation ceiling.
- Better multi-manager coexistence: ArgoCD can own some fields while another controller owns others, without either overwriting the other's fields on each apply.
- CRD-friendly: Works better with CRDs that have complex structural schemas.
syncOptions:
- ServerSideApply=trueThe trade-off: SSA errors are sometimes harder to interpret than client-side apply errors, and not all Kubernetes versions or configurations handle all edge cases identically. It is worth enabling for complex resources or when you hit annotation size limits.
ArgoCD Notifications is a separate controller (shipped as part of the ArgoCD Helm chart and optionally in the install manifest) that sends alerts and messages when ArgoCD Application events occur. It subscribes to Application state changes and triggers configured notification services when conditions are met.
The notification system has three components:
- Triggers: conditions that activate a notification (e.g.,
on-sync-succeeded,on-health-degraded,on-sync-failed). You can also write custom trigger expressions. - Templates: message content rendered as text or structured blocks (Slack attachments, email HTML). Templates use Go template syntax and have access to the Application object.
- Services: the channels where messages are sent. Configured in a Secret (
argocd-notifications-secret) and a ConfigMap (argocd-notifications-cm).
Supported notification channels include: Slack, Microsoft Teams, Email (SMTP), PagerDuty, OpsGenie, GitHub (commit status), Bitbucket, Grafana annotations, Rocketchat, Telegram, Webhook (generic HTTP), and more via community contributions.
# Subscribe an Application to a notification
metadata:
annotations:
notifications.argoproj.io/subscribe.on-sync-failed.slack: my-deployments-channel
notifications.argoproj.io/subscribe.on-health-degraded.pagerduty: "true"Subscriptions are set as annotations on the Application resource. This means different teams can subscribe their applications to different channels without central coordination, and the configuration lives in Git alongside the Application manifest.
ArgoCD stores a history of every sync operation for each Application, including the Git commit SHA, parameters, and manifests that were applied. Rolling back means telling ArgoCD to re-sync the Application to a specific previous revision from this history, overriding the current HEAD of the tracked branch.
Rollback via CLI
# View sync history
argocd app history my-app
# Roll back to history ID 3
argocd app rollback my-app 3Rollback via UI
In the ArgoCD UI, navigate to the Application → History and Rollback tab. Each entry shows the commit SHA, time, and initiator. Click Rollback on any row to restore that state.
Important caveats:
- A rollback puts the Application into an
OutOfSyncstate relative to the current Git HEAD, because the cluster is now running a different revision than what Git currently says. - If automated sync or self-healing is enabled, ArgoCD will immediately re-sync back to HEAD after the rollback, undoing it. You must disable automated sync before rolling back if you want the rollback to persist.
- The GitOps-native alternative to rollback is to revert the Git commit — this preserves the audit trail and lets ArgoCD sync forward to the reverted state rather than syncing backward.
History retention is configurable via server.app.revision.history.limit in argocd-cm (default is 10 revisions).
The ArgoCD Repository Server caches rendered manifests to avoid redundant Git clones and template renders on every reconciliation cycle. Understanding this cache is important for diagnosing stale manifest issues and tuning performance at scale.
What is cached:
- Rendered manifests keyed by
(repoURL, targetRevision, path, applicationSourceType, parameters). If all these inputs are identical to a previous render, the cached output is returned without re-runninghelm templateorkustomize build. - Git repository metadata (refs, commit SHAs) to avoid repeated
git ls-remotecalls. - The actual git clone is reused as a local cache on disk within the repository server pod.
Cache storage: By default, rendered manifest cache is stored in Redis. The default TTL is 24 hours. When Redis is unavailable, the repo server falls back to re-rendering on every request.
Cache invalidation: The cache is invalidated when any of the cache key components change — primarily when a new commit is pushed (changing the resolved SHA for HEAD). Webhook delivery from Git accelerates this by immediately triggering a refresh without waiting for the 3-minute poll cycle.
Configurable limits:
# argocd-cm
data:
reposerver.parallelism.limit: "10" # max parallel manifest generations
timeout.reconciliation: 180s # how often apps are reconciledAt large scale (hundreds of applications), the repository server becomes a bottleneck. Horizontal scaling is possible — you can run multiple repo server replicas behind a load balancer. Combine this with reposerver.parallelism.limit tuning to prevent OOM from concurrent Helm renders.
