Skip to main content
Version: v4.9 Stable

Deploy Multi-Region Platform on AWS (EKS)

info
This feature is available from the Platform version v4.8.0
note

These instructions are tested on AWS. Multi-region platform can run on other cloud providers with comparable capabilities (managed Kubernetes, cross-region networking, latency-based DNS, and a shared database).

These steps walk you through setting up vCluster Platform across two AWS regions using EKS, cross-region VPC peering, shared database (Kine), ALB ingress, and Route 53 latency-based routing.

Prerequisites​

Before you begin, ensure you have:

  • An AWS account with sufficient IAM permissions
  • A registered domain (example: multi-region.example.com)
  • A public Route 53 hosted zone
  • The following tools installed:

Configure your values​

This guide uses resource identifiers that are unique to your AWS environment: account IDs, VPC IDs, security group IDs, cluster ARNs, ALB host names, and DNS names. Fill in the fields below once and every command on this page updates to use your values, ready to copy and run without manual substitution.

Variables prefixed with US_ and EU_ are named for the example regions in this guide. You can deploy to any two AWS regions. Set AWS_REGION and EU_REGION to your actual region codes and update the other US_/EU_ values accordingly.

Expand to set page variables
Modify the following with your specific values to replace on the whole page and generate copyable commands:

Step 1 - Create two EKS clusters​

Important

All three VPCs (two EKS clusters and one database) must use different, non-overlapping CIDR ranges to allow VPC peering.

U.S. region

eksctl create cluster \
--name platform-multi-region-us-east-1 \
--region us-east-1 \
--nodes 2 \
--managed \
--vpc-cidr 10.0.0.0/16 \
--with-oidc

E.U. region

eksctl create cluster \
--name platform-multi-region-eu-west-1 \
--region eu-west-1 \
--nodes 2 \
--managed \
--vpc-cidr 172.21.0.0/16 \
--with-oidc

Install the Amazon EBS CSI driver​

The EBS CSI driver is required for dynamic provisioning of persistent volumes on EKS. Without it, tenant cluster StatefulSet pods remain in Pending state because the gp2 storage class can't provision volumes.

Install the driver as an EKS managed add-on on each cluster:

eksctl create addon --name aws-ebs-csi-driver \
--cluster platform-multi-region-us-east-1 \
--region us-east-1

eksctl create addon --name aws-ebs-csi-driver \
--cluster platform-multi-region-eu-west-1 \
--region eu-west-1

For more details on EKS prerequisites for running tenant clusters, see the EKS environment setup guide.

Step 2 - Install AWS load balancer controller​

Create IAM policy​

curl -o iam_policy.json \
https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/main/docs/install/iam_policy.json

aws iam create-policy \
--policy-name AWSLoadBalancerControllerIAMPolicy \
--policy-document file://iam_policy.json

Create IAM service account (IRSA)​

U.S. region

eksctl create iamserviceaccount \
--cluster platform-multi-region-us-east-1 \
--namespace kube-system \
--name aws-load-balancer-controller \
--attach-policy-arn arn:aws:iam::123456789012:policy/AWSLoadBalancerControllerIAMPolicy \
--approve

E.U. region

eksctl create iamserviceaccount \
--cluster platform-multi-region-eu-west-1 \
--namespace kube-system \
--name aws-load-balancer-controller \
--attach-policy-arn arn:aws:iam::123456789012:policy/AWSLoadBalancerControllerIAMPolicy \
--approve

Install using Helm​

helm repo add eks https://aws.github.io/eks-charts
helm repo update

U.S. region

helm install aws-load-balancer-controller eks/aws-load-balancer-controller \
-n kube-system \
--set clusterName=platform-multi-region-us-east-1 \
--set serviceAccount.create=false \
--set serviceAccount.name=aws-load-balancer-controller

E.U. region

helm install aws-load-balancer-controller eks/aws-load-balancer-controller \
-n kube-system \
--set clusterName=platform-multi-region-eu-west-1 \
--set serviceAccount.create=false \
--set serviceAccount.name=aws-load-balancer-controller

Step 3 - Create the database (Kine backend)​

Create an RDS instance (MariaDB) in its own isolated VPC, separate from the EKS cluster VPCs. This keeps the database network boundary independent from the cluster workloads and simplifies security group rules.

Important

For production multi-region deployments, configure RDS in an active-active setup so the database automatically fails over between regions. See Active-Active Replication on Amazon RDS for MySQL for guidance on setting this up.

