Argo CD Tutorial: 13 Steps, 55 Min on Kubernetes [2026]

Google · Preferred Sources

Don't miss new tech stories on Google

Add Tech Insider once in the Google app and our stories appear in your news suggestions.

Add Now

Why an Argo CD Tutorial Still Matters on Kubernetes 1.37

Argo CD is an open-source GitOps continuous delivery tool that watches a Git repository and keeps a Kubernetes cluster matching what it finds there, as the official Argo CD documentation explains. That single idea explains why platform teams adopted it. Git becomes the audit log, the review process and the rollback button for every change that reaches a cluster.

This Argo CD tutorial takes you through 13 steps in roughly 55 minutes. You will build a local Kubernetes cluster, install Argo CD, deploy an app from Git, scale it to several environments with an ApplicationSet, and finish with RBAC and alerts. Still weighing tools before you commit an hour? Our Argo CD vs Flux comparison covers the trade-offs in depth, and this guide assumes you already picked Argo CD.

Timing matters right now. As of October 29, 2026, the Kubernetes project supports three minor branches: 1.37, 1.36 and 1.35. Kubernetes 1.34 stopped receiving upstream patches on October 27, 2026, according to a DEV Community write-up, so any tutorial that still builds on 1.34 or older ships a cluster that nobody patches. On the Argo CD side, the newest stable release listed on the project’s GitHub releases page was v3.5.6, published October 20, 2026. A 3.6.0 release candidate (rc4) appeared two days later, on October 22. It is a prerelease, so keep it out of production.

Argo CD’s roadmap is also moving. CNCF coverage from July 2026 described the 3.5 release as an effort to make ApplicationSets first-class citizens, and a September 30, 2026 CNCF post said the Argo community had begun visioning work for Argo CD 4.0. None of that changes the workflow below. It does mean you should pin versions, read release notes before upgrades, and avoid tutorials that point at a moving stable tag.

Why bother with GitOps at all? In an interview on the Red Hat Technically Speaking podcast page, Chris Wright, identified there as Red Hat’s chief technology officer, put it this way: “GitOps is a set of practices to manage infrastructure and application configurations using Git as a single source of truth.” He added that the core principles require the desired state to be “expressed declaratively and that desired state is versioned and immutable, pulled automatically, and is continuously reconciled.” Argo CD implements exactly that loop.

By the end of the tutorial you will have these pieces running:

  • A local kind cluster that mirrors a real Kubernetes 1.37 or 1.36 environment
  • Argo CD installed from pinned manifests with a rotated admin password
  • A Git repository holding Kustomize manifests for a small web app
  • An AppProject that limits what Argo CD may deploy and where
  • An ApplicationSet that creates one Application per environment folder
  • Sync waves, a PostSync smoke test, a CI account with narrow RBAC and Slack alerts

Everything runs on a laptop with Docker, so the cost is $0 unless you move it to a managed cluster. A later section shows the AWS price math for that case.

Prerequisites and Versions You Need Before Starting

Install the tools below before you open a terminal for Step 1. The table lists what each one does and how strict the version requirement is. Where the table says “latest stable,” run the tool’s own version command and confirm it prints a recent release rather than something from 2024.

ToolVersion to useWhy you need it
Docker Engine or Docker DesktopCurrent stable releasekind runs each Kubernetes node as a container
kindLatest stable releaseCreates the local cluster in about 40 seconds
Kubernetes1.37 preferred, 1.36 or 1.35 also supported upstreamThe cluster Argo CD manages
kubectlWithin one minor version of the clusterTalks to the API server and applies manifests
argocd CLISame minor version as the server you installLogs in, syncs apps, manages tokens
GitAny 2.x releaseHolds the desired state
GitHub accountFree plan is enoughHosts the demo repository
Slack workspace (optional)Any plan that allows a bot tokenReceives sync and health alerts in Step 13

Two cautions apply. First, the kind node image decides your Kubernetes version. If you want 1.37 exactly, check kind’s release notes for the node image built for that version and pass it with --image. The default image may lag behind the upstream release. Second, keep kubectl within one minor version of the cluster, because the supported skew is one minor version in either direction.

You also need about 4 GB of free RAM for Docker and a terminal that can run background processes. On Windows, run every command inside WSL 2 with an Ubuntu distribution, since the shell snippets use Bash syntax. Budget 55 minutes if you type the commands yourself and 25 minutes if you copy them from the full project section near the end.

How Argo CD Works: Components and the Sync Loop

Argo CD runs entirely inside your cluster as a small group of controllers. Knowing what each piece does makes the troubleshooting section later in this guide far easier to follow.

  • argocd-server exposes the web UI, the API and the gRPC endpoint that the CLI uses.
  • argocd-repo-server clones Git repositories and renders manifests from Helm, Kustomize or plain YAML.
  • argocd-application-controller compares the rendered manifests with live cluster state and applies changes.
  • argocd-applicationset-controller generates Application objects from templates and generators.
  • argocd-notifications-controller sends messages to Slack, email, webhooks and other services.
  • argocd-redis caches state, and argocd-dex-server handles single sign-on connectors.

