Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,9 @@ archived_version

# Local Netlify folder
.netlify

# Local artifacts when running tests
artifacts

# Certs generated during tests
certs
71 changes: 71 additions & 0 deletions content/en/docs/ambient/install/multicluster/_index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
---
title: Install Multicluster
description: Install an Istio mesh in ambient mode across multiple Kubernetes clusters.
weight: 40
keywords: [kubernetes,multicluster,ambient]
simple_list: true
content_above: true
test: table-of-contents
owner: istio/wg-environments-maintainers
---

Follow this guide to install an Istio {{< gloss "ambient" >}}ambient service mesh{{< /gloss >}}
that spans multiple {{< gloss "cluster" >}}clusters{{< /gloss >}}.

## Current Status and Limitations

{{< warning >}}
**Ambient multicluster is currently in alpha status** and has significant limitations.
This feature is under active development and should not be used in production environments.
{{< /warning >}}

Before proceeding with ambient multicluster installation, it's critical to understand
the current state and limitations of this feature:

### Supported Configurations

Currently, ambient multicluster only supports:
Before proceeding with an ambient multicluster installation, it is critical to understand
the current state and limitations of this feature.

### Critical Limitations

#### Network Topology Restrictions

**Multi-cluster single-network configurations are untested, and may be broken**
- Use caution when deploying ambient across clusters that share the same network
- Only multi-network configurations are supported

#### Control Plane Limitations

**Primary remote configuration is not currently supported**
- You can only have multiple primary clusters
- Configurations with one or more remote clusters will not work correctly

#### Waypoint Requirements

**Universal waypoint deployments are assumed across clusters**
- All clusters must have identically named waypoint deployments
- Waypoint configurations must be synchronized manually across clusters (e.g. using Flux, ArgoCD, or similar tools)
- Traffic routing relies on consistent waypoint naming conventions

#### Service Visibility and Scoping
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The locality of services with waypoints is also confusing and worth mentioning. Like if service is local, but its waypoint service is labeled as global, then it is global.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, this makes sense when I think of the implementation, but it's probably something to make an adjustment to in beta (/cc @therealmitchconnors @krinkinmu)


**Service scope configurations are not read from across clusters**
- Only the local cluster's service scope configuration is used as the source of truth
- Remote cluster service scopes are not respected, which can lead to unexpected traffic behavior
- Cross-cluster service discovery may not respect intended service boundaries

**If a service's waypoint is marked as global, that service will also be global**
- This can lead to unintended cross-cluster traffic if not managed carefully

#### Gateway Limitations

**Ambient east-west gateways currently only support meshed mTLS traffic**
- Cannot currently expose `istiod` across networks using ambient east-west gateways. You can still use a classic e/w gateway for this.