Create the database VPC​

Create a VPC with a CIDR that doesn't overlap with either EKS cluster VPC. Enable DNS support and DNS hostnames so the RDS endpoint resolves correctly across VPC peering connections.

aws ec2 create-vpc \
--cidr-block 10.1.0.0/16 \
--region us-east-1 \
--tag-specifications 'ResourceType=vpc,Tags=[{Key=Name,Value=multi-region-db-vpc}]'

Note the VpcId from the output, then enable DNS settings:

aws ec2 modify-vpc-attribute \
--vpc-id vpc-xxxxxxxxx \
--enable-dns-support '{"Value":true}' \
--region us-east-1

aws ec2 modify-vpc-attribute \
--vpc-id vpc-xxxxxxxxx \
--enable-dns-hostnames '{"Value":true}' \
--region us-east-1

Create subnets and DB subnet group​

Create subnets in at least two availability zones (required by RDS), then create a DB subnet group.

aws ec2 create-subnet \
--vpc-id vpc-xxxxxxxxx \
--cidr-block 10.1.1.0/24 \
--availability-zone us-east-1a \
--region us-east-1 \
--tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=multi-region-db-subnet-1a}]'

aws ec2 create-subnet \
--vpc-id vpc-xxxxxxxxx \
--cidr-block 10.1.2.0/24 \
--availability-zone us-east-1b \
--region us-east-1 \
--tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=multi-region-db-subnet-1b}]'
Modify the following with your specific values to generate a copyable command:
aws rds create-db-subnet-group \
--db-subnet-group-name multi-region-db-subnet \
--db-subnet-group-description "Isolated VPC subnet group for multi-region RDS" \
--subnet-ids subnet-xxxxxxxxx subnet-yyyyyyyyy \
--region us-east-1

Create a security group for the database​

Create a security group that allows inbound MariaDB traffic (port 3306) from both EKS cluster VPC CIDR ranges.

aws ec2 create-security-group \
--group-name multi-region-db-sg \
--description "Allow MariaDB from EKS VPCs via peering" \
--vpc-id vpc-xxxxxxxxx \
--region us-east-1
aws ec2 authorize-security-group-ingress \
--group-id sg-xxxxxxxxx \
--protocol tcp --port 3306 \
--cidr 10.0.0.0/16 \
--region us-east-1

aws ec2 authorize-security-group-ingress \
--group-id sg-xxxxxxxxx \
--protocol tcp --port 3306 \
--cidr 172.21.0.0/16 \
--region us-east-1

Create the RDS instance​

Modify the following with your specific values to generate a copyable command:
aws rds create-db-instance \
--engine mariadb \
--db-instance-identifier mariadb-multi-region \
--allocated-storage 20 \
--region us-east-1 \
--db-instance-class db.t3.medium \
--master-username admin \
--master-user-password your-password \
--db-subnet-group-name multi-region-db-subnet \
--vpc-security-group-ids sg-xxxxxxxxx \
--no-publicly-accessible \
--enable-iam-database-authentication

Wait for the instance to become available:

aws rds wait db-instance-available \
--db-instance-identifier mariadb-multi-region \
--region us-east-1

Create the Kine database and IAM user​

Connect to the database instance as the admin user and create the kine database and user. The user authenticates with the AWSAuthenticationPlugin instead of a password.

CREATE DATABASE IF NOT EXISTS kine;

CREATE USER 'kine'@'%' IDENTIFIED WITH AWSAuthenticationPlugin AS 'RDS';
GRANT ALL PRIVILEGES ON kine.* TO 'kine'@'%';
FLUSH PRIVILEGES;

Create an IAM policy for RDS access​

Create an IAM policy that grants the rds-db:connect permission for the kine database user. Replace <DBI_RESOURCE_ID> with the RDS instance resource ID (run aws rds describe-db-instances --query 'DBInstances[0].DbiResourceId' to retrieve it).

Modify the following with your specific values to generate a copyable command:
aws iam create-policy \
--policy-name RDSIAMAuthKine \
--policy-document '{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "rds-db:connect",
"Resource": "arn:aws:rds-db:us-east-1:123456789012:dbuser:db-XXXXXXXXXXXXXXXXXXXXXXXXXX/kine"
}
]
}'

Create an IAM role for Pod Identity​

Create an IAM role with a trust policy that allows the EKS Pod Identity agent to assume it. The pods.eks.amazonaws.com trust principal is region-agnostic, so a single role works for clusters in any region.