Three custom resources carry the configuration. An Application ties one Git path to one destination. An AppProject sets the guardrails, such as which repositories and namespaces an app may touch. An ApplicationSet stamps out many Applications from a generator, for example one per directory or one per cluster.

Argo CD tracks two separate statuses for every Application. Sync status says whether live state matches Git: Synced or OutOfSync. Health status says whether the resources actually work: Healthy, Progressing, Degraded or Missing. A Deployment can be perfectly Synced and still Degraded because the image will not pull. Keep that distinction in mind, because it is the root of half the confusion beginners report.

Drift detection is the feature that makes the pull model valuable. As Akuity’s explanation of Argo CD sync and drift detection describes, the controller keeps comparing live objects against the desired state, so a manual kubectl edit shows up as OutOfSync within moments. With selfHeal enabled, Argo CD reverts the change on its own. By default the repo server also polls Git about every three minutes, and you can cut that delay to seconds with a webhook, which Step 8 and the advanced tips cover.

Phase 1: Build the Cluster and the Git Repository (Steps 1-3)

Step 1: Install and verify the tooling

Install the command-line tools. On macOS or Linux with Homebrew, one command handles everything. On other systems, use each project’s install page, then confirm the versions.

# macOS or Linux with Homebrew
brew install kind kubectl argocd git

# Verify each tool answers
kind version
kubectl version --client
argocd version --client
docker info --format '{{.ServerVersion}}'

If docker info fails, start Docker Desktop or the Docker daemon first. kind cannot create nodes without it.

Step 2: Create the kind cluster

Create a single-node cluster named gitops. One node is enough for this tutorial, and it keeps memory use near 2 GB.

kind create cluster --name gitops
kubectl cluster-info --context kind-gitops
kubectl get nodes

A healthy result looks like the output below. The version column shows whichever Kubernetes release your kind node image carries, so it may read 1.37 or a neighboring minor version.

NAME                   STATUS   ROLES           AGE   VERSION
gitops-control-plane   Ready    control-plane   42s   v1.37.x

If you do not have a cluster of your own yet and want a longer walkthrough of how clusters are put together, see our guide to building a Kubernetes cluster in 13 steps.

Step 3: Create the Git repository with Kustomize manifests

Create a public GitHub repository named gitops-demo. A public repo needs no credentials, which keeps the first run simple. Step 6 shows how to register a private one. Then build this layout locally:

gitops-demo/
  apps/web/base/
    configmap.yaml
    deployment.yaml
    service.yaml
    smoke-test.yaml
    kustomization.yaml
  apps/web/overlays/dev/kustomization.yaml
  apps/web/overlays/staging/kustomization.yaml
  argocd/
    project.yaml
    applicationset.yaml

Start with the base manifests. The ConfigMap, Deployment and Service describe a tiny nginx app. The ConfigMap and Service carry sync-wave annotations that Step 11 explains, so add them now and save a later commit.

# apps/web/base/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: web-config
  annotations:
    argocd.argoproj.io/sync-wave: "-1"
data:
  MESSAGE: "hello from git"
# apps/web/base/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: web
  template:
    metadata:
      labels:
        app.kubernetes.io/name: web
    spec:
      containers:
        - name: nginx
          image: nginx:stable-alpine
          ports:
            - containerPort: 80
          envFrom:
            - configMapRef:
                name: web-config
          readinessProbe:
            httpGet:
              path: /
              port: 80
          resources:
            requests:
              cpu: 25m
              memory: 32Mi
            limits:
              memory: 64Mi
# apps/web/base/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: web
  annotations:
    argocd.argoproj.io/sync-wave: "1"
spec:
  selector:
    app.kubernetes.io/name: web
  ports:
    - port: 80
      targetPort: 80

Next, the PostSync smoke test. Argo CD runs this Job after every successful sync and deletes it when it passes, so a failed check surfaces immediately in the UI.

# apps/web/base/smoke-test.yaml
apiVersion: batch/v1
kind: Job
metadata:
  name: web-smoke-test
  annotations:
    argocd.argoproj.io/hook: PostSync
    argocd.argoproj.io/hook-delete-policy: HookSucceeded
spec:
  backoffLimit: 0
  template:
    spec:
      restartPolicy: Never
      containers:
        - name: check
          image: busybox:stable
          command: ["sh", "-c", "wget -q -O /dev/null http://web:80 && echo smoke test passed"]

Finish with the kustomizations. The base lists its resources, and each overlay sets a namespace and a replica count.

# apps/web/base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - configmap.yaml
  - deployment.yaml
  - service.yaml
  - smoke-test.yaml
