Microsoft Tech Community is in Read Only mode.  Please enjoy browsing our content while we complete our platform upgrade.

Blog Post

Apps on Azure Blog
8 MIN READ

Istio - A Robust, Extensible Service Mesh for K8s

monojit18's avatar
monojit18
Microsoft
Feb 04, 2022

What is Service Mesh?

Service Mesh provides managing capabilities for the micro-services hosted in the Kubernetes cluster uniformly and decouples them from the Applications (Microservices) layer.

 

This makes it a great tool for Infrastructure architects as well as Developer architects easily Manage, Observe and Secure the cluster.

 

 

Features

  • Observability - Monitor applications hosted inside the cluster

  • Traffic Splitting - Split Ingress Traffic to different versions of an API. Helps  to perform Blue/Green Deployment, A/B Testing, Fault Injection

  • Distributed Tracing - Trace/Compare Service to Service calls with visualisation

  • Circuit Breaking - Limit impact of failures due to uncertainty in Network and make services resilient

  • Mirroring - Allows copying traffic directed to one Service to another Service without affecting the primary traffic anyway. This is also called Shadowing

Considerations

  • Complexity - More complex for simple requirements

  • Resource Overhead - Additional components needs additional resources - CPU, Memory

  • Additional Latency - Proxies, Policy checks adds latency; so might be a challenge for highly latency sensitive applications

 

Istio Service Mesh

A rich Service Mesh tool designed to provide deep insights of applications being deployed inside the K8s cluster, details of the cluster infrastructure and ability to extend by allowing connection to another K8s cluster or other external services.

 

Istio comes with its own visualisation through kiali dashboard

 

Istio Components

 

Gateway
  • Defines a LoadBalancer at the edge of the Service Mesh receiving incoming or outgoing connections
  • Single Gateway can contain multiple hosts

  • Scoped to a Namespace

Virtual Service
  • Defines the traffic routing rules for a host
  • Single Virtual Service can be mapped with multiple Gateways

  • Single Virtual Service can contain multiple hosts

  • Scoped to a Namespace

Destination Rule
  • Defines Policies to traffic post Routing

  • LoadBalancing, Connection Pool, Outlier

  • Scoped to a Namespace

Service Entry
  • Enables services within the mesh to connect to services which are not registered with the mesh

  • Destination service endpoints can be External to mesh or even outside the cluster
  • Enables the most important concept called Shadowing or Mirroring

 

Let us now delve into this by deploying Istio on an existing AKS cluster. This article would assume that the reader already has created and AKS cluster of any form and is able to access the cluster

 

Plan

  • Prepare two AKS clusters - Primary and Secondary
  • Download Istio command line - istioctl
  • Deploy Istio on both the clusters
  • Deploy multiple applications onto the Primary cluster
  • Check different Service Mesh features on the Primary cluster
  • Deploy specific version of one application (HelloWorld) onto Secondary cluster. Implement Service Mirroring to send live traffic from Primary cluster to Secondary cluster
  • Source Code

 

Set CLI Variables

 

tenantId=""
subscriptionId=""
location="eastus"
clusterName="primary-mesh-cluster"
aksResourceGroup="primary-workshop-rg"
acrName="srvmeshacr"
baseFolderPath=""
primaryResourceGroup=$aksResourceGroup
primaryClusterName=$clusterName
secondaryResourceGroup="secondary-workshop-rg"
secondaryClusterName="secondary-mesh-cluster"
primaryAcrName=$acrName
istioPath="$baseFolderPath/Istio"

 

 

 

Login to Azure

 

#Login to Azure
az login --tenant $tenantId

#Check Selected Subscription
az account show

#Set appropriate Subscription, if needed
#az account set -s $subscriptionId

 

 

 

Configure Primary Cluster

 

#Set Env Variable for Primary Cluster
#This helps to switch context easily between multiple clusters
export CTX_CLUSTER1=primary

#Connect to Public AKS Cluster with Primary Context
az aks get-credentials -g $aksResourceGroup -n $clusterName --context $CTX_CLUSTER1

#Additional helpful commands
#Switch context between multiple clusters
kubectl config use-context <context>

 

 

 

Download Istio

 

#Download Istio binary
curl -L https://istio.io/downloadIstio | sh -