aws iam create-role \
--role-name PlatformKineRDSRole \
--assume-role-policy-document '{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "pods.eks.amazonaws.com"
},
"Action": [
"sts:AssumeRole",
"sts:TagSession"
]
}
]
}'

aws iam attach-role-policy \
--role-name PlatformKineRDSRole \
--policy-arn arn:aws:iam::123456789012:policy/RDSIAMAuthKine

Install the EKS Pod Identity Agent​

Install the Pod Identity Agent add-on on every cluster. Without this add-on, the Pod Identity association has no effect and pods can't obtain IAM credentials.

aws eks create-addon \
--cluster-name platform-multi-region-us-east-1 \
--addon-name eks-pod-identity-agent \
--region us-east-1

aws eks create-addon \
--cluster-name platform-multi-region-eu-west-1 \
--addon-name eks-pod-identity-agent \
--region eu-west-1

Verify the add-on is ACTIVE on each cluster before proceeding:

aws eks describe-addon \
--cluster-name platform-multi-region-us-east-1 \
--addon-name eks-pod-identity-agent \
--region us-east-1 \
--query 'addon.status'

Create Pod Identity associations​

Associate the IAM role with the loft service account in the vcluster-platform namespace on every cluster. This allows the platform pods to generate temporary IAM authentication tokens for the database connection.

Important

You must create a Pod Identity association on each cluster, not just the cluster in the same region as the database. Without the association, the platform pods in that cluster can't authenticate with the RDS instance and fail with Access denied errors.

U.S. region

aws eks create-pod-identity-association \
--cluster-name platform-multi-region-us-east-1 \
--role-arn arn:aws:iam::123456789012:role/PlatformKineRDSRole \
--namespace vcluster-platform \
--service-account loft \
--region us-east-1

E.U. region

aws eks create-pod-identity-association \
--cluster-name platform-multi-region-eu-west-1 \
--role-arn arn:aws:iam::123456789012:role/PlatformKineRDSRole \
--namespace vcluster-platform \
--service-account loft \
--region eu-west-1

For more details on IAM database authentication with EKS Pod Identity, see IAM database authentication.

Step 4 - Create VPC peering to the database​

Create VPC peering connections between each EKS cluster VPC and the database VPC. This gives both clusters network access to the RDS instance without requiring direct cluster-to-cluster peering.

Create peering connections​

Database VPC to U.S. cluster VPC (same region):

Modify the following with your specific values to generate a copyable command:
aws ec2 create-vpc-peering-connection \
--vpc-id vpc-xxxxxxxxx \
--peer-vpc-id vpc-yyyyyyyyy \
--region us-east-1 \
--tag-specifications 'ResourceType=vpc-peering-connection,Tags=[{Key=Name,Value=db-vpc-to-eks-us-east-1}]'

Database VPC to E.U. cluster VPC (cross-region):

Modify the following with your specific values to generate a copyable command:
aws ec2 create-vpc-peering-connection \
--vpc-id vpc-xxxxxxxxx \
--peer-vpc-id vpc-zzzzzzzzz \
--peer-region eu-west-1 \
--region us-east-1 \
--tag-specifications 'ResourceType=vpc-peering-connection,Tags=[{Key=Name,Value=db-vpc-to-eks-eu-west-1}]'

Accept the peering connections​

The same-region peering is accepted in us-east-1. The cross-region peering must be accepted in eu-west-1.

aws ec2 accept-vpc-peering-connection \
--vpc-peering-connection-id pcx-xxxxxxxxx \
--region us-east-1

aws ec2 accept-vpc-peering-connection \
--vpc-peering-connection-id pcx-yyyyyyyyy \
--region eu-west-1

Enable DNS resolution​

Enable DNS resolution on both peering connections so the RDS endpoint hostname resolves to its private IP from the EKS VPCs.

aws ec2 modify-vpc-peering-connection-options \
--vpc-peering-connection-id pcx-xxxxxxxxx \
--requester-peering-connection-options AllowDnsResolutionFromRemoteVpc=true \
--accepter-peering-connection-options AllowDnsResolutionFromRemoteVpc=true \
--region us-east-1

For the cross-region peering, set the requester side (DB VPC) in us-east-1 and the accepter side (E.U. cluster VPC) in eu-west-1:

aws ec2 modify-vpc-peering-connection-options \
--vpc-peering-connection-id pcx-yyyyyyyyy \
--requester-peering-connection-options AllowDnsResolutionFromRemoteVpc=true \
--region us-east-1

aws ec2 modify-vpc-peering-connection-options \
--vpc-peering-connection-id pcx-yyyyyyyyy \
--accepter-peering-connection-options AllowDnsResolutionFromRemoteVpc=true \
--region eu-west-1

Add routes​

Add routes so traffic can flow between each EKS VPC and the database VPC.

Important

Add routes to every route table whose subnets host EKS nodes, including public route tables. If your EKS nodes run in public subnets (the eksctl default), missing routes on the public route table cause database connection timeouts even though VPC peering is active.

Database VPC route table — route to both EKS VPC CIDRs:

aws ec2 create-route \
--route-table-id rtb-xxxxxxxxx \
--destination-cidr-block 10.0.0.0/16 \
--vpc-peering-connection-id pcx-xxxxxxxxx \
--region us-east-1

aws ec2 create-route \
--route-table-id rtb-xxxxxxxxx \
--destination-cidr-block 172.21.0.0/16 \
--vpc-peering-connection-id pcx-yyyyyyyyy \
--region us-east-1

U.S. EKS VPC route tables — route to the database VPC CIDR. Repeat for every route table associated with subnets that host EKS nodes:

Modify the following with your specific values to generate a copyable command:
aws ec2 create-route \
--route-table-id rtb-yyyyyyyyy \
--destination-cidr-block 10.1.0.0/16 \
--vpc-peering-connection-id pcx-xxxxxxxxx \
--region us-east-1

E.U. EKS VPC route tables — route to the database VPC CIDR. Repeat for every route table associated with subnets that host EKS nodes:

Modify the following with your specific values to generate a copyable command:
aws ec2 create-route \
--route-table-id rtb-zzzzzzzzz \
--destination-cidr-block 10.1.0.0/16 \
--vpc-peering-connection-id pcx-yyyyyyyyy \
--region eu-west-1

To list all route tables for a VPC and identify which subnets they serve:

Modify the following with your specific values to generate a copyable command:
aws ec2 describe-route-tables \
--filters "Name=vpc-id,Values=vpc-xxxxxxxxx" \
--region us-east-1 \
--query 'RouteTables[].{RouteTableId:RouteTableId,Name:Tags[?Key==`Name`].Value|[0],Subnets:Associations[].SubnetId}'

Verify connectivity​

Launch a test pod in each EKS cluster and verify it can reach the RDS endpoint:

Modify the following with your specific values to generate a copyable command:
kubectl run dbtest --image=busybox --restart=Never --rm -it -- \
nc -zv mariadb-multi-region.xxxxxxxxxxxx.us-east-1.rds.amazonaws.com 3306

The connection should report open. If it times out, verify that routes exist on the correct route tables and that the database security group allows ingress from the cluster's VPC CIDR.

Step 5 - Deploy vCluster platform​

Deploy the platform on each cluster using the multiRegion Helm values. Each cluster needs a region-specific multiRegion.host value (used as the custom DERP server endpoint), while config.loftHost should be the shared DNS domain.

Create a values file for each region. The only differences between regions are multiRegion.host and multiRegion.region.

U.S. region (save as US_VALUES_FILE)

admin:
email: admin@example.com

multiRegion:
enabled: true
host: us.multi-region.example.com
region: us-east-1

replicaCount: 3

config:
loftHost: multi-region.example.com
database:
enabled: true
dataSource: "mysql://kine@tcp(mariadb-multi-region.xxxxxxxxxxxx.us-east-1.rds.amazonaws.com:3306)/kine"
identityProvider: "aws"
extraArgs:
- --datastore-max-open-connections=20
- --datastore-max-idle-connections=0

# Cost control requires a single-region database and is not compatible
# with the shared Kine backend used in multi-region deployments.
costControl:
enabled: false

agentValues:
replicaCount: 3

E.U. region (save as EU_VALUES_FILE)

admin:
email: admin@example.com

multiRegion:
enabled: true
host: eu.multi-region.example.com
region: eu-west-1

replicaCount: 3

config:
loftHost: multi-region.example.com
database:
enabled: true
dataSource: "mysql://kine@tcp(mariadb-multi-region.xxxxxxxxxxxx.us-east-1.rds.amazonaws.com:3306)/kine"
identityProvider: "aws"
extraArgs:
- --datastore-max-open-connections=20
- --datastore-max-idle-connections=0