# apps/web/overlays/dev/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: web-dev
resources:
  - ../../base
patches:
  - target:
      kind: Deployment
      name: web
    patch: |-
      - op: replace
        path: /spec/replicas
        value: 1

Copy that file to apps/web/overlays/staging/kustomization.yaml, change the namespace to web-staging and set the replica value to 2. Then render locally to catch typos before Argo CD ever sees them, and push.

kubectl kustomize apps/web/overlays/dev | head -20

git init -b main
git add .
git commit -m "Add web app base and overlays"
git remote add origin https://github.com/YOUR_USER/gitops-demo.git
git push -u origin main

Replace YOUR_USER with your GitHub username everywhere it appears in this tutorial. The local render step is worth keeping as a habit. A manifest that fails kubectl kustomize will also fail inside the repo server, but the error there is harder to read.

Phase 2: Install Argo CD and Log In (Steps 4-6)

Step 4: Install Argo CD from pinned manifests

Pin the version. The install manifests live in the Argo CD repository under each release tag, so a variable keeps every later command consistent. At the time of writing the newest stable tag on the project’s releases page was v3.5.6, but check that page yourself and use whatever stable tag is current when you read this. Skip release candidates.

export ARGOCD_VERSION=v3.5.6

kubectl create namespace argocd
kubectl apply -n argocd --server-side --force-conflicts \
  -f https://raw.githubusercontent.com/argoproj/argo-cd/${ARGOCD_VERSION}/manifests/install.yaml

kubectl -n argocd rollout status deploy/argocd-server --timeout=180s
kubectl -n argocd get pods

The --server-side flag is not optional. Some Argo CD custom resource definitions are large enough that a client-side apply fails with an annotation size error. Server-side apply sidesteps the problem, and --force-conflicts lets you re-run the same command during upgrades.

Within a minute or two every pod should report Running. Your pod name suffixes will differ from the sample below.

NAME                                                READY   STATUS    RESTARTS   AGE
argocd-application-controller-0                     1/1     Running   0          78s
argocd-applicationset-controller-6b7d9c8f5d-x2k4q   1/1     Running   0          78s
argocd-dex-server-5c8d7b9f6-m9wzt                   1/1     Running   0          78s
argocd-notifications-controller-7f4d6c9b8-h6s2p     1/1     Running   0          78s
argocd-redis-64b8c7d5f9-q8v7n                       1/1     Running   0          78s
argocd-repo-server-68c9f7b5d4-t5r8j                 1/1     Running   0          78s
argocd-server-7d6b9c5f84-k3n6w                      1/1     Running   0          78s

Step 5: Log in and replace the admin password

Argo CD generates a random admin password on first install. Expose the API server with a port-forward, read the password with the CLI, and log in. The --insecure flag is acceptable here because the certificate is self-signed and the traffic never leaves your laptop.

kubectl -n argocd port-forward svc/argocd-server 8443:443 > /dev/null 2>&1 &

argocd admin initial-password -n argocd
argocd login localhost:8443 --username admin --insecure
argocd account update-password
kubectl -n argocd delete secret argocd-initial-admin-secret

Open https://localhost:8443 in a browser, accept the certificate warning and sign in as admin with your new password. The empty Applications screen is what you want to see. Deleting the initial secret afterward is good hygiene, because it holds the original password in plain text.

Never leave the port-forward as your long-term access method. For a shared cluster, put the server behind an Ingress or a Gateway API route with a real certificate, then restrict who can reach it. Our guide to deploying applications with Kubernetes and Helm shows a packaging approach that pairs well with this step when you move beyond a laptop.

Step 6: Create an AppProject and register the repository

The built-in default project allows any source and any destination. That is fine for a five-minute demo and dangerous everywhere else. Create a dedicated project that allows only your repository, only namespaces starting with web-, and only the Namespace kind at cluster scope.

# argocd/project.yaml
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
  name: demo
  namespace: argocd
spec:
  description: Demo apps for the GitOps tutorial
  sourceRepos:
    - https://github.com/YOUR_USER/gitops-demo.git
  destinations:
    - server: https://kubernetes.default.svc
      namespace: web-*
  clusterResourceWhitelist:
    - group: ""
      kind: Namespace
kubectl apply -f argocd/project.yaml
argocd proj get demo

If your repository is private, register credentials now. Use a fine-grained personal access token with read-only access to repository contents, and store it in an environment variable instead of typing it into your shell history.

argocd repo add https://github.com/YOUR_USER/gitops-demo.git \
  --username YOUR_USER \
  --password "$GITHUB_TOKEN"
argocd repo list

Phase 3: Deploy Your First Application (Steps 7-9)

Step 7: Create the web-dev Application declaratively

You can create Applications from the UI or the CLI, but a YAML manifest is reviewable and repeatable. This one points at the dev overlay, enables automated sync with pruning and self-healing, and asks Argo CD to create the target namespace.

