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. # --name is optional to set a alias, eg. beta for the cluster context. argocd cluster add --grpc-web my_kubernetes_cluster_context_name --name beta # verify via the list command argocd cluster list --grpc-web
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🙂