# Cost control requires a single-region database and is not compatible
# with the shared Kine backend used in multi-region deployments.
costControl:
enabled: false

agentValues:
replicaCount: 3

Install the platform on each cluster using its values file.

U.S. region

Modify the following with your specific values to generate a copyable command:
vcluster platform start \
--namespace vcluster-platform \
--kube-context arn:aws:eks:us-east-1:123456789012:cluster/platform-multi-region-us-east-1 \
--values platform-us-east-1-values.yaml \
--no-tunnel

E.U. region

Modify the following with your specific values to generate a copyable command:
vcluster platform start \
--namespace vcluster-platform \
--kube-context arn:aws:eks:eu-west-1:123456789012:cluster/platform-multi-region-eu-west-1 \
--values platform-eu-west-1-values.yaml \
--no-tunnel

Setting multiRegion.enabled=true automatically configures:

  • Embedded Kubernetes (Kine) with the shared database
  • Leader election across regions
  • Multi-region platform license check

Step 6 - Configure HTTPS with AWS Certificate Manager (ACM)​

Request a certificate in each region that covers both the shared DNS domain and the region-specific subdomain. The wildcard *.multi-region.example.com covers the regional subdomains (us.multi-region.example.com, eu.multi-region.example.com), and multi-region.example.com is added as a SAN to cover the apex.

Run this command in each region. The command uses the AWS_REGION page variable — run it a second time after setting EU_REGION as the region value to request the certificate there too.

aws acm request-certificate \
--region us-east-1 \
--domain-name "multi-region.example.com" \
--subject-alternative-names "*.multi-region.example.com" \
--validation-method DNS

Get the certificate ARN from the output and describe the certificate. Replace <CERTIFICATE_ARN_ID> with the ARN ID generated from the command above.

Modify the following with your specific values to generate a copyable command:
aws acm describe-certificate \
--region us-east-1 \
--certificate-arn arn:aws:acm:us-east-1:123456789012:certificate/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

Add DNS validation CNAMEs in Route 53 and wait until certificate status is ISSUED.

note

You can also do this step by setting up cert-manager in the clusters instead of using AWS ACM.

Step 7 - Create Ingress (ALB)​

Apply the Ingress manifest in each cluster to provision an ALB and route traffic to the loft service.

Modify the following with your specific values to generate a copyable command:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: loft
namespace: vcluster-platform
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/listen-ports: '[{"HTTP":80},{"HTTPS":443}]'
alb.ingress.kubernetes.io/certificate-arn: "arn:aws:acm:us-east-1:123456789012:certificate/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
alb.ingress.kubernetes.io/ssl-redirect: "443"
alb.ingress.kubernetes.io/idle-timeout: "3600"
alb.ingress.kubernetes.io/healthcheck-path: /healthz
alb.ingress.kubernetes.io/success-codes: "200"
spec:
ingressClassName: alb
rules:
- host: us.multi-region.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: loft
port:
number: 80
- host: multi-region.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: loft
port:
number: 80

Step 8 - Configure Route 53 latency-based routing​

Create health checks​

Create an HTTPS health check for each regional ALB. Route 53 uses these to detect when a region is unavailable and fail over traffic automatically.

U.S. region

aws route53 create-health-check \
--caller-reference "us-east-1-platform-healthz" \
--health-check-config '{
"FullyQualifiedDomainName": "us.multi-region.example.com",
"Port": 443,
"Type": "HTTPS",
"ResourcePath": "/healthz",
"RequestInterval": 10,
"FailureThreshold": 3,
"EnableSNI": true
}'

E.U. region

aws route53 create-health-check \
--caller-reference "eu-west-1-platform-healthz" \
--health-check-config '{
"FullyQualifiedDomainName": "eu.multi-region.example.com",
"Port": 443,
"Type": "HTTPS",
"ResourcePath": "/healthz",
"RequestInterval": 10,
"FailureThreshold": 3,
"EnableSNI": true
}'

Note the health check IDs from the output. You can tag them for easier identification:

aws route53 change-tags-for-resource \
--resource-type healthcheck --resource-id xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx \
--add-tags Key=Name,Value=us-platform-healthz

Create DNS records​

Create latency-based A (Alias) records in Route 53 pointing to each regional ALB. Attach the health checks created above so that Route 53 can fail over traffic when a region becomes unavailable.

