Building an ArgoCD that doesn't fall over easily: HA architecture with multiple replicas and leader election, per-component HA including Redis with Sentinel, network HA, and failure testing with chaos testing and failure injection.

In episode 25 we optimized ArgoCD's performance — making it fast with thousands of applications. But speed doesn't guarantee availability: if the node hosting argocd-server dies, no matter how fast it is, the whole team loses access to the UI and CLI. In this episode we discuss high availability setup — designing ArgoCD so that a pod, node, or zone failure doesn't stop delivery.
Why does this matter? Remember ArgoCD's position: it's the only bridge between Git and the cluster. If ArgoCD dies, applications don't immediately die (Kubernetes keeps running what's already there), but everything else stops: sync, drift detection, self-healing, and operational access. For environments promising SLOs, ArgoCD itself must be the component that's hardest to kill. This episode gives the recipe — and how to prove it.
The basic HA principle is no single component is a point of failure. This is realized through three mechanisms:
When this design is right, one dead pod is an ordinary event, not an incident. You'll see leader lease logs on the controller:
argocd-application-controller-0 ... starting leader election
argocd-application-controller-1 ... attempting to acquire leadership
argocd-application-controller-1 ... successfully acquired lease argocd/argocd-application-controllerNote
Deploying ready-made ArgoCD HA is easier than assembling it yourself. The official argo-cd Helm chart provides the controller.replicas, server.replicas, repoServer.replicas, and redis-ha.enabled values — the HA patterns below are an interpretation of what that chart does, and you can use them directly.
Let's break it down one by one.
argocd-server is stateless; run several replicas behind a Service:
apiVersion: apps/v1
kind: Deployment
metadata:
name: argocd-server
spec:
replicas: 3
template:
spec:
containers:
- name: argocd-server
args:
- /usr/local/bin/argocd-server
- --staticassets=/shared/appArgoCD handles this easily; with topologySpreadConstraints (below) replicas are spread across nodes so one node failure doesn't kill all replicas.
argocd-repo-server is also stateless, but it stores caches in Redis (not locally). So horizontal scaling is safe. Use HPA (episode 25) or fixed replicas, and make sure all replicas share the same Redis so the cache isn't fragmented.
The controller is stateful: it holds application state and must be executed by one leader at a time. ArgoCD solves this with leader election based on coordination.k8s.io/Lease. Run 2-3 replicas; only the leader works, the rest are standby ready to take over:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: argocd-application-controller
spec:
replicas: 2When the leader dies, the lease expires and a standby takes over within seconds. This is the same active-passive pattern as the multi-cluster DR concept in episode 21, but within one cluster.
Redis is ArgoCD's cache brain. If it dies, ArgoCD still works but without a cache — performance returns to "full clone" mode. For HA:
Both need a PersistentVolumeClaim so data isn't lost on pod restart, and both are managed as manifests in Git:
redis:
enabled: true
sentinel:
enabled: true
masterName: argocd
metrics:
enabled: trueThe Redis cache isn't a database that "must always be consistent" — losing it only degrades performance. But two practices are still mandatory:
For the controller state, remember: ArgoCD's real state is already in Git. This is the structural advantage of GitOps — ArgoCD doesn't store truth, it stores results. Losing internal status only means re-reconcile, not data loss.
The last layer is access. The UI/CLI must stay reachable when individual components change:
argocd-server (NodePort/LoadBalancer/Ingress). Health checks make sure traffic only goes to healthy replicas.Topology spread is an important refinement: spread replicas across different nodes so one node going down doesn't take down all replicas:
spec:
template:
spec:
topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app.kubernetes.io/name: argocd-serverAn HA architecture that isn't tested is the same as none. Use chaos engineering to prove the claims:
kubectl delete pod -n argocd argocd-server-xxx and observe whether the Service hides the replacement.topologySpreadConstraints works and replicas re-spread.Tools like kube-monkey or Litmus execute these scenarios on a schedule, but even a manual monthly drill (the same pattern as the DR drill in episode 21) is hugely valuable:
kubectl delete pod -n argocd -l app.kubernetes.io/name=argocd-server --wait=false
kubectl get pods -n argocd -w
argocd app listRecovery validation — measure the time from failure injection until all components are healthy again. Record the results: if recovery takes longer than your SLO, fix the design before a real failure happens.
Warning
ArgoCD HA is only useful if the cluster itself is HA. If the cluster runs in a single zone, ArgoCD HA is an illusion. For serious availability claims, combine: multi-node, multi-zone, and back it up with multi-cluster (episode 21). An HA ArgoCD on a fragile cluster still falls with its cluster.
This episode closed ArgoCD's availability loop: HA architecture with multiple replicas and leader election, per-component HA (server, repo server, active-passive controller, Redis Sentinel), storage and Redis backup considerations, network HA with load balancers, ingress redundancy, and topology spread, and testing with chaos engineering and failure injection.
The points you should take with you:
With this episode, the journey from GitOps basics to production readiness is a complete line: installation, applications, scale, security, and resilience. In the next episode 27 we discuss troubleshooting & debugging — solving sync failures, failed health checks, authentication issues, repo access, and debugging techniques with the ArgoCD CLI. See you in episode 27!