Argo CD can run in high availability (HA) mode, but it doesn’t actually make the application highly available; it makes the control plane highly available.

Let’s see Argo CD in action. Imagine you have a Kubernetes cluster and you want to deploy an application using GitOps. You’ve got your application definition in a Git repository.

# Example Git Repository Content: app.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: my-app
  namespace: argocd
spec:
  destination:
    namespace: default
    server: https://kubernetes.default.svc
  project: default
  source:
    repoURL: https://github.com/your-username/your-repo.git
    targetRevision: HEAD
    path: path/to/your/app
  syncPolicy:
    automated:
      prune: true
      selfHeal: true

When you create this Application custom resource in your argocd namespace, Argo CD’s controller, running in the argocd namespace, detects it.

kubectl apply -f app.yaml

The controller then fetches the manifests from your Git repository (https://github.com/your-username/your-repo.git) and compares them to the desired state in your Kubernetes cluster. If there’s a difference, it creates, updates, or deletes Kubernetes resources to match the Git state.

Now, what happens if that single Argo CD controller pod dies? Your applications stop being reconciled. New deployments won’t be picked up, and if a manual sync was in progress, it might be left in an inconsistent state. This is where High Availability comes in.

To run Argo CD in HA mode, you deploy multiple replicas of the Argo CD controller. The key is that these controllers coordinate via a shared PostgreSQL database. Each controller instance watches the PostgreSQL database for changes to Argo CD’s internal state and the desired state of applications.

Here’s how you typically configure it in your argocd-ha StatefulSet definition (or when installing via Helm):

# Example argocd-ha StatefulSet snippet
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: argocd-server
  namespace: argocd
spec:
  replicas: 3 # <-- This is the HA part
  template:
    spec:
      containers:
      - name: argocd-server
        # ... other container config ...
        env:
        - name: ARGOCD_APPLICATION_CONTROLLER_REPLICAS
          value: "3" # <-- Inform controllers about the HA setup
        - name: ARGOCD_DB_USER
          valueFrom:
            secretKeyRef:
              name: argocd-db
              key: user
        - name: ARGOCD_DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: argocd-db
              key: password
        - name: ARGOCD_DB_HOST
          value: "argocd-postgresql.argocd.svc.cluster.local"
        - name: ARGOCD_DB_PORT
          value: "5432"
        - name: ARGOCD_DB_NAME
          value: "argocd"

The ARGOCD_APPLICATION_CONTROLLER_REPLICAS environment variable tells the controller instances how many replicas are expected. This is crucial for leader election and ensuring only one controller is actively reconciling at any given moment. The PostgreSQL database acts as the single source of truth for both the application state and the controller’s internal state.

When a controller pod starts, it attempts to acquire a lock in the PostgreSQL database. The controller that successfully acquires the lock becomes the "leader" and is responsible for reconciling applications. If the leader pod fails, the lock is released, and another available controller pod will acquire it, becoming the new leader. This failover happens automatically.

The argocd-server deployment also typically runs with multiple replicas, often behind a Kubernetes Service of type LoadBalancer or Ingress, to ensure the UI and API are always accessible. However, the application reconciliation HA is handled by the argocd-application-controller component, which is often deployed as a separate StatefulSet or managed within the main argocd-server StatefulSet.

The most surprising thing about Argo CD HA is that while you run multiple controller pods, only one is actively performing synchronization operations at any given time. The others are on standby, ready to take over. This prevents race conditions where multiple controllers might try to update the same resource simultaneously, leading to unpredictable states.

The next logical step is to explore how Argo CD handles secrets and credentials for accessing Git repositories and Kubernetes clusters in an HA setup.

Want structured learning?

Take the full Argocd course →