You are viewing legacy v1.20 Service Mesh documentation.
Available versions
Cloud Service Mesh latest
Cloud Service Mesh 1.26 archive
Cloud Service Mesh 1.24 archive
Cloud Service Mesh 1.24 archive
Cloud Service Mesh 1.23 archive
Cloud Service Mesh 1.22 archive
Cloud Service Mesh 1.21 archive
Cloud Service Mesh 1.20 archive
Anthos Service Mesh 1.19 archive
Set up a multi-cluster mesh outside Google Cloud
This guide explains how to set up a multi-cluster mesh for the followingplatforms:
- Google Distributed Cloud
- Google Distributed Cloud
- GKE on Azure
- GKE on AWS
- Attached clusters, including Amazon EKS clusters and Microsoft AKS clusters
This guide shows how to set up two clusters, but you can extend this process toincorporate any number of clusters into your mesh.
Platform note: Theasmcli create-mesh command that you use toenable endpoint discovery requires all the clusters to be on the same platform. Currently,asmcli create-mesh only supports hybrid mesh in preview.Before you begin
This guide assumes you installed Cloud Service Mesh usingasmcli install. You needasmcli and the configuration package thatasmcli downloads to thedirectory that you specified in--output_dir when you ranasmcli install.If need to get set up, follow the steps inInstall dependent tools and validate clusterto:
- Install required tools
- Download
asmcli - Grant cluster admin permissions
- Validate your project and cluster
You need access to the kubeconfig files for all the clusters that you aresetting up in the mesh.
Warning: Only use kubeconfig files from trusted sources. Using aspecially-crafted kubeconfig file could result in malicious code execution orfile exposure. If you must use an untrusted kubeconfig file, inspect itcarefully first, much as you would a shell script.Set up environment variables and placeholders
You need the following environment variables when you install the east-westgateway.
Create an environment variable for the project number. In the followingcommand, replaceFLEET_PROJECT_ID with thethe project ID of thefleet host project.
exportPROJECT_NUMBER=$(gcloudprojectsdescribeFLEET_PROJECT_ID\--format="value(projectNumber)")Create an environment variable for the mesh identifier.
exportMESH_ID="proj-${PROJECT_NUMBER}"Create environment variables for the cluster names in the format that
asmclirequires.exportCLUSTER_1="cn-FLEET_PROJECT_ID-global-CLUSTER_NAME_1"exportCLUSTER_2="cn-FLEET_PROJECT_ID-global-CLUSTER_NAME_2"Get the context name for the clusters by usingthe values under the
NAMEcolumn in the output of this command:kubectl config get-contexts
Set the environment variables to the cluster context names, which this guideuses in many steps later:
export CTX_1=CLUSTER1_CONTEXT_NAMEexport CTX_2=CLUSTER2_CONTEXT_NAME
Install the east-west gateway
In the following commands:
Replace
CLUSTER_NAME_1andCLUSTER_NAME_2with the names of your clusters.Replace
PATH_TO_KUBECONFIG_1andPATH_TO_KUBECONFIG_2with the kubeconfig files foryour clusters.
Anthos Clusters
Mesh CA or CA Service
Install a gateway in cluster1 that is dedicated toeast-west traffic to
Note: If you installed Cloud Service Mesh using different values for$CLUSTER_2. By default, this gateway will be public on the Internet.Production systems might require additional access restrictions, forexample firewall rules, to prevent external attacks.--network_id, then you should pass the same values intogen-eastwest-gateway.shwith the--networkflag.asm/istio/expansion/gen-eastwest-gateway.sh\--mesh${MESH_ID}\--cluster${CLUSTER_1}\--networkdefault\--revision asm-1282-4|\./istioctl--kubeconfig=PATH_TO_KUBECONFIG_1\install-y--setspec.values.global.pilotCertProvider=kubernetes-f-Install a gateway in
$CLUSTER_2that is dedicated to east-west trafficfor$CLUSTER_1.asm/istio/expansion/gen-eastwest-gateway.sh\--mesh${MESH_ID}\--cluster${CLUSTER_2}\--networkdefault\--revision asm-1282-4|\./istioctl--kubeconfig=PATH_TO_KUBECONFIG_2\install-y--setspec.values.global.pilotCertProvider=kubernetes-f-
Istio CA
Install a gateway in cluster1 that is dedicated toeast-west traffic to
Note: If you installed Cloud Service Mesh using different values for$CLUSTER_2. By default, this gateway will be public on the Internet.Production systems might require additional access restrictions, forexample firewall rules, to prevent external attacks.--network_id, then you should pass the same values intogen-eastwest-gateway.shwith the--networkflag.asm/istio/expansion/gen-eastwest-gateway.sh\--mesh${MESH_ID}\--cluster${CLUSTER_1}\--networkdefault\--revision asm-1282-4|\./istioctl--kubeconfig=PATH_TO_KUBECONFIG_1\install-y--setspec.values.global.pilotCertProvider=istiod-f-Install a gateway in
$CLUSTER_2that is dedicated to east-west trafficfor$CLUSTER_1.asm/istio/expansion/gen-eastwest-gateway.sh\--mesh${MESH_ID}\--cluster${CLUSTER_2}\--networkdefault\--revision asm-1282-4|\./istioctl--kubeconfig=PATH_TO_KUBECONFIG_2\install-y--setspec.values.global.pilotCertProvider=istiod-f-
Azure, AWS, & Attached
Mesh CA
Install a gateway in cluster1 that is dedicated toeast-west traffic to
Note: If you installed Cloud Service Mesh using different values for$CLUSTER_2. By default, this gateway will be public on the Internet.Production systems might require additional access restrictions, forexample firewall rules, to prevent external attacks.--network_id, then you should pass the same values intogen-eastwest-gateway.shwith the--networkflag.asm/istio/expansion/gen-eastwest-gateway.sh\--mesh${MESH_ID}\--cluster${CLUSTER_1}\--networkdefault\--revision asm-1282-4|\./istioctl--kubeconfig=PATH_TO_KUBECONFIG_1\install-y--setspec.values.global.pilotCertProvider=istiod-f-Install a gateway in
$CLUSTER_2that is dedicated to east-west trafficfor$CLUSTER_1.asm/istio/expansion/gen-eastwest-gateway.sh\--mesh${MESH_ID}\--cluster${CLUSTER_2}\--networkdefault\--revision asm-1282-4|\./istioctl--kubeconfig=PATH_TO_KUBECONFIG_2\install-y--setspec.values.global.pilotCertProvider=istiod-f-
Istio CA
Install a gateway in cluster1 that is dedicated toeast-west traffic to
Note: If you installed Cloud Service Mesh using different values for$CLUSTER_2. By default, this gateway will be public on the Internet.Production systems might require additional access restrictions, forexample firewall rules, to prevent external attacks.--network_id, then you should pass the same values intogen-eastwest-gateway.shwith the--networkflag.asm/istio/expansion/gen-eastwest-gateway.sh\--mesh${MESH_ID}\--cluster${CLUSTER_1}\--networkdefault\--revision asm-1282-4|\./istioctl--kubeconfig=PATH_TO_KUBECONFIG_1\install-y--setspec.values.global.pilotCertProvider=istiod-f-Install a gateway in
$CLUSTER_2that is dedicated to east-west trafficfor$CLUSTER_1.asm/istio/expansion/gen-eastwest-gateway.sh\--mesh${MESH_ID}\--cluster${CLUSTER_2}\--networkdefault\--revision asm-1282-4|\./istioctl--kubeconfig=PATH_TO_KUBECONFIG_2\install-y--setspec.values.global.pilotCertProvider=istiod-f-
Exposing services
Since the clusters are on separate networks, you need to expose all services(*.local) on the east-west gateway in both clusters. While this gateway ispublic on the Internet, services behind it can only be accessed by services witha trusted mTLS certificate and workload ID, just as if they were on the samenetwork.
Expose services via the east-west gateway for
CLUSTER_NAME_1.kubectl --kubeconfig=PATH_TO_KUBECONFIG_1 apply -n istio-system -f \ asm/istio/expansion/expose-services.yamlExpose services via the east-west gateway for
CLUSTER_NAME_2.kubectl --kubeconfig=PATH_TO_KUBECONFIG_2 apply -n istio-system -f \ asm/istio/expansion/expose-services.yaml
Enable endpoint discovery
Note: For more information on endpoint discovery, refer toEndpoint discovery with multiple control planes.Run theasmcli create-mesh command to enable endpoint discovery. Thisexample only shows two clusters, but you can run the command to enableendpoint discovery on additional clusters, subject to theGKE Hub service limit.
./asmclicreate-mesh\FLEET_PROJECT_ID\PATH_TO_KUBECONFIG_1\PATH_TO_KUBECONFIG_2Verify multicluster connectivity
This section explains how to deploy the sampleHelloWorld andSleep servicesto your multi-cluster environment to verify that cross-cluster loadbalancing works.
samples directory included in theistioctl tarball (located inOUTPUT_DIR/istio-${ASM_VERSION%+*}/samples) and not thesamples directory downloaded byasmcli (located inOUTPUT_DIR/samples).Enable sidecar injection
Locate the revision label value, which you use in later steps.
Note: If your clusters each have different versions of Cloud Service Mesh you mustrun the following command for each cluster.Use the following command to locate the revision label, which you willuse in later steps.
kubectl-nistio-systemgetpods-lapp=istiod--show-labels
The output looks similar to the following:
NAMEREADYSTATUSRESTARTSAGELABELSistiod-asm-173-3-5788d57586-bljj41/1Running023happ=istiod,istio.io/rev=asm-173-3,istio=istiod,pod-template-hash=5788d57586istiod-asm-173-3-5788d57586-vsklm1/1Running123happ=istiod,istio.io/rev=asm-173-3,istio=istiod,pod-template-hash=5788d57586
In the output, under theLABELS column, note the value of theistiodrevision label, which follows the prefixistio.io/rev=. In this example,the value isasm-173-3. Use the revision value in the steps in the next section.
Install the HelloWorld service
Note: TheHelloWorld service example usesDocker Hub. In a privatecluster, the container runtime can pull container images fromArtifact Registryby default. The container runtime cannot pull images from any other containerimage registry on the internet. You can download the image and push to Artifact Registry or useCloud NAT to provide outbound internet access for certain private nodes. Formore information, seeMigrate external containersandCreating a private cluster.Create the sample namespace and the Service Definition in each cluster. Inthe following command, substituteREVISION with the
istiodrevision label that you noted from the previous step.forCTXin${CTX_1}${CTX_2}dokubectlcreate--context=${CTX}namespacesamplekubectllabel--context=${CTX}namespacesample\istio-injection-istio.io/rev=REVISION--overwritedonewhereREVISION is the
istiodrevision label that you previouslynoted.The output is:
label "istio-injection" not found.namespace/sample labeled
You can safely ignore
label "istio-injection" not found.Create the HelloWorld service in both clusters:
kubectl create --context=${CTX_1} \ -f ${SAMPLES_DIR}/samples/helloworld/helloworld.yaml \ -l service=helloworld -n samplekubectl create --context=${CTX_2} \ -f ${SAMPLES_DIR}/samples/helloworld/helloworld.yaml \ -l service=helloworld -n sample
Deploy HelloWorld v1 and v2 to each cluster
Deploy
HelloWorld v1toCLUSTER_1andv2toCLUSTER_2, which helps later to verify cross-cluster load balancing:kubectl create --context=${CTX_1} \ -f ${SAMPLES_DIR}/samples/helloworld/helloworld.yaml \ -l version=v1 -n samplekubectl create --context=${CTX_2} \ -f ${SAMPLES_DIR}/samples/helloworld/helloworld.yaml \ -l version=v2 -n sampleConfirm
HelloWorld v1andv2are running using the following commands. Verify that the output is similar to that shown.:kubectl get pod --context=${CTX_1} -n sampleNAME READY STATUS RESTARTS AGEhelloworld-v1-86f77cd7bd-cpxhv 2/2 Running 0 40s
kubectl get pod --context=${CTX_2} -n sampleNAME READY STATUS RESTARTS AGEhelloworld-v2-758dd55874-6x4t8 2/2 Running 0 40s
Deploy the Sleep service
Deploy the
Sleepservice to both clusters. This pod generates artificial network traffic for demonstration purposes:forCTXin${CTX_1}${CTX_2}dokubectlapply--context=${CTX}\-f${SAMPLES_DIR}/samples/sleep/sleep.yaml-nsampledoneWait for the
Sleepservice to start in each cluster. Verify that the output is similar to that shown:kubectl get pod --context=${CTX_1} -n sample -l app=sleepNAME READY STATUS RESTARTS AGEsleep-754684654f-n6bzf 2/2 Running 0 5s
kubectl get pod --context=${CTX_2} -n sample -l app=sleepNAME READY STATUS RESTARTS AGEsleep-754684654f-dzl9j 2/2 Running 0 5s
Verify cross-cluster load balancing
Call theHelloWorld service several times and check the output to verifyalternating replies from v1 and v2:
Call the
HelloWorldservice:kubectl exec --context="${CTX_1}" -n sample -c sleep \ "$(kubectl get pod --context="${CTX_1}" -n sample -l \ app=sleep -o jsonpath='{.items[0].metadata.name}')" \ -- /bin/sh -c 'for i in $(seq 1 20); do curl -sS helloworld.sample:5000/hello; done'The output is similar to that shown:
Hello version: v2, instance: helloworld-v2-758dd55874-6x4t8Hello version: v1, instance: helloworld-v1-86f77cd7bd-cpxhv...
Call the
HelloWorldservice again:kubectl exec --context="${CTX_2}" -n sample -c sleep \ "$(kubectl get pod --context="${CTX_2}" -n sample -l \ app=sleep -o jsonpath='{.items[0].metadata.name}')" \ -- /bin/sh -c 'for i in $(seq 1 20); do curl -sS helloworld.sample:5000/hello; done'The output is similar to that shown:
Hello version: v2, instance: helloworld-v2-758dd55874-6x4t8Hello version: v1, instance: helloworld-v1-86f77cd7bd-cpxhv...
Congratulations, you've verified your load-balanced, multi-cluster Cloud Service Mesh!
Clean up
When you finish verifying load balancing, remove theHelloWorld andSleepservice from your cluster.
kubectl delete ns sample --context ${CTX_1}kubectl delete ns sample --context ${CTX_2}Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 4.0 License, and code samples are licensed under theApache 2.0 License. For details, see theGoogle Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.
Last updated 2026-02-19 UTC.