Skip to main content
Kubernetes OrbStack Mac

I Set Up Argo CD on Local Kubernetes — Here's How

Install Argo CD on Docker Desktop Kubernetes in about ten minutes: the NetworkPolicy gotcha, a working Application manifest, and live self-heal tests.

9 min
Read time
1,616
Words
Published
Last revised
Engr Mejba Ahmed

Written by

Engr Mejba Ahmed

Share Article

I Set Up Argo CD on Local Kubernetes — Here's How
I Set Up Argo CD on Local Kubernetes — Here's How - Video thumbnail

The pod had been running for eleven days when I deleted it on purpose. Six seconds later a replacement was up with the same spec, and the Argo CD dashboard never showed anything but green. I did not run kubectl apply. I did not trigger a pipeline. Git said the pod should exist, so it existed again.

That test, run on my own laptop against Docker Desktop's built-in Kubernetes, is when GitOps stopped being a concept from conference talks and became something I could feel. Here is my honest claim after doing the setup: Argo CD on a local cluster takes about ten minutes, one of those minutes involves a gotcha no quick-start mentions, and the patterns you build locally are the same ones you ship to production unchanged. I tested it with a real workload, my InfraWhisper platform, a data-and-AI system with an API server, AI engine, stream processor, collector, and a real-time dashboard, which made it a genuine stress test rather than a nginx-hello-world demo.

I Set Up Argo CD on Local Kubernetes — Here's How - overview of why i stopped deploying to my cluster by hand, the setup, start to finish

Why I stopped deploying to my cluster by hand

My old local workflow was kubectl apply, forget the image tag, edit, apply again, wonder why old pods linger, delete and reapply. If you have run Kubernetes locally you know the loop. The problem is not that kubectl apply is broken; it is that you are the pipeline, and humans are unreliable pipelines.

The deeper problem is drift. You apply a manifest, then a quick kubectl edit happens at 2 AM, and now the cluster silently disagrees with the repo. When something breaks, nobody knows whether the truth lives in Git, in the cluster, or in someone's shell history.

GitOps makes one rule non-negotiable: Git is the truth, and the cluster converges to match it. Argo CD is the controller that enforces the rule through a continuous loop: observe the repo, diff desired state against live state, and reconcile the difference, either alerting you or fixing it automatically.

I run push-based pipelines for my web projects, like the GitHub Actions deploy that ships my Laravel site, and the contrast is instructive: a push pipeline executes a deploy when you push; a GitOps controller enforces a state forever. For a multi-service Kubernetes app, the second model is the one that scales.

The setup, start to finish

Prerequisites

Two things:

  • Docker Desktop with Kubernetes enabled (Settings → Kubernetes → Enable). I run this on macOS; the steps are identical elsewhere. If you use OrbStack's Kubernetes instead, everything below works the same way.
  • kubectl pointing at the local cluster:
kubectl config current-context
# must say: docker-desktop

Verify that context line. You do not want to discover mid-tutorial that you installed Argo CD onto a client's staging cluster. Ask me why that check is in bold in my own notes.

Step 1: install Argo CD

kubectl create namespace argocd

kubectl apply -n argocd -f \
  https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml

The stable manifest installs the full control plane into the argocd namespace: the API server and web UI, the repo server that clones and renders your manifests, the application controller that does the reconciling, plus Redis and Dex. Watch the pods come up; it takes a minute or two:

kubectl get pods -n argocd -w

Step 2: the Docker Desktop gotcha

This is the step that cost me twenty minutes and is the reason this post exists. After installation, port-forwarding to the UI simply did not work. Pods running, service present, connection refused anyway.

The cause: Argo CD ships NetworkPolicy resources that restrict traffic between its components. On a cluster whose CNI properly enforces them (Calico, Cilium), they are correct and desirable. On Docker Desktop's built-in networking they interfere with connectivity in subtle ways instead. The fix:

kubectl delete networkpolicies --all -n argocd

One command, local clusters only. On a real cluster with a policy-enforcing CNI, keep the policies; they are protecting you there. I suspect this single issue quietly kills more local Argo CD attempts than anything else, because nothing about "connection refused" points at NetworkPolicies.

Step 3: reach the dashboard and log in

kubectl port-forward svc/argocd-server -n argocd 8443:443

Browse to https://localhost:8443, accept the self-signed-certificate warning, and log in as admin with the auto-generated initial password:

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

Change it after first login (User Info → Update Password). Local machine or not, default credentials are a habit, and habits follow you to production.

Step 4: the Application manifest

The Application resource is the contract: what to watch, where to deploy, how to behave. Here is the shape I used for InfraWhisper, generalized:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: my-app
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/your-user/your-repo.git
    targetRevision: main
    path: deploy/helm/my-app
    helm:
      valueFiles:
        - values.yaml
  destination:
    server: https://kubernetes.default.svc
    namespace: my-app
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
      - CreateNamespace=true

The fields that deserve your attention:

  • destination.server: https://kubernetes.default.svc means "the cluster Argo CD itself runs in," which is always what you want locally.
  • prune: true: resources you delete from Git get deleted from the cluster. Without it, removed manifests leave orphans behind forever.
  • selfHeal: true: manual changes to the cluster get reverted to match Git. This is the switch that turns Argo CD from a deployer into an enforcer.
  • Helm is optional. Argo CD renders Helm, Kustomize, Jsonnet, or a plain directory of YAML. I used Helm because InfraWhisper's chart already existed; for raw manifests, point path at the directory and drop the helm block.