#Download specific version of Istio viz. 1.11.3
curl -L https://istio.io/downloadIstio | ISTIO_VERSION=1.11.3 TARGET_ARCH=x86_64 sh -

#The istioctl client binary in the bin/ directory
#Add the istioctl client to your path (Linux or macOS):
export PATH=$PWD/bin:$PATH

 

 

 

Check Cluster Health

 

kubectl get no --context=$CTX_CLUSTER1
kubectl get ns --context=$CTX_CLUSTER1

 

 

 

Create Namespaces

 

#Create namespaces for Istio
kubectl create namespace istio-system --context $CTX_CLUSTER1
kubectl create namespace primary --context $CTX_CLUSTER1

 

 

 

Install Istio CLI

 

#Install Istio CLI
#Select Default Istio Profile settings
#Ingress Gateway with Public IP Address
istioctl install --context=$CTX_CLUSTER1 --set profile=default -y

#Install Istio with custom configurations
#Ingress Gateway with Privae IP Address
#Another Publicly exposed LoadBalancer Service(L7) would be needed to access this Private IP
istioctl install --context=$CTX_CLUSTER1 -f $istioPath/Components/values-primary.yaml -y

#Following link describes - how to configure Application Gateway with AKS cluster
#This need to be used if Ingress Gateway is having Private IP
https://docs.microsoft.com/en-us/azure/application-gateway/configuration-http-settings 

 

 

 

 

Configure Istio in Primary Cluster

Inject Istio into Namespaces

 

#Inject Istio into primary namespace
#Ensures sidecar container to be added for every deployment in this namespace
kubectl label namespace primary istio-injection=enabled --context=$CTX_CLUSTER1

#Disable sidecar injection from primary namespace
#kubectl label namespace primary istio-injection=disabled --context=$CTX_CLUSTER1

 

 

 

Install Addons

 

#Install Istio Addons
#This primarily installs all dependencies for observability by Istio viz. Grafana, Kiali dashboard etc.
kubectl apply -f $istioPath/Components/samples/addons --context=$CTX_CLUSTER1

#Check rollout status of the Kiali deployment - usually takes sometime
kubectl rollout status deployment/kiali -n istio-system

#Launch Kiali as background process
istioctl dashboard kiali&

#Might need to Press CTRL+C to allow the job to continue in teh background
#Bring job to foreground - fg [<job-number>]

#Check Deployments within istio-system
#Istio Ingress gateway with public or private IP
kubectl get svc -n istio-system

 

 

 

Deploy BookInfo App

 

#Install BookInfo app onto the cluster
kubectl apply -f $istioPath/Examples/BookInfo/bookinfo.yaml -n primary

#Check Deployed Components
kubectl get svc -n primary --context=$CTX_CLUSTER1
kubectl get pods -n primary --context=$CTX_CLUSTER1

#Quick check to test BookInfo app
podName=$(kubectl get pod -l app=ratings -n primary -o jsonpath='{.items[0].metadata.name}')
kubectl exec $podName -n primary -c ratings -- curl -sS productpage:9080/productpage | grep -o "<title>.*</title>"

 

 

 

Expose Microservices thru an Ingress Gateway

 

#Need a Gateway to expose the service outside
#Check Routing definitions
#Replace <dns-name>
kubectl apply -f $istioPath/Examples/Networking/primary-gateway.yaml -n primary --context=$CTX_CLUSTER1

#Get GATEWAY_URL
kubectl get svc istio-ingressgateway -n istio-system
export INGRESS_HOST=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
export INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].port}')
export SECURE_INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="https")].port}')

#Call services using GATEWAY_URL
export GATEWAY_URL=$INGRESS_HOST:$INGRESS_PORT
echo "$GATEWAY_URL"

#Try the follwoing URL in the Browser or do a cUrl
curl http://$GATEWAY_URL/product

 

 

 

Expose Kiali dashboard service through a Gateway

 

#Need a Gateway to expose the Kiali service outside
#Check Routing definitions
#Replace <dns-name>
kubectl apply -f $istioPath/Examples/Networking/kiali-gateway.yaml -n istio-system --context=$CTX_CLUSTER1

#Launch Kiali in the browser
http://$INGRESS_HOST:$INGRESS_PORT/

#If used with Applicagtion Gateway then use appropriate Host header in Http Settings

 

 

 

 

Observability

 

 

Traffic Splitting

 

