Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Istio multi-cluster, multi-network, multi-primary blueprint #1899

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all 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
210 changes: 210 additions & 0 deletions patterns/istio-multi-network-multi-primary/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
# Istio multi-network, multi-primary on EKS

## Business Use Cases for Istio Multi-Cluster

**Fault Tolerance and High Availability:** For applications that require global reach or disaster recovery capabilities, Istio Multi-Cluster allows you to distribute your services across clusters in multiple geographic regions or availability zones enhancing resilience to failures and outages.. This improves availability, fault tolerance, and reduces latency by serving users from the nearest cluster.

**Isolation and Multitenancy:** In large organizations with multiple teams or business units, Istio Multi-Cluster allows you to isolate workloads into separate clusters while still maintaining a unified service mesh. This promotes multitenancy, security, and resource isolation between different applications or environments. It also strengthens security posture by implementing strict access controls and network segmentation, preventing unauthorized inter-service communications.

**Compliance and Regulatory Requirements:** In some industries, there may be requirements to keep certain data or workloads in specific geographic regions or environments. Istio Multi-Cluster enables you to deploy and manage applications across these isolated environments while still maintaining a unified service mesh. Istio's multi-cluster architecture ensures data segregation and compliance with regulations like GDPR and PCI DSS through Istio's multi-cluster architecture.

**Scalability, Performance and Load Balancing:** Istio Multi-Cluster achieves horizontal scaling and performance optimization by adding clusters in different regions, catering to traffic surges and reducing latency. Istio Multi-Cluster also provides load balancing across clusters, enabling you to distribute the load and avoid overloading a single cluster.

**Canary Deployments and A/B Testing:** When rolling out new versions of applications, you can use Istio Multi-Cluster to deploy the new version to a subset of clusters, allowing you to test and validate the changes before rolling them out to all clusters. This enables canary deployments and A/B testing across multiple clusters.

**Migration and Modernization:** If you're migrating applications from legacy systems to Kubernetes or modernizing your applications, Istio Multi-Cluster can help you manage the transition by allowing you to run the old and new versions of your applications in separate clusters while still maintaining connectivity and consistent policies.

![Istio Multi-Cluster Architecture](istio-multi-cluster-architecture.png "Istio Multi-Cluster Architecture on Amazon EKS")

## Prerequisites

Ensure that you have installed the following tools locally:

1. [awscli](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html)
2. [kubectl](https://kubernetes.io/docs/tasks/tools/)
3. [terraform](https://learn.hashicorp.com/tutorials/terraform/install-cli)
4. [istioctl](https://istio.io/latest/docs/ops/diagnostic-tools/istioctl/)

## Deploy

To deploy the terraform repo, run the commands shown below:
```sh
./scripts/deploy.sh
```

After running the command successfully, set the kubeconfig for both EKS clusters:
```sh
source scripts/set-cluster-contexts.sh
```

> **Note:** If using different cluster names other than the default `eks-1` and
`eks-2`, use the following command:

```sh
source scripts/set-cluster-contexts.sh eks_cluster_name_1 eks_cluster_name_2
```


## Testing

### Readiness of the Istio Gateway loadbalancers

Before you could do any testing, you need to ensure that:
* The loadbalancer for `istio-eastwestgateway` service is ready for the traffic
* The loadblanncer target groups have their targets ready.

Use the following script to test the readiness of the LBs:
```sh
./scripts/check-lb-readiness.sh
```
> **Note:** If using different cluster names other than the default `eks-1` and
`eks-2` use the following command:
```sh
./scripts/check-lb-readiness.sh eks_cluster_name_1 eks_cluster_name_2
```


You should see an output similar to below before proceeding any further:
```
Updated context arn:aws:eks:us-west-2:XXXXXXXXXXXX:cluster/eks-1 in /Users/maverick/.kube/config
Updated context arn:aws:eks:us-west-2:XXXXXXXXXXXX:cluster/eks-2 in /Users/maverick/.kube/config

Readiness check for arn:aws:eks:us-west-2:XXXXXXXXXXXX:cluster/eks-1:
{
"Target": {
"Id": "10.1.21.197",
"Port": 15443,
"AvailabilityZone": "us-west-2b"
},
"HealthCheckPort": "15443",
"TargetHealth": {
"State": "healthy"
}
}

Readiness check for arn:aws:eks:us-west-2:XXXXXXXXXXXX:cluster/eks-2:
{
"Target": {
"Id": "10.2.23.10",
"Port": 15443,
"AvailabilityZone": "us-west-2b"
},
"HealthCheckPort": "15443",
"TargetHealth": {
"State": "healthy"
}
}
```

### Cross-Cluster Sync

Run the following commands to ensure that the public Load Balancer IP addresses
are displayed in the output as shown.

```sh
./scripts/check-cross-cluster-sync.sh
```

> **Note:** If using different cluster names other than the default `eks-1` and
`eks-2` use the following command:
```sh
./scripts/check-cross-cluster-sync.sh eks_cluster_name_1 eks_cluster_name_2
```


The output should be similar to:
```
Updated context arn:aws:eks:us-west-2:XXXXXXXXXXXX:cluster/eks-1 in /Users/maverick/.kube/config
Updated context arn:aws:eks:us-west-2:XXXXXXXXXXXX:cluster/eks-2 in /Users/maverick/.kube/config

Cross cluster sync check for arn:aws:eks:us-west-2:XXXXXXXXXXXX:cluster/eks-1:
10.1.24.17:5000 HEALTHY OK outbound|5000||helloworld.sample.svc.cluster.local
44.227.39.238:15443 HEALTHY OK outbound|5000||helloworld.sample.svc.cluster.local
44.229.207.145:15443 HEALTHY OK outbound|5000||helloworld.sample.svc.cluster.local
52.33.147.49:15443 HEALTHY OK outbound|5000||helloworld.sample.svc.cluster.local

Cross cluster sync check for arn:aws:eks:us-west-2:XXXXXXXXXXXX:cluster/eks-2:
10.2.30.251:5000 HEALTHY OK outbound|5000||helloworld.sample.svc.cluster.local
34.213.174.24:15443 HEALTHY OK outbound|5000||helloworld.sample.svc.cluster.local
54.148.164.231:15443 HEALTHY OK outbound|5000||helloworld.sample.svc.cluster.local
54.148.184.188:15443 HEALTHY OK outbound|5000||helloworld.sample.svc.cluster.local
```

If you see public IP addresses in the output for both the clusters proceed
further to test multi-cluster communication.

### Cross-cluster Load-Balancing

Run the following command to check cross-cluster loadbalancing from the first
cluster.

```
for i in {1..10}
do
kubectl exec --context="${CTX_CLUSTER1}" -n sample -c sleep \
"$(kubectl get pod --context="${CTX_CLUSTER1}" -n sample -l \
app=sleep -o jsonpath='{.items[0].metadata.name}')" \
-- curl -sS helloworld.sample:5000/hello
done
```
Also test similar command to check cross-cluster loadbalancing from the second
cluster.

```
for i in {1..10}
do
kubectl exec --context="${CTX_CLUSTER2}" -n sample -c sleep \
"$(kubectl get pod --context="${CTX_CLUSTER2}" -n sample -l \
app=sleep -o jsonpath='{.items[0].metadata.name}')" \
-- curl -sS helloworld.sample:5000/hello
done
```

In either case the output should be similar to:

```
Hello version: v1, instance: helloworld-v1-867747c89-7vzwl
Hello version: v2, instance: helloworld-v2-7f46498c69-5g9rk
Hello version: v1, instance: helloworld-v1-867747c89-7vzwl
Hello version: v1, instance: helloworld-v1-867747c89-7vzwl
Hello version: v2, instance: helloworld-v2-7f46498c69-5g9rk
Hello version: v1, instance: helloworld-v1-867747c89-7vzwl
Hello version: v2, instance: helloworld-v2-7f46498c69-5g9rk
Hello version: v1, instance: helloworld-v1-867747c89-7vzwl
Hello version: v1, instance: helloworld-v1-867747c89-7vzwl
Hello version: v2, instance: helloworld-v2-7f46498c69-5g9rk
```

## Destroy
```sh
./scripts/destroy.sh
```

## Troubleshooting

There are many things that can go wrong when deploying a complex solutions such
as this, Istio multi-primary on different networks.

### Ordering in Terraform deployment

The ordering is important when deploying the resources with Terraform and here
it is:
1. Deploy the VPCs and EKS clusters
2. Deploy the `cacerts` secret in the `istio-system` namespace in both clusters
4. Deploy the control plane `istiod` in both clusters
5. Deploy the rest of the resources, including Helm Chart `multicluster-gateway-n-apps`
in both clusters.

The `multicluster-gateway-n-apps` Helm chart includes the following key resources:
1. `Deployment`, `Service Account` and `Service` definitions for `sleep` app
2. `Deployment` and `Service` definitions for `helloworld` app
3. Static `Gateway` definition of `cross-network-gateway` in `istio-ingress` namespace
4. Templated `Secret` definition of `istio-remote-secret-*`



## Documentation Links

1. [Install Multi-Primary on different networks](https://istio.io/latest/docs/setup/install/multicluster/multi-primary_multi-network/)
2. [Verifying cross-cluster traffic](https://istio.io/latest/docs/setup/install/multicluster/verify/#verifying-cross-cluster-traffic)
3. [Multicluster Troubleshooting](https://istio.io/latest/docs/ops/diagnostic-tools/multicluster/)
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
apiVersion: v2
name: multicluster-gateway-n-apps
description: A Helm chart for Kubernetes

# A chart can be either an 'application' or a 'library' chart.
#
# Application charts are a collection of templates that can be packaged into versioned archives
# to be deployed.
#
# Library charts provide useful utilities or functions for the chart developer. They're included as
# a dependency of application charts to inject those utilities and functions into the rendering
# pipeline. Library charts do not define any templates and therefore cannot be deployed.
type: application

# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.1.0

# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes.
appVersion: "1.16.0"
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: cross-network-gateway
namespace: istio-ingress
spec:
selector:
istio: eastwestgateway
servers:
- port:
number: 15443
name: tls
protocol: TLS
tls:
mode: AUTO_PASSTHROUGH
hosts:
- "*.local"

Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: helloworld-{{ .Values.version }}
labels:
app: helloworld
version: {{ .Values.version }}
spec:
replicas: 1
selector:
matchLabels:
app: helloworld
version: {{ .Values.version }}
template:
metadata:
labels:
app: helloworld
version: {{ .Values.version }}
spec:
containers:
- name: helloworld
image: docker.io/istio/examples-helloworld-{{ .Values.version }}
resources:
requests:
cpu: "100m"
imagePullPolicy: IfNotPresent #Always
ports:
- containerPort: 5000
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
apiVersion: v1
kind: Service
metadata:
name: helloworld
labels:
app: helloworld
service: helloworld
spec:
ports:
- port: 5000
name: http
selector:
app: helloworld
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
apiVersion: v1
kind: Secret
metadata:
annotations:
networking.istio.io/cluster: {{ .Values.clusterName }}
labels:
istio/multiCluster: "true"
name: istio-remote-secret-{{ .Values.clusterName }}
namespace: istio-system
stringData:
{{ .Values.clusterName }}: |
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: {{ .Values.certificateAuthorityData }}
server: {{ .Values.server }}
name: {{ .Values.clusterName }}
contexts:
- context:
cluster: {{ .Values.clusterName }}
user: {{ .Values.clusterName }}
name: {{ .Values.clusterName }}
current-context: {{ .Values.clusterName }}
kind: Config
preferences: {}
users:
- name: {{ .Values.clusterName }}
user:
token: {{ .Values.token }}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: sleep
spec:
replicas: 1
selector:
matchLabels:
app: sleep
template:
metadata:
labels:
app: sleep
spec:
terminationGracePeriodSeconds: 0
serviceAccountName: sleep
containers:
- name: sleep
image: curlimages/curl
command: ["/bin/sleep", "infinity"]
imagePullPolicy: IfNotPresent
volumeMounts:
- mountPath: /etc/sleep/tls
name: secret-volume
volumes:
- name: secret-volume
secret:
secretName: sleep-secret
optional: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
apiVersion: v1
kind: Service
metadata:
name: sleep
labels:
app: sleep
service: sleep
spec:
ports:
- port: 80
name: http
selector:
app: sleep
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: sleep
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
version: v1
1 change: 1 addition & 0 deletions patterns/istio-multi-network-multi-primary/data.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
data "aws_availability_zones" "available" {}
Loading
Loading