Apply it, then watch the dashboard:

kubectl apply -f application.yaml

Within seconds the application topology renders: for my stack that meant the API server's three replicas, the dashboard's two, the AI engine, stream processor, collector, and ingress, every component and its health in one view, with the triggering commit hash displayed. Docker Desktop's container list told the same story from below: 38 containers, Argo CD's control plane sitting alongside Kafka, ClickHouse, Postgres, and Redis. A full platform, driven entirely by a Git repo.

The three tests that prove it is real

Installing a tool is not the same as believing it. I ran three deliberate tests.

Self-healing. I deleted that eleven-day-old dashboard pod by hand. A replacement was running six seconds later. Kubernetes' ReplicaSet controller does the immediate resurrection, but Argo CD's reconciliation is what guarantees the deployment itself can never quietly diverge from the repo definition.

Drift correction. I manually scaled a deployment from three replicas to one, exactly the "quick production fix" that causes real incidents. For a few seconds the app showed Degraded, then the controller compared live state against Git and scaled it back to three. No intervention, and the drift event sits in the sync history as an audit trail. kubectl apply will never give you that.

Auto-sync. I bumped a replica count in values.yaml, committed, pushed, and watched with the dashboard and kubectl get pods -w side by side. Within roughly fifteen to twenty seconds of the push, the new pod was starting and the UI showed my commit message. Push code, cluster changes, nothing in between.

What I wish someone had told me first

An honest ledger after living with it:

  • The dashboard alone justifies the install. Topology, health, sync history, one-click rollback to any previous commit. For a dozen-component app it replaced my ritual of four chained kubectl commands.
  • The overhead is not nothing. The control plane added roughly half a gigabyte of RAM on my machine, on top of an already heavy stack. Modern laptop, fine; 8GB machine, you will feel it.
  • Private repos need credentials configured (SSH key, token, or GitHub App) in Argo CD's settings before your Application will sync. The two-command install skips this, and it will interrupt your flow at the worst moment. Do it first.
  • Install the CLI (brew install argocd) on day one. The UI is for understanding; the CLI is for operating.
  • Start with ApplicationSets if you know multiple environments are coming. One templated definition generating per-environment Applications beats migrating later.

Local is not practice. It is stage one

The strongest argument for this whole exercise: the Application manifest above does not change when it graduates. Moving from my laptop to a staging cluster changes the destination.server URL and a values file. The sync policy, the chart, the workflow, the habits all transfer untouched. You are not simulating a production workflow locally; you are running the first environment of it. That is also why I would do this before touching managed GitOps offerings: ten minutes on the cluster you already have, as I covered in running Kubernetes on a Mac with OrbStack, teaches you the model with zero stakes. And if your delivery story currently ends at a push-based pipeline like CodeDeploy on EC2, this is the natural next rung.

The checklist, compressed:

kubectl config current-context                # docker-desktop
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
kubectl get pods -n argocd -w                 # wait for Running
kubectl delete networkpolicies --all -n argocd   # Docker Desktop only
kubectl port-forward svc/argocd-server -n argocd 8443:443
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d
kubectl apply -f application.yaml

Eight commands. Then delete a pod on purpose and watch your repo bring it back. That six-second resurrection will teach you more about GitOps than everything you have read on it, this post included.

InfraWhisper, the platform I stress-tested this against, runs the same sync policy across a multi-service stack; it sits with the rest of my infrastructure builds on my projects page. That is the next rung after the local cluster — same manifests, more services, real traffic.

Advertisement
Coffee cup

Enjoyed this article?

Your support helps me create more in-depth technical content, open-source tools, and free resources for the developer community.

Related Topics

Engr Mejba Ahmed

Engr Mejba Ahmed

Engr. Mejba Ahmed builds AI-powered applications and secure cloud systems for businesses worldwide. With 8+ years shipping production software in Laravel, Python, and AWS, he's helped companies automate workflows, reduce infrastructure costs, and scale without security headaches. He writes about practical AI integration, cloud architecture, and developer productivity.

Related Articles

Browse All

Comments

Leave a Comment

Comments are moderated before appearing.

Learning Resources

Expand Your Knowledge

Accelerate your growth with structured courses, verified certificates, interactive flashcards, and production-ready AI agent skills.

Sample Certificate of Completion

Sample certificate — complete any course to earn yours

Engr Mejba Ahmed

Engr Mejba Ahmed

AI assistant · trained on my work

👋

Hey there!

Quick Actions

WhatsApp Direct line to me

Chat on WhatsApp

+880 1723 741224 · Replies within the hour on working days

Popular Questions

Engr Mejba Ahmed is connected
Engr Mejba Ahmed is typing...
Engr Mejba Ahmed avatar

✉ Want me to follow up? Drop your email

Engr Mejba Ahmed avatar

📞 Connect Directly

Choose how you'd like to reach me

WhatsApp

+880 1723 741224

Email

mejba.13@gmail.com

✓ Details sent! I'll get back to you shortly.

Powered by OpenAI

335+

Blog Posts

25

AI Courses

63

Projects

Services & Expertise

Pricing & Process

Learning & Resources

Connect & Support