# bootstrap/web-dev.yaml  (temporary, replaced in Step 10)
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: web-dev
  namespace: argocd
spec:
  project: demo
  source:
    repoURL: https://github.com/YOUR_USER/gitops-demo.git
    targetRevision: HEAD
    path: apps/web/overlays/dev
  destination:
    server: https://kubernetes.default.svc
    namespace: web-dev
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
      - CreateNamespace=true
kubectl apply -f bootstrap/web-dev.yaml
argocd app get web-dev
kubectl -n web-dev get all

The manifest deliberately omits the resources-finalizer.argocd.argoproj.io finalizer. Without it, deleting the Application leaves the deployed resources in place, which is exactly what Step 10 needs. Teams that want deletion to cascade add the finalizer back.

Expect output close to the following. Sync status reads Synced and health reads Healthy once the Deployment’s readiness probe passes and the PostSync smoke test completes.

Name:               argocd/web-dev
Project:            demo
Server:             https://kubernetes.default.svc
Namespace:          web-dev
URL:                https://localhost:8443/applications/web-dev
Repo:               https://github.com/YOUR_USER/gitops-demo.git
Target:             HEAD
Path:               apps/web/overlays/dev
Sync Policy:        Automated (Prune)
Sync Status:        Synced to HEAD (a1b2c3d)
Health Status:      Healthy

GROUP  KIND        NAMESPACE  NAME        STATUS  HEALTH   HOOK      MESSAGE
       ConfigMap   web-dev    web-config  Synced                     configmap/web-config created
       Service     web-dev    web         Synced  Healthy            service/web created
apps   Deployment  web-dev    web         Synced  Healthy            deployment.apps/web created

Step 8: Change Git and watch the cluster follow

Now prove the loop. Open apps/web/overlays/dev/kustomization.yaml, change the replica value from 1 to 2, commit and push. Argo CD notices within its polling interval, marks the app OutOfSync, and applies the change on its own.

git commit -am "Scale web-dev to 2 replicas"
git push

# Skip the polling wait by forcing a refresh
argocd app get web-dev --refresh
kubectl -n web-dev get deploy web

Next, test self-healing. Scale the Deployment by hand and watch Argo CD undo your change.

kubectl -n web-dev scale deploy/web --replicas=5
kubectl -n web-dev get deploy web -w

Within seconds the replica count drops back to 2. That is the pull model at work: the cluster is not allowed to disagree with Git. For instant reactions to pushes instead of the three-minute poll, add a GitHub webhook that points at https://YOUR_ARGOCD_HOST/api/webhook. It needs a publicly reachable Argo CD URL, so it does not work with the laptop port-forward.

Step 9: Test pruning and rollback

Pruning removes resources that disappear from Git. Delete the service.yaml line from the base kustomization.yaml, commit and push. After the next sync the Service vanishes from the cluster. Restore the line and push again to bring it back.

Rollback needs one extra detail. Argo CD blocks argocd app rollback while automated sync is enabled, because auto-sync would immediately re-apply Git’s version. You have two clean options. The better one is git revert followed by a push, which keeps Git as the source of truth. The other is to pause auto-sync, roll back, and investigate.

argocd app history web-dev

# Option 1 (preferred): revert in Git
git revert HEAD --no-edit && git push

# Option 2: pause auto-sync, roll back, then re-enable later
argocd app set web-dev --sync-policy none
argocd app rollback web-dev 2

Option 2 leaves the cluster running a version that Git no longer describes. Treat it as an emergency measure, and commit the fix or revert before you re-enable automation.

Phase 4: Scale Out With ApplicationSets and Sync Waves (Steps 10-11)

Step 10: Replace the single Application with an ApplicationSet

One Application per environment does not scale. An ApplicationSet watches your repository and creates an Application for every directory that matches a pattern. Add a new overlay folder, and a new Application appears with no further clicks. This is the feature the Argo CD maintainers have been investing in during the 3.5 cycle, so it is worth learning early.