Replace <US_HEALTH_CHECK_ID> and <EU_HEALTH_CHECK_ID> with the IDs from the previous step, and <US_ALB_HOSTED_ZONE_ID>, <EU_ALB_HOSTED_ZONE_ID> with the canonical hosted zone IDs of each ALB.

Modify the following with your specific values to generate a copyable command:
aws route53 change-resource-record-sets \
--hosted-zone-id Z1234567890ABC \
--change-batch '{
"Changes": [
{
"Action": "UPSERT",
"ResourceRecordSet": {
"Name": "multi-region.example.com",
"Type": "A",
"SetIdentifier": "us-east-1",
"Region": "us-east-1",
"HealthCheckId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"AliasTarget": {
"HostedZoneId": "ZXXXXXXXXUS",
"DNSName": "k8s-vcluster-loft-xxxxxxxxxx-xxxxxxxxx.us-east-1.elb.amazonaws.com",
"EvaluateTargetHealth": true
}
}
},
{
"Action": "UPSERT",
"ResourceRecordSet": {
"Name": "multi-region.example.com",
"Type": "A",
"SetIdentifier": "eu-west-1",
"Region": "eu-west-1",
"HealthCheckId": "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy",
"AliasTarget": {
"HostedZoneId": "ZXXXXXXXXEU",
"DNSName": "k8s-vcluster-loft-xxxxxxxxxx-xxxxxxxxx.eu-west-1.elb.amazonaws.com",
"EvaluateTargetHealth": true
}
}
}
]
}'

Also create A records for the region-specific subdomains used by the custom DERP server and health checks. Replace <US_ALB_HOSTED_ZONE_ID>, <EU_ALB_HOSTED_ZONE_ID> with the canonical hosted zone IDs and <US_ALB_DNS_NAME>, <EU_ALB_DNS_NAME> with the DNS names of each ALB.

aws route53 change-resource-record-sets \
--hosted-zone-id Z1234567890ABC \
--change-batch '{
"Changes": [
{
"Action": "UPSERT",
"ResourceRecordSet": {
"Name": "us.multi-region.example.com",
"Type": "A",
"AliasTarget": {
"HostedZoneId": "ZXXXXXXXXUS",
"DNSName": "k8s-vcluster-loft-xxxxxxxxxx-xxxxxxxxx.us-east-1.elb.amazonaws.com",
"EvaluateTargetHealth": true
}
}
},
{
"Action": "UPSERT",
"ResourceRecordSet": {
"Name": "eu.multi-region.example.com",
"Type": "A",
"AliasTarget": {
"HostedZoneId": "ZXXXXXXXXEU",
"DNSName": "k8s-vcluster-loft-xxxxxxxxxx-xxxxxxxxx.eu-west-1.elb.amazonaws.com",
"EvaluateTargetHealth": true
}
}
}
]
}'

Verify health checks​

Confirm both health checks are healthy before proceeding:

aws route53 get-health-check-status --health-check-id xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx \
--query 'HealthCheckObservations[].{Region:Region,Status:StatusReport.Status}' \
--output table
Important

Without health checks attached to the latency-based records, Route 53 can't detect regional failures and continues routing traffic to an unavailable region. Always verify that health checks are healthy before proceeding.

Step 9 - Deploy the agent on the clusters​

The agent must be deployed in a different namespace than the platform (for example, vcluster-agent). The agentValues block in the platform values files (Step 5) controls the agent's replica count, leader election, and other settings.

Use the vCluster CLI to add each cluster as a connected cluster. Generate an access token from the platform UI under Users & Teams > Access Keys, or by running vcluster platform get token.

Modify the following with your specific values to generate a copyable command:
vcluster platform add cluster platform-multi-region-us-east-1 \
--namespace vcluster-agent \
--display-name my-cluster \
--values 'https://multi-region.example.com/clusters/agent-values/platform-multi-region-us-east-1?token=your-access-token'

Repeat on the second cluster, substituting EU_CLUSTER_NAME for the cluster name and providing a new DISPLAY_NAME.

Result​

You now have a fully operational multi-region vCluster Platform deployment with:

  • Two EKS clusters (U.S. + E.U.)
  • Shared Kine database in an isolated VPC with IAM-based authentication (Pod Identity)
  • VPC peering between each cluster VPC and the database VPC
  • Regional ALBs with extended idle timeout
  • ACM wildcard certificates
  • Route 53 latency-based routing with health checks for automatic failover
  • Platform deployed on both clusters sharing the same Kine database