Argo CD
Argo CD is the declarative GitOps continuous-delivery controller for Kubernetes: it runs inside your cluster, watches a Git repository for the manifests you say should be running, and never stops comparing that desired state against what is actually live — showing you the diff in a web UI and, if you let it, correcting reality automatically. It solves the platform problem of “nobody can tell me what is deployed where, or who changed it” by turning deployment from an action a human performs into a state a repository declares.
Imagine a huge LEGO city a hundred kids build together. Argo CD is the patient caretaker who keeps the instruction booklet on a shelf everyone can see. Every minute it walks the city, booklet in hand: “page 12 says a red tower — yep. Page 13 says a bridge — hmm, someone took the bridge apart.” It shows a big board with green ticks for what matches and orange marks for what doesn’t, and if you flip the “fix it yourself” switch, it quietly rebuilds the bridge. To change the city, you don’t move bricks — you edit the booklet.
What Argo CD is and the problem it solves
☺ Like you’re 10: It’s a robot living in your cluster whose only job is to make the cluster look exactly like a folder in Git.
Argo CD is a CNCF graduated project and the most widely deployed implementation of the GitOps pull model — a Kubernetes controller plus a UI, installed into a namespace (conventionally argocd). You give it a Git repository and a folder inside it; it renders whatever it finds there — plain YAML, a Kustomize overlay, or a Helm chart — into Kubernetes objects, compares them to the live objects, and reports a verdict.
The problem before Argo CD
Push-based delivery — a CI job holding a kubeconfig and running kubectl apply or helm upgrade — creates three durable headaches. CI needs long-lived cluster credentials, which makes the pipeline a juicy target. Nothing detects drift between merges. And there is no authoritative answer to “what is supposed to be running in prod?” — only a scroll through pipeline logs. Argo CD collapses all three: credentials stay inside the cluster, drift is detected continuously, and the repo is the answer.
The Application as the unit of delivery
Argo CD’s central idea is that a deployable thing is a custom resource called an Application. It is a three-part sentence: source (which repo, which path, which revision), destination (which cluster, which namespace), and project (which tenancy boundary it lives under). Everything else — automation, pruning, ordering, difference-ignoring — is policy hung off that sentence. Because the Application is itself a Kubernetes object, you can put Applications under Git too — the “app-of-apps” trick you meet below.
Argo CD keeps no external database. Its state lives in Kubernetes: Application, AppProject and ApplicationSet custom resources, plus Secrets holding repo and cluster credentials. Redis is a cache — delete the Redis pod and Argo CD is slow for a minute while it recomputes, but nothing is lost. That is why Argo CD itself is easy to make disposable.
What it is not
Argo CD is not a CI system: it does not build images or run tests — pair it with Tekton, Argo Workflows or a hosted CI. It is not a progressive-delivery engine either: canaries and blue/green belong to Argo Rollouts (or Flagger), which Argo CD happily syncs and reports health for. And it is not a secret manager — see Secrets Management and External Secrets Operator for the reference-in-Git, plaintext-never pattern.
Where it fits in a platform
☺ Like you’re 10: Argo CD sits between the “what we want” drawer and the real cluster, and it is the only thing allowed to open the cluster’s door.
In the layered platform model, Argo CD lives in the delivery plane: it consumes artefacts and config produced upstream and writes them into the Kubernetes substrate — deliberately as the only writer. Once a cluster is Argo-managed, a human kubectl apply is an exception that raises an alert, not a workflow.
Its neighbours
Upstream sits CI, which builds an image and commits a tag bump to the config repo. Beside Argo CD sit the renderers it invokes — Helm and Kustomize — and the policy engines that vet what it applies, Kyverno or OPA Gatekeeper, since admission control still runs on everything it sends. Downstream, Prometheus scrapes Argo CD’s metrics so you can alert on apps stuck OutOfSync or Degraded. And when Argo CD syncs Crossplane claims or Cluster API resources, the same loop provisions infrastructure and clusters, not just workloads.
Why platform teams reach for it
Two reasons dominate. The UI is a genuine developer-experience asset: teams see their own resource tree, diff and events without cluster credentials, killing a whole class of “can you check prod for me?” tickets. And ApplicationSet plus AppProject makes onboarding a team a directory creation rather than a ticket — the self-service moment.
CNPE domain relevance
Argo is named on the official CNPE tool list and lands squarely in GitOps & Continuous Delivery (25%) — one of the two joint-largest domains on the exam blueprint, alongside Platform APIs & Self-Service. It also brushes Platform Architecture & Infrastructure (it is the delivery control plane in nearly every reference design) and Security & Policy Enforcement (pull-based delivery, project-scoped RBAC, no cluster credentials in CI). Practise it against the GitOps practice tasks.
How it works — architecture and CRDs
☺ Like you’re 10: There are a few little helpers: one reads Git and turns it into instructions, one compares and fixes, one draws the website, and one remembers things quickly.
A standard install lays down a handful of workloads in the argocd namespace. Knowing which does what turns most Argo CD debugging into a two-minute job, because the logs you need are almost always in exactly one of them.
The components
The application-controller is Recon: it watches every Application, asks the repo-server for rendered manifests, compares them against live objects, computes health, and performs syncs. In the standard install it runs as a StatefulSet — remember that, because scaling it means sharding across clusters, and because kubectl get deploy -n argocd appears to be missing the most important workload. The repo-server clones repos and renders them; Helm templating and Kustomize builds execute here, so “my chart won’t render” bugs live in its logs. The API/UI server (argocd-server) serves the web UI and the gRPC/REST API the CLI uses, and enforces RBAC. Redis caches manifests and resource trees. Dex is the optional identity broker bridging to your OIDC provider (drop it and point argocd-cm straight at an OIDC issuer if you already have one). Current versions of the standard install also lay down the applicationset-controller and the notifications-controller.
The custom resources it introduces
Argo CD adds three CRDs in the argoproj.io group. Application is one deployable unit. AppProject is a tenancy boundary: which repos an app may come from, which cluster/namespace destinations it may target, which cluster-scoped kinds it may create, and which roles can act on it. ApplicationSet is a templating factory that generates Applications. All three normally live in the argocd namespace, though Applications may live elsewhere when the project explicitly allows it.
Configuration lives in ConfigMaps, not a config file
Everything about the installation itself is declarative too, which is why an Argo CD install is trivially GitOps-managed by a second Argo CD (or by itself). Four objects in the argocd namespace carry it: argocd-cm is the main ConfigMap — resource health customisations, resource exclusions, OIDC settings; argocd-rbac-cm holds the RBAC policy as CSV lines plus a policy.default fallback (commonly role:readonly); argocd-cmd-params-cm supplies command-line parameters to the individual components; and the argocd-secret Secret holds the server signing key, the admin password hash and TLS material.
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-rbac-cm
namespace: argocd
labels:
app.kubernetes.io/name: argocd-rbac-cm
app.kubernetes.io/part-of: argocd # the label the standard install stamps on its own objects
data:
policy.default: role:readonly # everyone can look, nobody can act, by default
policy.csv: |
p, role:payments-deploy, applications, sync, payments/*, allow
p, role:payments-deploy, applications, get, payments/*, allow
g, acme:payments-engineers, role:payments-deployThe grammar is worth memorising: p lines are permissions — subject, resource, action, object, effect — and g lines bind an SSO group to a role. The object for an application is <project>/<application>, which is what makes AppProject the real tenancy hinge rather than a label.
Sync status vs health status — two different questions
Beginners conflate these constantly, and the exam likes the distinction. Sync status answers “does the cluster match Git?” Health status answers “is the thing actually working?” An app can be perfectly Synced and thoroughly Degraded — you faithfully deployed a broken image.
| Status family | Value | Means |
|---|---|---|
| Sync | Synced | Live state matches the rendered desired state at targetRevision. |
OutOfSync | A difference exists — new commit not yet applied, or someone drifted the cluster. | |
Unknown | Argo CD could not compare — usually a repo it can’t reach or manifests it can’t render. | |
| Health | Healthy | All resources report ready per their health check (built-in for common kinds, Lua-scriptable for CRDs). |
Progressing | Still rolling out; not yet a failure. Deployments sit here during an update. | |
Degraded | A resource failed — crash-looping pods, failed Job, unavailable replicas. | |
Suspended | Intentionally paused, e.g. a suspended CronJob or a paused Rollout awaiting promotion. | |
Missing | Declared in Git but absent from the cluster. | |
Unknown | Health could not be assessed — no health check applies, or the comparison itself failed. |
“When a deploy looks weird I open the Argo CD app tile and read the two badges. Green-and-green, it’s not the deploy. Synced but Degraded means my code is the problem — Argo shipped my bug faithfully. OutOfSync means my merge hasn’t landed yet, so I go bother the pipeline, not the SRE.”
The resources you will actually write
☺ Like you’re 10: Here are the actual bits of YAML you type — one for an app, one for ordering the steps, one for a team’s sandbox, one for stamping out many apps at once.
Four manifests carry ninety percent of real Argo CD work. Type them until they come out of your fingers — they are on Know Cold for a reason.
An Application with a real sync policy
Note carefully: prune and selfHeal both default to false. Adding automated: {} gives you auto-sync on new commits but neither deletion of removed resources nor drift correction — a very common exam trap and a very common production surprise.
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: checkout-prod
namespace: argocd # Applications live in the Argo CD namespace
finalizers:
- resources-finalizer.argocd.argoproj.io # cascade-delete live resources with the App
spec:
project: payments # an AppProject, NOT a Kubernetes namespace
source:
repoURL: https://github.com/acme/platform-config.git
targetRevision: main # branch, tag, or commit SHA — pin prod to a tag/SHA
path: apps/checkout/overlays/prod # a Kustomize overlay; repo-server renders it
destination:
server: https://kubernetes.default.svc # in-cluster; or use `name:` for a registered cluster
namespace: checkout
syncPolicy:
automated:
prune: true # DEFAULT false — delete live resources removed from Git
selfHeal: true # DEFAULT false — revert out-of-band drift back to Git
allowEmpty: false # default; refuse to apply a render that produced zero resources
syncOptions:
- CreateNamespace=true # create spec.destination.namespace if absent
- ServerSideApply=true # SSA: better with large CRDs and shared field ownership
- PruneLast=true # delete removed resources only after everything else applied
retry:
limit: 5
backoff: { duration: 5s, factor: 2, maxDuration: 3m }
ignoreDifferences:
- group: apps
kind: Deployment
jsonPointers:
- /spec/replicas # let an HPA own replica count without causing OutOfSyncignoreDifferences is a scalpel, not a mute buttonEvery field you ignore is a field Git no longer governs. Ignoring /spec/replicas so an HPA can breathe is legitimate. Ignoring a whole spec because “it keeps going OutOfSync” hides a real conflict — usually a mutating webhook — and you rediscover it during an incident.
Ordering a sync: waves and hooks
A sync is not one big apply. Argo CD splits it into phases — PreSync, Sync, PostSync — and within a phase orders resources by sync wave, an integer annotation (negatives first, default 0). A wave must become healthy before the next starts. Hooks are ordinary resources — usually Jobs — annotated to run in a phase.
apiVersion: batch/v1
kind: Job
metadata:
name: db-migrate
annotations:
argocd.argoproj.io/hook: PreSync # run BEFORE the main apply
argocd.argoproj.io/hook-delete-policy: HookSucceeded # tidy up the Job when it passes
spec:
template:
spec:
restartPolicy: Never
containers:
- name: migrate
image: ghcr.io/acme/checkout-migrations:1.4.3
command: ["/app/migrate", "up"]
---
apiVersion: v1
kind: Namespace
metadata:
name: checkout
annotations:
argocd.argoproj.io/sync-wave: "-2" # namespaces and CRDs go early
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: checkout
annotations:
argocd.argoproj.io/sync-wave: "1" # after config, secrets and CRDs land
spec:
replicas: 3
selector:
matchLabels:
app.kubernetes.io/name: checkout # must match the pod template labels exactly
template:
metadata:
labels:
app.kubernetes.io/name: checkout
spec:
containers:
- name: checkout
image: ghcr.io/acme/checkout:1.4.3
ports:
- containerPort: 8080The hook annotation accepts PreSync, Sync, PostSync, SyncFail, PostDelete (run after the Application’s resources are deleted) and Skip (never apply this resource at all). Delete policies are HookSucceeded, HookFailed and BeforeHookCreation — the last being the default, which deletes the previous instance just before creating a new one so a re-run of a fixed-name Job does not collide. A PostSync smoke-test Job plus a SyncFail notifier Job is a tidy pattern worth stealing.
Two details that catch people out. A wave boundary is a health gate, not just an apply gate: Argo CD will not start wave n+1 until everything in wave n reports healthy, so a resource with no health check races ahead and one that never goes healthy stalls the sync until it times out. And waves are ordered within a phase — a PreSync hook always runs before every Sync-phase resource regardless of how negative that resource’s wave number is.
An AppProject for tenancy
Projects stop team A deploying into team B’s namespace, or creating cluster-scoped objects nobody approved. Treat them as the security boundary; see Governance & Compliance for the wider picture.
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
name: payments
namespace: argocd
spec:
description: Apps owned by the Payments team
sourceRepos:
- https://github.com/acme/platform-config.git # only this repo may be a source
destinations:
- server: https://kubernetes.default.svc
namespace: 'checkout*' # only namespaces matching this glob
clusterResourceWhitelist: [] # no cluster-scoped resources at all
namespaceResourceBlacklist:
- group: ''
kind: ResourceQuota # tenants may not rewrite their own quota
roles:
- name: deployer
policies:
- p, proj:payments:deployer, applications, sync, payments/*, allow
groups:
- acme:payments-engineers # mapped from your SSO groupsApplicationSet: one template, many apps
Hand-writing an Application per team per cluster stops scaling at about a dozen. Generators do the stamping: list (explicit items), git (one app per directory, or driven by JSON/YAML files in the repo), cluster (one per registered cluster), matrix (cross-product of two generators), merge (combine generators, later ones overriding parameters), SCM provider (one per repo in an org) and pull request (a preview environment per open PR). “Every app × every cluster” is the multi-cluster workhorse.
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: addons-everywhere
namespace: argocd
spec:
goTemplate: true
generators:
- matrix: # cross-product: each add-on × each cluster
generators:
- git:
repoURL: https://github.com/acme/platform-config.git
revision: main
directories:
- path: infrastructure/* # one entry per add-on folder
- clusters:
selector:
matchLabels: { env: prod } # only clusters labelled env=prod
template:
metadata:
name: '{{.path.basename}}-{{.name}}' # e.g. cert-manager-eu-west-1
spec:
project: platform
source:
repoURL: https://github.com/acme/platform-config.git
targetRevision: main
path: '{{.path.path}}'
destination:
server: '{{.server}}'
namespace: '{{.path.basename}}'
syncPolicy:
automated: { prune: true, selfHeal: true }
syncOptions: [ CreateNamespace=true ]The app-of-apps pattern is simpler than it sounds: write one Application whose path points at a folder full of other Application manifests. Argo CD syncs that folder, which creates the child Applications, which sync their own workloads. It bootstraps an entire cluster from a single kubectl apply. Reach for app-of-apps when the list is small and hand-curated, ApplicationSets when it should be generated.
Day-to-day commands
☺ Like you’re 10: A short list of things you type at the terminal to look at apps, push them, and undo them.
The argocd CLI talks to the API server, so log in first. Almost everything it does is also possible by editing the Application CR with kubectl — useful when the API server is what’s broken.
Install, log in, register
# Standard install (the manifest lives in the argo-cd GitHub repo)
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
kubectl -n argocd rollout status statefulset/argocd-application-controller
# The bootstrap admin password is generated into a Secret
kubectl -n argocd get secret argocd-initial-admin-secret \
-o jsonpath='{.data.password}' | base64 -d; echo
# Reach the API server without an Ingress, then log in
kubectl -n argocd port-forward svc/argocd-server 8080:443 &
argocd login localhost:8080 --username admin --insecure
# Register a private repo and an extra cluster
argocd repo add https://github.com/acme/platform-config.git --username git --password "$TOKEN"
argocd cluster add prod-eu-west-1 # uses the named kubeconfig contextCreate, inspect, diff
argocd app create checkout-prod \ --repo https://github.com/acme/platform-config.git \ --path apps/checkout/overlays/prod \ --revision main \ --dest-server https://kubernetes.default.svc \ --dest-namespace checkout \ --project payments \ --sync-policy automated --auto-prune --self-heal \ --sync-option CreateNamespace=true argocd app list # every app, with SYNC and HEALTH columns argocd app get checkout-prod # summary + per-resource tree argocd app diff checkout-prod # live vs desired; exits non-zero if it differs argocd app manifests checkout-prod # exactly what the repo-server rendered argocd app logs checkout-prod --tail 50 # pod logs for the app's workloads
argocd app diff returning a non-zero exit code when differences exist makes it a natural drift check in a scheduled CI job or a pre-merge gate.
Sync, wait, and undo
argocd app sync checkout-prod # apply desired state now argocd app sync checkout-prod --prune --dry-run # preview what pruning would delete argocd app sync checkout-prod --resource apps:Deployment:checkout # one resource only argocd app wait checkout-prod --health --timeout 300 # block until Healthy (great in pipelines) argocd app set checkout-prod --revision v1.4.3 # repoint at a tag argocd app history checkout-prod # numbered deployment history argocd app set checkout-prod --sync-policy none # rollback is refused while auto-sync is on argocd app rollback checkout-prod 12 # redeploy history entry 12 # Refresh vs hard refresh: re-compare, or re-clone and re-render first argocd app get checkout-prod --refresh argocd app get checkout-prod --hard-refresh
rollback is a temporary lieargocd app rollback redeploys a previous entry from the app’s deployment history — and Argo CD refuses to do it while automated sync is enabled, so you must turn automation off first. That is exactly the point: the moment you switch automation back on, Recon compares the app against Git again and cheerfully re-deploys the bad version. Rollback is incident response, not a fix. The real rollback is always a Git revert — see Release Engineering.
Gotchas and failure modes
☺ Like you’re 10: Here are the ways the tireless robot annoys people who haven’t met it before.
Self-heal fights the human
With selfHeal: true, a kubectl edit or kubectl scale on a managed resource is reverted within seconds. Engineers debugging under pressure find this maddening until someone explains it. The escape hatches, in order of preference: change Git; temporarily disable automation with argocd app set <app> --sync-policy none; or, for a planned experiment, add the resource to ignoreDifferences. Never disable self-heal cluster-wide to unblock one person — delivery triage has the decision tree.
Prune deletes things you meant to keep
Prune is symmetric with Git: remove the manifest, lose the resource. That is desirable — until someone moves a directory, renames a chart release, or an ApplicationSet generator briefly returns an empty list and a whole environment evaporates. Three guards: leave allowEmpty at its default of false and never flip it on to “fix” an empty render; annotate resources that must never be auto-deleted with argocd.argoproj.io/sync-options: Prune=false (PVCs holding data are the classic); and run --dry-run first on a busy cluster.
Immutable fields make an app OutOfSync forever
Some fields cannot be changed after creation: a Deployment’s spec.selector, a Job’s spec.template, a StatefulSet’s volumeClaimTemplates, a Service’s clusterIP. Change one in Git and every sync fails with a field is immutable error, leaving the app stuck OutOfSync while the error hides in the sync result. The fix is to replace rather than patch: argocd app sync <app> --replace, the Replace=true sync option, or the per-resource argocd.argoproj.io/sync-options: Replace=true annotation — all delete and recreate the object, so weigh the disruption. Better still, don’t mutate immutable fields.
The quieter operational traps
A few more, in the order you meet them. The application-controller is a StatefulSet, so kubectl get deploy -n argocd won’t show it and your “is Argo up?” check may lie. Big monorepos make the repo-server slow and memory-hungry — narrow the path, and add webhooks so Argo reacts to pushes instead of waiting for the default three-minute poll. Helm charts using lookup or random/time functions render differently every time, producing permanent meaningless drift. CRDs applied in the same wave as the custom resources that use them fail — put CRDs in an earlier wave. And an Application whose destination or repoURL the AppProject forbids fails with an error that reads like RBAC but is really a project problem. When stuck, open the troubleshooting playbook.
On a throwaway kind or minikube cluster: install Argo CD from the stable manifest and log in. Create an Application pointing at a public repo path with automated: {} only. Now kubectl scale the deployment by hand: Argo reports OutOfSync and does nothing — the default everyone forgets. Add selfHeal: true and scale again; reverted in seconds. Delete a manifest from your fork and confirm nothing is removed until you add prune: true. Finally add a PreSync hook Job that sleeps ten seconds and watch the phase ordering in the UI.
Alternatives and when to choose it
☺ Like you’re 10: Other robots can do this job too — here’s how to pick one.
The honest answer is that Flux and Argo CD are both excellent and both CNCF-graduated; the choice is about shape and team, not capability.
The comparison that decides it
| Option | Model | Best when | Costs you |
|---|---|---|---|
| Argo CD | Application-centric pull; one integrated product with a rich UI | Many app teams need visibility without cluster access; you want sync waves, hooks and a diff view out of the box | Heavier install; an extra RBAC/SSO surface; the UI can become a shadow control plane if people click Sync instead of merging |
| Flux | Composable toolkit of small controllers, API-first | Building bespoke platform primitives; you want built-in image automation and SOPS decryption, and only Kubernetes RBAC | No official UI, so developer visibility must be built or bought |
CI push (kubectl apply from a pipeline) | Push, at merge time only | One small cluster, one small team, nothing more needed | Cluster credentials in CI; no drift detection — fails OpenGitOps principles 3 and 4 |
| Helm/Kustomize alone | Renderers, not reconcilers | Always — they render for Argo CD or Flux | Alone they answer “what do these manifests look like?”, never “is the cluster still correct?” |
| Argo Rollouts / Flagger | Progressive delivery controllers | Alongside Argo CD, for canary or blue/green with automated analysis | Not a substitute — they change how a workload updates, not where desired state comes from |
A practical rule
Choose Argo CD when the platform’s customers are many application teams who benefit from seeing their own deployments; choose Flux when the platform team is composing its own APIs and values controllers over dashboards. Plenty of organisations run both — Flux for infrastructure add-ons, Argo CD for tenant workloads. See The Tool Landscape for how this sits among the other named projects, and CI/CD & Progressive Delivery for the pipeline half of the story.
Foxy: I turned on auto-sync last week and it still didn’t undo my hand-edit. Broken?
Benny: Working exactly as documented. automated on its own only syncs new commits. prune and selfHeal are both false by default — you have to ask for them.
Recon: BEEP. I saw the drift. I reported OutOfSync. Nobody gave me permission to act. I am a very well-behaved robot.
Gizmo: Just click Sync in the UI whenever prod looks wrong. Way faster than a pull request. 🤑
Timmy: And now the UI is the source of truth and Git is fiction. Clicking Sync is fine to accelerate what Git already says — never to deploy something Git doesn’t.
Dot: Honestly the resource tree is my favourite part. I can see my own pods going Progressing → Healthy without begging anyone for a kubeconfig.
Exam relevance and going further
☺ Like you’re 10: On exam day you can’t open Argo’s own website — so the YAML has to already be in your head.
“Argo” is on the official CNPE tool list and Argo CD is the most likely way a GitOps task is presented. Expect to install or inspect it, create or repair an Application, turn on the right sync policy, diagnose an OutOfSync or Degraded app, and explain the pull model.
The documentation allowlist — read this twice
During the CNPE the only documentation you may open is kubernetes.io/docs, kubernetes.io/blog, task-specific documentation explicitly linked in the exam’s Quick Reference box, and local man pages / /usr/share docs on the exam machine. argo-cd.readthedocs.io is not on that list. Unless a task’s Quick Reference hands you an Argo CD link, write the Application manifest from memory. Drill it from Know Cold — that page exists precisely for the manifests you cannot look up.
⚖ CNPA vs CNPE — That allowlist is a CNPE-specific mechanic; CNPA has no allowlist at all, because CNPA is fully closed-book — zero external resources, zero lookups of any kind, on anything. That’s stricter than CNPE, not looser. Even so, the Argo CD concepts on this page — the pull model, the sync/health distinction, ApplicationSet generators — are worth knowing cold, since this concept-level knowledge still matters for CNPA’s closed-book recall.
What to be able to do without notes
Write a valid Application from a blank file: apiVersion: argoproj.io/v1alpha1, kind: Application, the argocd namespace, the source/destination/project triple, prune and selfHeal (both default false), and CreateNamespace=true. Explain sync status versus health status and name the values of each. Name the components and say which renders Helm charts. Name four ApplicationSet generators. Say what an AppProject restricts. And know the CLI spine: argocd login, app create, get, diff, sync, set, wait, history, rollback — all in the command reference.
Official resources for after the exam
Outside the exam, the canonical sources are argo-cd.readthedocs.io (the Declarative Setup, Sync Options and ApplicationSet pages repay careful reading), the project site at argoproj.github.io/cd, the source at github.com/argoproj/argo-cd, and cncf.io/projects/argo. Pair this page with GitOps Workflows for the principles, Flux for the comparison, and the glossary when a term stops making sense.
1. Which Argo CD component renders a Helm chart into manifests, and which one applies them? 2. You set syncPolicy.automated: {} and nothing reverts a manual kubectl scale. Why, and what do you add? 3. An app shows Synced and Degraded — whose problem is it? 4. Your sync keeps failing with “field is immutable” on a Deployment. Name one fix and its cost. 5. Which ApplicationSet generator deploys every add-on folder to every production cluster? 6. During the exam, where can you look up the Application schema?
Check your answers
- The repo-server clones and renders (Helm, Kustomize, plain YAML); the application-controller diffs the result against live state and applies it. The application-controller runs as a StatefulSet.
pruneandselfHealboth default to false. Bareautomatedonly syncs new commits; addselfHeal: trueto revert drift (andprune: truefor deletions).- Yours, not the platform’s.
Syncedmeans Argo CD faithfully deployed what Git asked for;Degradedmeans the workload itself is unhealthy — a bad image, a crash loop, a failing probe. - Replace instead of patch:
argocd app sync <app> --replace, theReplace=truesync option, or the per-resourceargocd.argoproj.io/sync-options: Replace=trueannotation. The cost is that the object is deleted and recreated, which is disruptive — so prefer not to change immutable fields at all. - A matrix generator combining a git directory generator (one entry per add-on folder) with a cluster generator selecting production clusters.
- You can’t — Argo CD’s documentation is not on the exam allowlist (kubernetes.io/docs, kubernetes.io/blog, task-specific Quick Reference links, and local man/
/usr/sharedocs only). Write it from memory; drill it on Know Cold.