#Traffic Shifting
kubectl apply -f $istioPath/Examples/HelloWorld/helloworld-app.yaml -n primary --context=$CTX_CLUSTER1
kubectl get po -n primary --context=$CTX_CLUSTER1

#Check Routing definitions
kubectl apply -f $istioPath/Examples/Networking/primary-gateway.yaml -n primary --context=$CTX_CLUSTER1

#Destination Rule
kubectl apply -f $istioPath/Examples/Networking/helloworld-destination-rule.yaml -n primary --context=$CTX_CLUSTER1

kubectl apply -f $istioPath/Examples/HelloWorld/helloworld-app-v2.yaml -n primary --context=$CTX_CLUSTER1
kubectl get po -n primary --context=$CTX_CLUSTER1

#Check Routing behaviour
#UNCOMMENT: Test Traffic Shifting
#Update Primary Gateway Routes - Change Traffic weight
kubectl apply -f $istioPath/Examples/Networking/primary-gateway.yaml -n primary --context=$CTX_CLUSTER1

#Destination Rule
kubectl apply -f $istioPath/Examples/Networking/helloworld-destination-rule.yaml -n primary --context=$CTX_CLUSTER1

#Check Routing behaviour again

 

 

 

 

Blue/Green

 

#Blue/Green
#Deploy PodInfo Blue
kubectl apply -f $istioPath/Examples/BlueGreen/podinfo-blue.yaml -n primary --context=$CTX_CLUSTER1

#Check Routing definitions
kubectl apply -f $istioPath/Examples/Networking/primary-gateway.yaml -n primary --context=$CTX_CLUSTER1

#Destination Rule
kubectl apply -f $istioPath/Examples/Networking/podinfo-destination-rule.yaml -n primary --context=$CTX_CLUSTER1

#Deploy PodInfo green
kubectl apply -f $istioPath/Examples/BlueGreen/podinfo-green.yaml -n primary --context=$CTX_CLUSTER1

#Check Routing behaviour
#UNCOMMENT: Test Blue/Green
#Update Primary Gateway Routes - Change Traffic weight
kubectl apply -f $istioPath/Examples/Networking/primary-gateway.yaml -n primary --context=$CTX_CLUSTER1

#Destination Rule
kubectl apply -f $istioPath/Examples/Networking/podinfo-destination-rule.yaml -n primary --context=$CTX_CLUSTER1

#Check Routing behaviour again

 

 

 

 

 

Service Mirroring

 

Configure Secondary Cluster

 

#Service Mirroring or Shadowing
#Create Secondary Cluster - CLI or Portal
export CTX_CLUSTER2=secondary

#Connect to Public AKS Cluster with Primary Context
az aks get-credentials -g $primaryResourceGroup -n $secondaryClusterName --context $CTX_CLUSTER2

kubectl config use-context $CTX_CLUSTER2

#Check Cluster Health - Secondary
kubectl get no --context=$CTX_CLUSTER2
kubectl get ns --context=$CTX_CLUSTER2
kubectl create namespace istio-system --context $CTX_CLUSTER2
kubectl create namespace secondary --context $CTX_CLUSTER2

#Install Istio CLI
#Select Default Istio Profile settings
#Ingress Gateway with Public IP Address
istioctl install --context=$CTX_CLUSTER2 --set profile=default -y

#Install Istio with custom configurations
#Ingress Gateway with Privae IP Address
#Another Publicly exposed LoadBalancer Service(L7) would be needed to access this Private IP
istioctl install --context=$CTX_CLUSTER2 -f $istioPath/Components/values-secondary.yaml -y

#Inject Istio into Secondary namespace of the cluster 
#This ensures sidecar container to be added for every deployment in this namespace
kubectl label namespace secondary istio-injection=enabled --context=$CTX_CLUSTER2

#Install Istio Addons
#This primarily installs all dependencies for observability by Istio viz. Grafana, Kiali dashboard etc.
kubectl apply -f $istioPath/Components/samples/addons --context=$CTX_CLUSTER2

kubectl get svc istio-ingressgateway -n istio-system
export INGRESS_HOST=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
export INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].port}')
export SECURE_INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="https")].port}')

export GATEWAY_URL2=$INGRESS_HOST:$INGRESS_PORT
echo "$GATEWAY_URL2"

