Skip to main content

ArgoCD

ArgoCD is a declarative GitOps continuous delivery tool for Kubernetes that watches a Git repository and automatically synchronises the cluster to match the declared state — providing self-healing, auditable deployments where every change is a Git commit.

Understanding ArgoCD

What Is ArgoCD in Simple Terms

ArgoCD is a Kubernetes controller that asks one question continuously: does my cluster look like what Git says it should look like? If yes, do nothing. If no, fix it.

This is the GitOps model: Git is the source of truth, not a human running kubectl commands or a push-based CI pipeline writing directly to the cluster. When an engineer wants to deploy a new version, they update the Kubernetes manifest in Git. ArgoCD sees the change within seconds and applies it to the cluster. No deployment scripts. No direct cluster access needed. Full audit trail in Git history.

Razorpay, PhonePe, and Hotstar use ArgoCD-style GitOps for their Kubernetes deployments — it is the production standard for teams that need auditable, reproducible, self-healing deployments.

How It Works

Bash
+------------------------------------------+
| Git Repository (config repo) |
| kubernetes/payment-api/deployment.yaml |
| image: payment-api:v1.2.3 <- updated |
+------------------------------------------+
|
ArgoCD polls every 3 minutes
OR webhook triggers immediately
|
v
+------------------------------------------+
| ArgoCD Application Controller |
| Compares: Git state vs cluster state |
| Finds: image tag differs |
+------------------------------------------+
|
OutOfSync detected
|
v
+------------------------------------------+
| Sync operation |
| kubectl apply -f deployment.yaml |
| Kubernetes rolling update begins |
+------------------------------------------+
|
v
+------------------------------------------+
| Application: Synced + Healthy |
| Cluster matches Git exactly |
+------------------------------------------+

ArgoCD Application manifest:

YAML
## application.yaml -- defines what ArgoCD manages
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: payment-api
namespace: argocd
spec:
project: default
## Source: where the Kubernetes manifests live
source:
repoURL: https://github.com/razorpay/k8s-configs
targetRevision: main
path: apps/payment-api/production
## Destination: which cluster and namespace to deploy to
destination:
server: https://kubernetes.default.svc
namespace: payment-api-production
## Sync policy: how ArgoCD manages the application
syncPolicy:
automated:
prune: true ## delete resources removed from Git
selfHeal: true ## revert manual kubectl changes
syncOptions:
- CreateNamespace=true

Key ArgoCD commands:

Bash
## Install ArgoCD
kubectl create namespace argocd
kubectl apply -n argocd -f \
https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
## CLI login
argocd login argocd.internal --username admin --password $PASSWORD
## Create an application
argocd app create payment-api \
--repo https://github.com/razorpay/k8s-configs \
--path apps/payment-api/production \
--dest-server https://kubernetes.default.svc \
--dest-namespace payment-api-production \
--sync-policy automated
## Check application status
argocd app get payment-api
argocd app list
## Manually sync an application
argocd app sync payment-api
## Rollback to a previous version
argocd app history payment-api
argocd app rollback payment-api HISTORY_ID
## View sync diff before applying
argocd app diff payment-api

Troubleshooting

Symptom Check What to Look For
App stuck OutOfSync argocd app diff Manifest differs from cluster state
Sync failing argocd app get --show-operation Error message in sync operation
Self-heal reverting intentional change Update Git first Always change Git, not cluster directly
App Degraded not Healthy Check pod logs Application health check failing
Tip

Use the App of Apps pattern to manage ArgoCD Applications themselves with ArgoCD. Create one root Application that watches a directory containing all your other Application manifests. Adding a new service means adding one YAML file to Git — ArgoCD automatically creates and manages the new Application.

Remember

With ArgoCD's selfHeal enabled, any manual kubectl change to a managed resource will be reverted within minutes. This is the point — it enforces Git as the single source of truth. If you need to make an emergency change, update Git first, then ArgoCD applies it. Never work around ArgoCD with direct kubectl commands.

Security

Restrict who can trigger manual syncs and who can manage ArgoCD Applications using RBAC and Projects. An ArgoCD project can restrict which source repositories, destination clusters, and namespaces an Application can use — preventing a misconfigured application from deploying to the wrong namespace.

Common Mistake

Using the same Git repository for application code and Kubernetes manifests. The app repo and config repo should be separate. When your pipeline updates the image tag in the config repo, it triggers ArgoCD. If they are the same repo, every code commit triggers a sync — including commits that have nothing to do with deployment.

Frequently Asked Questions

What does 'GitOps' actually mean in the context of ArgoCD?

GitOps means the Git repository is the single source of truth for what should be running in the cluster — you don't run kubectl apply manually or from a CI pipeline; instead you commit the desired manifests to Git, and ArgoCD continuously reconciles the live cluster state to match it. If someone changes something directly in the cluster (kubectl edit), ArgoCD detects the drift and can automatically revert it, since Git — not the cluster — is authoritative.

What's a common mistake teams make when adopting ArgoCD?

Enabling auto-sync with self-heal turned on before the team trusts their manifests, causing ArgoCD to aggressively revert emergency kubectl fixes made during an incident, right when someone needs to patch something fast. Many teams start with manual sync or disable self-heal on production apps until their Git-based workflow is mature enough that direct cluster edits are genuinely never needed.