# argocd/applicationset.yaml
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: web
  namespace: argocd
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
    - git:
        repoURL: https://github.com/YOUR_USER/gitops-demo.git
        revision: HEAD
        directories:
          - path: apps/web/overlays/*
  template:
    metadata:
      name: 'web-{{.path.basename}}'
    spec:
      project: demo
      source:
        repoURL: https://github.com/YOUR_USER/gitops-demo.git
        targetRevision: HEAD
        path: '{{.path.path}}'
      destination:
        server: https://kubernetes.default.svc
        namespace: 'web-{{.path.basename}}'
      syncPolicy:
        automated:
          prune: true
          selfHeal: true
        syncOptions:
          - CreateNamespace=true

The old Application and the generated one share the name web-dev, so delete the manual version first. Because it has no finalizer, the running resources stay in place and the new Application adopts them.

kubectl -n argocd delete application web-dev
git add argocd/applicationset.yaml && git commit -m "Add web ApplicationSet" && git push
kubectl apply -f argocd/applicationset.yaml
argocd app list
NAME                CLUSTER                         NAMESPACE    PROJECT  STATUS  HEALTH   SYNCPOLICY
argocd/web-dev      https://kubernetes.default.svc  web-dev      demo     Synced  Healthy  Auto-Prune
argocd/web-staging  https://kubernetes.default.svc  web-staging  demo     Synced  Healthy  Auto-Prune

To see the generator earn its keep, copy the staging folder to apps/web/overlays/qa, change the namespace inside to web-qa, commit and push. A third Application named web-qa appears after the next poll. Deleting the folder removes the Application again, though you should test that on a throwaway environment first. If you later need progressive delivery on top of this layout, our walkthrough of setting up Argo Rollouts covers canary and blue-green strategies.

Step 11: Order resources with sync waves and hooks

Kubernetes does not care about the order in which objects are created, but your app might. The ConfigMap you added in Step 3 carries wave -1, the Deployment sits at the default wave 0, and the Service uses wave 1. Argo CD applies one wave at a time and waits for each resource to become healthy before it moves to the next.

Hooks work alongside waves. The smoke-test Job has a PostSync hook, so it runs only after every other resource is Healthy. The delete policy HookSucceeded removes it after a pass and leaves a failed Job behind for debugging. You can verify the whole sequence from the CLI.

argocd app sync web-staging --prune
argocd app get web-staging --show-operation
kubectl -n web-staging get jobs

One hook caveat saves a headache. PreSync hooks run before regular resources, so a PreSync Job that needs a namespace, ServiceAccount or ConfigMap from the same Application will fail on a first-time sync. Use PostSync for checks that depend on the app, and keep PreSync for work like database migrations against infrastructure that already exists.

Phase 5: Lock It Down and Get Alerts (Steps 12-13)

Step 12: Add a CI account with narrow RBAC

The admin account can do everything, which makes it a poor choice for pipelines. Create a local account called ci that can only read and sync applications in the demo project. Set the default policy to read-only so that anyone who signs in without a role cannot change anything.

kubectl -n argocd patch configmap argocd-cm --type merge \
  -p '{"data":{"accounts.ci":"apiKey"}}'

kubectl -n argocd patch configmap argocd-rbac-cm --type merge \
  -p '{"data":{"policy.default":"role:readonly","policy.csv":"p, ci, applications, get, demo/*, allow\np, ci, applications, sync, demo/*, allow\n"}}'

argocd account list
TOKEN=$(argocd account generate-token --account ci)
argocd account can-i sync applications 'demo/web-dev' --auth-token "$TOKEN" --insecure --server localhost:8443
argocd app sync web-dev --auth-token "$TOKEN" --insecure --server localhost:8443

Store the token in your CI system’s secret store and set an expiry with --expires-in for anything long-lived. Once you wire up single sign-on through Dex or an external OIDC provider, consider disabling the local admin account by setting admin.enabled to "false" in argocd-cm. Confirm that your SSO login works first, or you will lock yourself out.

Declarative setup is the end goal. Both ConfigMaps above can live in Git and sync through a second Application, which makes your Argo CD configuration reviewable like any other change. The pattern is often called app-of-apps, and the advanced section returns to it.

Step 13: Send sync and health alerts to Slack

The notifications controller ships with the standard install, and the project maintains a catalog of ready-made triggers and templates. Install the catalog that matches your pinned version, add your Slack bot token, and register the Slack service. Create the bot in your workspace, give it permission to post messages, and invite it to the #gitops-alerts channel.

kubectl apply -n argocd -f \
  https://raw.githubusercontent.com/argoproj/argo-cd/${ARGOCD_VERSION}/notifications_catalog/install.yaml

kubectl -n argocd patch secret argocd-notifications-secret --type merge \
  -p "{\"stringData\":{\"slack-token\":\"${SLACK_TOKEN}\"}}"

kubectl -n argocd patch configmap argocd-notifications-cm --type merge \
  -p '{"data":{"service.slack":"token: $slack-token\n"}}'

Then subscribe applications to triggers using annotations. Because the ApplicationSet generates every Application, add the annotations to its template once and they apply everywhere. Edit the template metadata like this, commit and push, and re-apply the file.

  template:
    metadata:
      name: 'web-{{.path.basename}}'
      annotations:
        notifications.argoproj.io/subscribe.on-sync-failed.slack: gitops-alerts
        notifications.argoproj.io/subscribe.on-health-degraded.slack: gitops-alerts

Break something on purpose to test the wiring. Change the image tag in the staging overlay to a tag that does not exist, push, and wait. The app turns Degraded once the pod hits ImagePullBackOff, and Slack should show a message from the bot. Revert the commit afterward. Two triggers are enough to start with. Alert fatigue kills notification setups faster than anything else, so add more only when a real incident shows you a gap.

Expected Output and Verification Checklist

Before you move on to production habits, confirm that each phase produced the result below. If a row does not match, jump to the troubleshooting section and fix it now. Problems compound quickly in GitOps because every later step assumes the earlier ones work.

StepCommand to runWhat success looks like
1kubectl version --clientClient version prints, within one minor version of the cluster
2kubectl get nodesOne node, status Ready
4kubectl -n argocd get podsSeven pods, all Running and 1/1 ready
5argocd account get-user-infoLogged in as admin, no certificate errors with –insecure
6argocd proj get demoSource repo and web-* destination listed
7argocd app get web-devSync Status Synced, Health Status Healthy
8kubectl -n web-dev get deploy webReplica count returns to the Git value after a manual scale
10argocd app listweb-dev and web-staging, both owned by the ApplicationSet
12argocd account listci account with apiKey capability, enabled
13Break the staging image tagSlack message arrives within about a minute

Also open the UI after Step 10. The Applications tile view shows both apps with green health icons, and clicking one reveals a resource tree: Application, ConfigMap, Deployment, ReplicaSet, Pod and Service. That tree is where you will spend most of your debugging time, so get comfortable reading it.

Running Argo CD on EKS: Self-Managed vs Managed Capability

Everything above runs unchanged on a managed cluster. Point kubectl at an Amazon EKS cluster, run the same install command, and the in-cluster destination https://kubernetes.default.svc keeps working. If you need to build the cluster first, our guide to setting up Amazon EKS walks through it, and AWS said Amazon EKS added Kubernetes 1.37 support on October 2, 2026, including upgrades for existing clusters.

AWS now offers a second path. Amazon EKS Capabilities includes a managed Argo CD, alongside AWS Controllers for Kubernetes and Kube Resource Orchestrator, according to AWS material dated September 2026. Managed Argo CD trades operational work for a metered fee. You skip patching the controllers, sizing Redis and planning upgrades, but you pay by the hour for the capability and again for each application it manages.

The table uses the rates from AWS’s EKS pricing page and a 730-hour month, the same month length AWS uses in its own worked examples. The monthly figures are my arithmetic from those rates. They cover control-plane and Argo CD fees only, so worker nodes, load balancers and data transfer come on top.

Cost itemRateMonthly at 730 hours
EKS cluster, standard Kubernetes support$0.10 per cluster-hour$73.00
EKS cluster, extended support$0.60 per cluster-hour$438.00
Managed Argo CD capability fee$0.03 per capability-hour$21.90
Managed Argo CD, 10 applications$0.0015 per application-hourNot listed
Managed Argo CD, 100 applications$0.0015 per application-hour$109.50
Managed Argo CD total, 10 appsCapability plus applicationsNot listed
Managed Argo CD total, 100 appsCapability plus applications$131.40
Self-managed Argo CD, any app countNo license fee$0 plus your own compute and time

For a team running 10 applications, managed Argo CD adds a capability charge of $0.03 per hour plus $0.0015 per application-hour, which stays modest next to the $0.10 per cluster-hour fee and the worker nodes. The real question is operational. Self-managed Argo CD carries no license fee, but according to Akuity’s comparison page you remain responsible for infrastructure, upgrades, scaling, high availability and recovery. If your platform team already runs plenty of other controllers, one more is cheap. If not, the managed option removes a whole category of 2 a.m. pages.

Check one caution before you decide. Version support matters because a cluster in standard support costs $0.10 an hour and one in extended support costs $0.60, so an upgrade backlog is a budget problem as well as a security one. Our breakdown of the EKS cluster fee against ECS shows how that fee shapes the wider AWS container decision.

AWS also said on October 28, 2026 that EKS Auto Mode added support for the Kubernetes Gateway API, with Gateway and HTTPRoute resources provisioning the load balancing underneath. That gives you a clean way to expose the Argo CD UI on EKS without hand-built Ingress objects. Standard AWS load balancer charges still apply.

7 Common Pitfalls That Break Argo CD Setups

Most failed installs trace back to a short list of habits. Check this list before you blame the tool.

  1. Applying the install manifest client-side. Plain kubectl apply can fail on large custom resource definitions. Use --server-side every time, including on upgrades.
  2. Pointing at a moving tag. A URL containing stable or master changes under you. Pin an exact release tag and upgrade deliberately.
  3. Enabling prune without understanding it. With prune: true, deleting a file in Git deletes the live resource. Test on dev first and keep PVC-backed apps on manual prune.
  4. Fighting an autoscaler. If an HPA changes replicas and Git says otherwise, selfHeal resets them in a loop. Add an ignoreDifferences rule for /spec/replicas.
  5. Committing secrets to Git. Base64 is not encryption. Use Sealed Secrets, External Secrets Operator or SOPS, and rotate anything that already landed in history.
  6. Leaving everything in the default project. The default project trusts any repo and any namespace. Create scoped projects early, because retrofitting them later means touching every Application.
  7. Expecting instant syncs. The default polling interval is about three minutes. Engineers who push and then see nothing assume the tool is broken. Use a refresh or add a webhook.

One more habit belongs on the list. Do not run kubectl apply on resources that Argo CD owns. It works once, then Argo CD reverts you, and the confusing back-and-forth wastes an afternoon. Change Git instead, or temporarily disable auto-sync on the specific Application.

Troubleshooting: 10 Argo CD Errors and Fixes

These ten problems account for most of the support threads you will find. Each entry names the symptom, the cause and the fix.

  1. Error: metadata.annotations: Too long during install. You used client-side apply. Re-run the install with --server-side --force-conflicts.
  2. Application stays OutOfSync even after a sync. A controller or admission webhook mutates a field that Git does not specify, often replicas or injected sidecars. Run argocd app diff web-dev to find the field, then add an ignoreDifferences entry for it.
  3. ComparisonError: authentication required. The repo URL is wrong or credentials are missing. Run argocd repo list, confirm the URL ends the same way as in the Application, and re-add the repo with a valid token.
  4. application destination is not permitted in project. The AppProject does not list the namespace. Add a matching entry to spec.destinations and re-apply the project.
  5. namespaces “web-dev” not found. Add CreateNamespace=true to syncOptions, and make sure the project whitelists the Namespace kind.
  6. App stuck in Progressing. Sync worked but a resource is not healthy. Check kubectl -n web-dev describe pod for ImagePullBackOff, a failing probe or insufficient resources on the kind node.
  7. Application will not delete. The resources finalizer is waiting on a child that cannot be removed. Fix or delete the stuck child, or as a last resort patch the finalizer away with kubectl patch app NAME -n argocd --type merge -p '{"metadata":{"finalizers":null}}'.
  8. x509: certificate signed by unknown authority on login. Argo CD generated a self-signed certificate. Add --insecure for local work, or install a trusted certificate before real use.
  9. ApplicationSet generates no Applications. The directory glob matches nothing or the repo is unreachable. Check kubectl -n argocd logs deploy/argocd-applicationset-controller and confirm the path pattern matches your folders exactly.
  10. argocd-initial-admin-secret not found. You already deleted it, or the password was changed. Reset the admin password by patching argocd-secret with a new bcrypt hash, as described in the upstream docs, then restart the server pod.

When none of these fit, read the controller logs first. kubectl -n argocd logs statefulset/argocd-application-controller and the repo-server logs explain nearly every failure in plain language. The UI event list under each Application is the second place to look.

Advanced Tips for Production GitOps

Once the basics work, these upgrades pay off fastest. Pick the ones that match your risk, not all at once.

Use webhooks instead of polling. Add a webhook in your Git host that posts to /api/webhook on the Argo CD server. Syncs begin within seconds of a merge, and the repo server stops hammering Git on a timer.

Ignore fields owned by other controllers. The block below stops Argo CD from resetting replicas that an HPA controls.

spec:
  ignoreDifferences:
    - group: apps
      kind: Deployment
      jsonPointers:
        - /spec/replicas

Bootstrap with app-of-apps. A single root Application can watch the argocd/ folder and apply your project, ApplicationSet and configuration. Then a brand-new cluster needs only one manual command.

# bootstrap/root.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: root
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/YOUR_USER/gitops-demo.git
    targetRevision: HEAD
    path: argocd
    directory:
      recurse: true
  destination:
    server: https://kubernetes.default.svc
    namespace: argocd
  syncPolicy:
    automated:
      prune: true
      selfHeal: true

Prepare for upgrades. The Argo CD 3.6 release candidate is out, and write-ups such as the one on preparing for the Argo CD 3.6 upgrade cover server-side diff and related behavior changes that may affect your Applications. Read them, test in a throwaway cluster, and wait for a stable tag before touching production.

Check your Helm assumptions. Helm 4 is now the current major line, with 4.3.1 released on October 15, 2026, and Helm 3 security fixes end on February 10, 2027, according to the Helm project. If your Applications render Helm charts, confirm which Helm version your Argo CD release bundles and test chart rendering before you upgrade either side. Our Helm 3 to Helm 4 migration guide lists the chart changes to look for.

Manage more than one cluster. Register each extra cluster with argocd cluster add CONTEXT_NAME, then point ApplicationSet generators at the cluster list. One Git repo can then drive dev, staging and production clusters from a single control plane. Many teams run a dedicated management cluster for Argo CD so an application outage cannot take down the deployment tool.

Run in high availability. The project ships an HA manifest alongside the standard one. Use it once you have more than a handful of Applications, and size Redis and the repo server for your repository count rather than your app count.

Gate changes before merge. Run kubectl kustomize or helm template plus a schema check such as kubeconform in CI. Cheap checks on the pull request stop broken manifests before Argo CD ever sees them. OpenShift teams should also compare notes with our look at OpenShift versus upstream Kubernetes, since GitOps tooling choices differ there.

The Full Working Project: Files and One-Shot Bootstrap Script

Here is the finished repository layout, followed by a script that rebuilds the whole environment on a fresh machine. Replace the two placeholders at the top, push the repository first, and run the script. It takes about four minutes once Docker has pulled the images.

gitops-demo/
  apps/web/base/
    configmap.yaml        # sync-wave -1
    deployment.yaml       # wave 0 (default)
    service.yaml          # sync-wave 1
    smoke-test.yaml       # PostSync hook
    kustomization.yaml
  apps/web/overlays/
    dev/kustomization.yaml       # namespace web-dev, 1 replica
    staging/kustomization.yaml   # namespace web-staging, 2 replicas
  argocd/
    project.yaml
    applicationset.yaml
  bootstrap/
    root.yaml
#!/usr/bin/env bash
set -euo pipefail

GITHUB_USER="YOUR_USER"
ARGOCD_VERSION="v3.5.6"   # use the newest stable tag from the releases page
REPO="https://github.com/${GITHUB_USER}/gitops-demo.git"

kind create cluster --name gitops
kubectl create namespace argocd
kubectl apply -n argocd --server-side --force-conflicts \
  -f "https://raw.githubusercontent.com/argoproj/argo-cd/${ARGOCD_VERSION}/manifests/install.yaml"
kubectl -n argocd rollout status deploy/argocd-server --timeout=300s
kubectl -n argocd rollout status deploy/argocd-applicationset-controller --timeout=300s

# Point the manifests at your fork, then let Argo CD take over
sed -i.bak "s#https://github.com/YOUR_USER/gitops-demo.git#${REPO}#g" argocd/*.yaml bootstrap/*.yaml
kubectl apply -f argocd/project.yaml
kubectl apply -f argocd/applicationset.yaml

echo "Initial admin password:"
kubectl -n argocd get secret argocd-initial-admin-secret \
  -o jsonpath="{.data.password}" | base64 -d; echo

echo "Open the UI with: kubectl -n argocd port-forward svc/argocd-server 8443:443"

Tear everything down when you finish with kind delete cluster --name gitops. The Git repository keeps the entire desired state, so rebuilding takes minutes. That is the real payoff of this approach, and it applies equally to a production cluster after a bad day. For more cluster-level guides, browse our cloud computing coverage.

Argo CD Tutorial FAQ

What is Argo CD used for?

Argo CD deploys and maintains Kubernetes applications by treating a Git repository as the source of truth. It compares the manifests in Git with what runs in the cluster, reports differences and, if you allow it, fixes them automatically.

Is Argo CD free?

Yes. The project is open source under the Apache 2.0 license and graduated from the CNCF in 2022, according to Akuity. Self-managed installs carry no license fee, though you pay for the compute that runs them. Managed offerings, including the AWS capability priced above, charge by usage.

Which Kubernetes versions should I run it on?

Use a version the Kubernetes project still supports. As of October 29, 2026, that means 1.37, 1.36 or 1.35. Check the Argo CD documentation for the tested Kubernetes versions of your chosen Argo CD release, since the two projects release on separate schedules.

How often does Argo CD sync from Git?

By default the repo server checks for changes about every three minutes. A Git provider webhook cuts that to a few seconds, and argocd app get NAME --refresh forces an immediate check.

How should I store secrets with Argo CD?

Do not put plain secrets in Git. Encrypt them with Sealed Secrets or SOPS, or keep them in an external store and sync them with the External Secrets Operator. Argo CD then manages the encrypted object or the reference, never the raw value.

Should I run the Argo CD 3.6 release candidate?

No, not in production. A 3.6.0 release candidate (rc4) was published on October 22, 2026, and release candidates can change before the final tag. Test it in a disposable cluster if you want an early look, and run the newest stable release everywhere else.

Can Argo CD deploy Helm charts?

Yes. Point an Application’s source at a chart in Git or a chart repository and supply values in the manifest. The repo server renders the chart, and Argo CD applies the result like any other manifest. Confirm the Helm version your Argo CD release bundles before relying on Helm 4 behavior.

Sofia LindstrÃķm

Sofia LindstrÃķm

Editor-in-Chief

Sofia LindstrÃķm is the Editor-in-Chief at Tech Insider, where she leads editorial strategy and oversees coverage across AI, cybersecurity, and enterprise technology. With over a decade in Swedish tech journalism, she previously served as technology editor at Dagens Industri and covered the Nordic startup ecosystem for Breakit. Sofia holds an MSc in Media Technology from KTH Royal Institute of Technology and is a frequent speaker at Web Summit and Slush. She is passionate about making complex technology accessible to business leaders.

View all articles