kubectl apply -f $istioPath/Examples/HelloWorld/helloworld-app-v2.yaml -n secondary --context=$CTX_CLUSTER2
kubectl get po -n secondary --context=$CTX_CLUSTER2

#Need a Gateway to expose the service outside
#Check Routing definitions
#Replace <dns-name>
kubectl apply -f $istioPath/Examples/Networking/secondary-gateway.yaml -n secondary --context=$CTX_CLUSTER2

#Destination Rule
kubectl apply -f $istioPath/Examples/Networking/helloworld-v2-destination-rule.yaml -n secondary --context=$CTX_CLUSTER2

kubectl get svc -n secondary --context=$CTX_CLUSTER2
kubectl describe svc -n secondary --context=$CTX_CLUSTER2
kubectl get svc -A --context=$CTX_CLUSTER2

 

 

 

 

Configure Primary to Mirror services

 

#Switch to the Primary Cluster
kubectl config use-context $CTX_CLUSTER1

#Check Routing definitions
kubectl apply -f $istioPath/Examples/Networking/primary-gateway.yaml -n primary --context=$CTX_CLUSTER1

#Deploy components so that Mirroring can work
#Replace <dns-name>
kubectl apply -f $istioPath/Examples/Networking/primary-serviceentry.yaml -n primary --context=$CTX_CLUSTER1

#Destination Rule
#Replace <dns-name>
kubectl apply -f $istioPath/Examples/Networking/helloworld-destination-rule.yaml -n primary --context=$CTX_CLUSTER1

kubectl get svc -n primary --context=$CTX_CLUSTER1
kubectl describe svc -n primary --context=$CTX_CLUSTER1
kubectl get svc -A --context=$CTX_CLUSTER1

#Call helloworld-v1
#Observe that all calls being replicated to helloworld-v2 of secondary cluster

 

 

 

 

 

Circuit Breaker

Destination Rule with Circuit Breaker configurations

 

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: httpbin
spec:
  host: httpbin
  trafficPolicy:
    connectionPool:
      tcp:
        maxConnections: 1
      http:
        http1MaxPendingRequests: 1
        maxRequestsPerConnection: 1
    outlierDetection:
      consecutive5xxErrors: 1
      interval: 1s
      baseEjectionTime: 3m
      maxEjectionPercent: 100
EOF

 

 

 

#Circuit Breaker
#Deploy HttpBin App
kubectl apply -f $istioPath/Examples/HttpBin/httpbin.yaml -n primary --context=$CTX_CLUSTER1
kubectl apply -f $istioPath/Examples/Networking/httpbin-gateway.yaml -n primary --context=$CTX_CLUSTER1

#Deploy HttpBin Destination Rule
kubectl apply -f $istioPath/Examples/Networking/httpbin-destination-rule.yaml -n primary --context=$CTX_CLUSTER1

#Check Routing behaviour
#UNCOMMENT: Test Circuit Breaking
kubectl apply -f $istioPath/Examples/Networking/primary-gateway.yaml -n primary --context=$CTX_CLUSTER1

#Generate Load - e.g. JMeter or Fortio or any other Laod Testing client

#Deploy Fortio client
kubectl apply -f $istioPath/Examples/HttpBin/sample-client/fortio-deploy.yaml -n primary --context=$CTX_CLUSTER1

#Make calls from Fortio client
export FORTIO_POD=$(kubectl get pods -l app=fortio -o 'jsonpath={.items[0].metadata.name}')
kubectl exec "$FORTIO_POD" -c fortio -- /usr/bin/fortio curl -quiet http://httpbin:8000/get

#Check Routing behaviour
#Observer many calls being failed and circuit is broken and joined automatically
#Change parameters in the $istioPath/Examples/Networking/httpbin-destination-rule.yaml file
#Play around and see the chnage in the behaviour

 

 

 

 

Distributed Tracing

 

 

CleanUP

 

#Cleanup
#Uninstall Istio setup - primary cluster
istioctl x uninstall --set profile=default --purge --context=$CTX_CLUSTER1
kubectl delete namespace istio-system --context=$CTX_CLUSTER1
  
#Uninstall Istio setup - secondary cluster
istioctl x uninstall --set profile=default --purge --context=$CTX_CLUSTER2
kubectl delete namespace istio-system --context=$CTX_CLUSTER2

 

 

 

 

 

 

 

 

Updated Feb 04, 2022
Version 3.0