How to Deploy to Multiple Clusters with ArgoCD


TL; DR: here are the steps to deploy to multiple Kubernetes clusters using a single ArgoCD server + Application Sets. Let’s get to it.

Add a Kubernetes Cluster to ArgoCD

First, we’ll use the argocd CLI. Just in case you don’t have it yet, it’s easy to install. Assuming kubectl is already configured and has admin access to more than 1 Kubernetes clusters.

# login to argocd
# mine is sso-enabled. this can be done using username and password too
argocd login argocd.my-domain.name --sso

# list context names of all kubernetes clusters
kubectl config get-contexts -o name

# add a cluster by its context name, ie. pick one from previous step
# this will create service account, etc. in the target cluster
# and save the token of the service account for ArgoCD to authenticate with
argocd cluster add --grpc-web my_kubernetes_cluster_context_name

# verify via the list command
argocd cluster list --grpc-web

# for the sake of simplicity let's rename the cluster
argocd cluster set my_kubernetes_cluster_context_name --grpc-web --name beta

Check the ArgoCD Project

Usually apps in the default project can be deployed to any cluster – in ArgoCD’s term, destination. If it’s a new project, we’d make sure it has the cluster as one of its destinations.

Use Application Set to Deploy

With Application Set, an Application can be deployed to multiple clusters using a template like this:

# application-set.yaml
# this will create 3 apps one in each cluster
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: my-multi-cluster-app
  namespace: argocd
spec:
  generators:
  - list:
      elements:
      - cluster: alpha
        # this is where the argocd resides too, so in-cluster it is
        destination_cluster_name: in-cluster
      - cluster: beta
        destination_cluster_name: beta
      - cluster: theta
        destination_cluster_name: theta
  goTemplate: true
  goTemplateOptions:
  - missingkey=error
  ignoreApplicationDifferences:
  - jsonPointers:
    - /spec/syncPolicy
    - /spec/source/targetRevision
  template:
    metadata:
      finalizers:
      - resources-finalizer.argocd.argoproj.io
      labels:
        app.kubernetes.io/instance: my-multi-cluster-app
        cluster: '{{.cluster}}'
        name: my-multi-cluster-app
      name: my-multi-cluster-app-{{.cluster}}
    spec:
      destination:
        name: '{{ .destination_cluster_name }}'
        namespace: my-app-namespace
      project: default
        path: .
        repoURL: git@github.com:my-org/my-gitops.git
      syncPolicy:
        automated:
          prune: true
          selfHeal: true
        syncOptions:
        - ApplyOutOfSyncOnly=true

🙂