{{< tip >}}
As ambient multicluster matures, many of these limitations will be addressed.
Check the [Istio release notes](https://istio.io/latest/news/) for updates on
ambient multicluster capabilities.
{{< /tip >}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
---
title: Before you begin
description: Initial steps before installing Istio on multiple clusters.
weight: 1
keywords: [kubernetes,multicluster,ambient]
test: n/a
owner: istio/wg-environments-maintainers
---

{{< boilerplate alpha >}}

Before you begin a multicluster installation, review the
[deployment models guide](/docs/ops/deployment/deployment-models)
which describes the foundational concepts used throughout this guide.
Comment on lines +14 to +16
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will sending people to the sidecar version of the doc confuse them?

Copy link
Contributor

@keithmattix keithmattix Aug 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIUC, the link isn't a sidecar specific doc; in theory, ambient can support all of the deployment models listed there.


In addition, review the requirements and perform the initial steps below.

## Requirements

### Cluster

This guide requires that you have two Kubernetes clusters with support for LoadBalancer `Services` on any of the
[supported Kubernetes versions:](/docs/releases/supported-releases#support-status-of-istio-releases) {{< supported_kubernetes_versions >}}.

### API Server Access

The API Server in each cluster must be accessible to the other clusters in the
mesh. Many cloud providers make API Servers publicly accessible via network
load balancers (NLB). The ambient east-west gateway cannot be used to expose
the API server as it only supports double HBONE traffic. A non-ambient
[east-west](https://en.wikipedia.org/wiki/East-west_traffic) gateway could be
used to enable access to the API Server.

## Environment Variables

This guide will refer to two clusters: `cluster1` and `cluster2`. The following
environment variables will be used throughout to simplify the instructions:

Variable | Description
-------- | -----------
`CTX_CLUSTER1` | The context name in the default [Kubernetes configuration file](https://kubernetes.io/docs/tasks/access-application-cluster/configure-access-multiple-clusters/) used for accessing the `cluster1` cluster.
`CTX_CLUSTER2` | The context name in the default [Kubernetes configuration file](https://kubernetes.io/docs/tasks/access-application-cluster/configure-access-multiple-clusters/) used for accessing the `cluster2` cluster.

Set the two variables before proceeding:

{{< text syntax=bash snip_id=none >}}
$ export CTX_CLUSTER1=<your cluster1 context>
$ export CTX_CLUSTER2=<your cluster2 context>
{{< /text >}}

## Configure Trust

A multicluster service mesh deployment requires that you establish trust
between all clusters in the mesh. Depending on the requirements for your
system, there may be multiple options available for establishing trust.
See [certificate management](/docs/tasks/security/cert-management/) for
detailed descriptions and instructions for all available options.
Depending on which option you choose, the installation instructions for
Istio may change slightly.

This guide will assume that you use a common root to generate intermediate
certificates for each primary cluster.
Follow the [instructions](/docs/tasks/security/cert-management/plugin-ca-cert/)
to generate and push a CA certificate secret to both the `cluster1` and `cluster2`
clusters.

{{< tip >}}
If you currently have a single cluster with a self-signed CA (as described
in [Getting Started](/docs/setup/getting-started/)), you need to
change the CA using one of the methods described in
[certificate management](/docs/tasks/security/cert-management/). Changing the
CA typically requires reinstalling Istio. The installation instructions
below may have to be altered based on your choice of CA.
{{< /tip >}}

## Next steps

You're now ready to install an Istio ambient mesh across multiple clusters.

- [Install Multi-Primary on Different Networks](/docs/ambient/install/multicluster/multi-primary_multi-network)

{{< tip >}}
If you plan on installing Istio multi-cluster using Helm, follow the
[Helm prerequisites](/docs/setup/install/helm/#prerequisites) in the Helm install guide first.
{{< /tip >}}
197 changes: 197 additions & 0 deletions content/en/docs/ambient/install/multicluster/common.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
#!/usr/bin/env bash
# shellcheck disable=SC1090,SC2034,SC2154

# Copyright Istio Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Initialize KUBECONFIG_FILES and KUBE_CONTEXTS
_set_kube_vars

source content/en/docs/ambient/install/multicluster/verify/snips.sh

# set_single_network_vars initializes all variables for a single network config.
function set_single_network_vars
{
export KUBECONFIG_CLUSTER1="${KUBECONFIG_FILES[0]}"
export KUBECONFIG_CLUSTER2="${KUBECONFIG_FILES[1]}"
export CTX_CLUSTER1="${KUBE_CONTEXTS[0]}"
export CTX_CLUSTER2="${KUBE_CONTEXTS[1]}"
}

# set_multi_network_vars initializes all variables for a multi-network config.
function set_multi_network_vars
{
export KUBECONFIG_CLUSTER1="${KUBECONFIG_FILES[0]}"
export KUBECONFIG_CLUSTER2="${KUBECONFIG_FILES[2]}"
export CTX_CLUSTER1="${KUBE_CONTEXTS[0]}"
export CTX_CLUSTER2="${KUBE_CONTEXTS[2]}"
}

# configure_trust creates a hierarchy of
function configure_trust
{
# Keeps the certs under a separate directory.
mkdir -p certs
pushd certs || exit

# Create the root cert.
make -f ../tools/certs/Makefile.selfsigned.mk root-ca

# Create and deploy intermediate certs for cluster1 and cluster2.
make -f ../tools/certs/Makefile.selfsigned.mk cluster1-cacerts
make -f ../tools/certs/Makefile.selfsigned.mk cluster2-cacerts

# Create the istio-system namespace in each cluster so that we can create the secrets.
kubectl --context="$CTX_CLUSTER1" create namespace istio-system
kubectl --context="$CTX_CLUSTER2" create namespace istio-system

# Deploy secret to each cluster
kubectl --context="$CTX_CLUSTER1" create secret generic cacerts -n istio-system \
--from-file=cluster1/ca-cert.pem \
--from-file=cluster1/ca-key.pem \
--from-file=cluster1/root-cert.pem \
--from-file=cluster1/cert-chain.pem
kubectl --context="$CTX_CLUSTER2" create secret generic cacerts -n istio-system \
--from-file=cluster2/ca-cert.pem \
--from-file=cluster2/ca-key.pem \
--from-file=cluster2/root-cert.pem \
--from-file=cluster2/cert-chain.pem

popd || exit # Return to the previous directory.
}

# cleanup_istioctl removes all resources created by the tests with istioctl.
function cleanup_istioctl
{
# Remove temp files.
rm -f cluster1.yaml cluster2.yaml certs

# Cleanup both clusters concurrently
cleanup_cluster1_istioctl &
cleanup_cluster2_istioctl &
wait
snip_delete_crds
}

# cleanup_cluster1_istioctl removes the istio-system and sample namespaces on CLUSTER1 with istioctl.
function cleanup_cluster1_istioctl
{
echo y | istioctl uninstall --revision=default --context="${CTX_CLUSTER1}"
kubectl delete ns istio-system sample --context="${CTX_CLUSTER1}" --ignore-not-found
}

# cleanup_cluster2_istioctl removes the istio-system and sample namespaces on CLUSTER2 with istioctl.
function cleanup_cluster2_istioctl
{
echo y | istioctl uninstall --revision=default --context="${CTX_CLUSTER2}"
kubectl delete ns istio-system sample --context="${CTX_CLUSTER2}" --ignore-not-found
}

# verify_load_balancing verifies that traffic is load balanced properly
# between CLUSTER1 and CLUSTER2.
function verify_load_balancing
{
# Verify istiod is synced
echo "Verifying istiod is synced to remote cluster."
_verify_like snip_verify_multicluster_1 "$snip_verify_multicluster_1_out"

# Deploy the HelloWorld service.
snip_deploy_the_helloworld_service_1
snip_deploy_the_helloworld_service_2
snip_deploy_the_helloworld_service_3

# Deploy HelloWorld v1 and v2
snip_deploy_helloworld_v1_1
snip_deploy_helloworld_v2_1

# Deploy curl
snip_deploy_curl_1

# Wait for all the deployments.
_wait_for_deployment sample helloworld-v1 "${CTX_CLUSTER1}"
_wait_for_deployment sample curl "${CTX_CLUSTER1}"
_wait_for_deployment sample helloworld-v2 "${CTX_CLUSTER2}"
_wait_for_deployment sample curl "${CTX_CLUSTER2}"

# Expose the helloworld service in both clusters.
echo "Exposing helloworld in cluster1"
kubectl --context="${CTX_CLUSTER1}" label svc helloworld -n sample istio.io/global="true"
echo "Exposing helloworld in cluster2"
kubectl --context="${CTX_CLUSTER2}" label svc helloworld -n sample istio.io/global="true"

# Verify everything is deployed as expected.
VERIFY_TIMEOUT=0 # Don't retry.
echo "Verifying helloworld v1 deployment"
_verify_like snip_deploy_helloworld_v1_2 "$snip_deploy_helloworld_v1_2_out"
echo "Verifying helloworld v2 deployment"
_verify_like snip_deploy_helloworld_v2_2 "$snip_deploy_helloworld_v2_2_out"
echo "Verifying curl deployment in ${CTX_CLUSTER1}"
_verify_like snip_deploy_curl_2 "$snip_deploy_curl_2_out"
echo "Verifying curl deployment in ${CTX_CLUSTER2}"
_verify_like snip_deploy_curl_3 "$snip_deploy_curl_3_out"
unset VERIFY_TIMEOUT # Restore default

local EXPECTED_RESPONSE_FROM_CLUSTER1="Hello version: v1, instance:"
local EXPECTED_RESPONSE_FROM_CLUSTER2="Hello version: v2, instance:"

# Verify we hit both clusters from CLUSTER1
echo "Verifying load balancing from ${CTX_CLUSTER1}"
_verify_contains snip_verifying_crosscluster_traffic_1 "$EXPECTED_RESPONSE_FROM_CLUSTER1"
_verify_contains snip_verifying_crosscluster_traffic_1 "$EXPECTED_RESPONSE_FROM_CLUSTER2"

# Verify we hit both clusters from CLUSTER2
echo "Verifying load balancing from ${CTX_CLUSTER2}"
_verify_contains snip_verifying_crosscluster_traffic_3 "$EXPECTED_RESPONSE_FROM_CLUSTER1"
_verify_contains snip_verifying_crosscluster_traffic_3 "$EXPECTED_RESPONSE_FROM_CLUSTER2"
}

# For Helm multi-cluster installation steps

function create_istio_system_ns
{
snip_create_istio_system_namespace_cluster_1
snip_create_istio_system_namespace_cluster_2
}

function setup_helm_repo
{
snip_setup_helm_repo_cluster_1
snip_setup_helm_repo_cluster_2
}

snip_create_istio_system_namespace_cluster_1() {
kubectl create namespace istio-system --context "${CTX_CLUSTER1}"
}

snip_create_istio_system_namespace_cluster_2() {
kubectl create namespace istio-system --context "${CTX_CLUSTER2}"
}

snip_setup_helm_repo_cluster_1() {
helm repo add istio https://istio-release.storage.googleapis.com/charts --kube-context "${CTX_CLUSTER1}"
helm repo update --kube-context "${CTX_CLUSTER1}"
}

snip_setup_helm_repo_cluster_2() {
helm repo add istio https://istio-release.storage.googleapis.com/charts --kube-context "${CTX_CLUSTER2}"
helm repo update --kube-context "${CTX_CLUSTER2}"
}

snip_delete_sample_ns_cluster_1() {
kubectl delete namespace sample --context "${CTX_CLUSTER1}"
}

snip_delete_sample_ns_cluster_2() {
kubectl delete namespace sample --context "${CTX_CLUSTER2}"
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading