Deploy a Self-Healing Microservices Platform with Istio Service Mesh
Install Istio on EKS, deploy interconnected microservices, configure canary deployments, mutual TLS, circuit breaking, and visualise with Kiali.
Domains & Technologies
Blueprint Walkthrough
Architecture Overview
This project deploys a complete service mesh using Istio on Kubernetes. A service mesh solves a fundamental problem — in a microservices architecture with 20 or 30 services, how do you control traffic between them, secure service-to-service communication, and understand what is happening inside your cluster without changing application code?
Istio answers all three questions by injecting a small proxy (Envoy) as a sidecar into every pod. All network traffic flows through these proxies, giving you traffic control, security, and observability for free regardless of what language your services are written in.
This is how PhonePe manages communication between their payment, wallet, and notification services — a service mesh that handles routing, retries, timeouts, and circuit breaking so application developers never have to write that logic themselves.
+------------------+ | Kiali UI | <- Visualises the entire service graph | (Graph/Mesh) | +------------------+ | +------------------+ | Istiod | <- Control plane: configures all proxies | (Control Plane)| +------------------+ / | \ / | \+---------+ +--------+ +----------+| Service | | Service| | Service || A | | B | | C || [Envoy] | |[Envoy] | | [Envoy] |+---------+ +--------+ +----------+ ^ ^ ^ | | | +-----mTLS--+-----------+ All traffic encryptedProblem Solved
Without a service mesh, each microservice team is responsible for implementing retry logic, timeouts, circuit breakers, mutual TLS, and distributed tracing individually. Teams copy-paste the same boilerplate across 20 services in 4 different programming languages. When something breaks, nobody knows which service is failing because there is no centralised view of traffic.
Istio moves all of this out of application code and into the infrastructure layer:
- Traffic control — canary deployments, blue-green switching, weighted routing between service versions without redeploying anything.
- Security — mutual TLS between every service automatically. Even if an attacker gets inside your cluster network, they cannot impersonate a legitimate service.
- Observability — every request between services is automatically traced, measured, and visualised in Kiali without adding a single line of instrumentation code.
- Resilience — circuit breakers that automatically stop sending traffic to a failing service, preventing cascade failures from taking down the entire platform.
Step-by-Step Implementation Guide
Step 1: Install Istio on Your Kubernetes Cluster
Istio has its own CLI called istioctl that handles installation and validation.
## Download the latest Istio releasecurl -L https://istio.io/downloadIstio | sh - ## Move istioctl to your PATHcd istio-1.20.0 # version may differexport PATH=$PWD/bin:$PATHecho 'export PATH=$HOME/istio-1.20.0/bin:$PATH' >> ~/.bashrc ## Verify istioctl is workingistioctl version ## Run pre-installation checks on your clusteristioctl x precheck## Expected: No issues found when checking the cluster ## Install Istio with the demo profile## demo profile includes all components including tracing and Kialiistioctl install --set profile=demo -y ## Verify all Istio components are runningkubectl get pods -n istio-system## Expected: istiod, istio-ingressgateway, istio-egressgateway all Running ## Install Istio addons (Kiali, Prometheus, Grafana, Jaeger)kubectl apply -f samples/addons/kubectl rollout status deployment/kiali -n istio-systemRememberThe demo profile is for learning and includes everything. For production, use the default profile and add only the components you need. The demo profile installs Kiali, Jaeger, Prometheus, and Grafana which consume significant cluster resources.
Step 2: Deploy Three Interconnected Microservices
You will deploy an order service, payment service, and notification service. These three services call each other to simulate a real e-commerce transaction flow — similar to how Swiggy processes a food order.
## Create the application namespace and enable Istio sidecar injection## The label tells Istio to automatically inject Envoy into every pod in this namespacekubectl create namespace swiggy-demokubectl label namespace swiggy-demo istio-injection=enabled ## Verify the label is setkubectl get namespace swiggy-demo --show-labels## Expected: istio-injection=enabled ## Deploy the Order Service (v1 and v2 — we will use both for canary deployment later)kubectl apply -n swiggy-demo -f - <<EOFapiVersion: apps/v1kind: Deploymentmetadata: name: order-service-v1spec: replicas: 2 selector: matchLabels: app: order-service version: v1 template: metadata: labels: app: order-service version: v1 spec: containers: * name: order-service image: nginx:alpine ports: * containerPort: 80---apiVersion: apps/v1kind: Deploymentmetadata: name: order-service-v2spec: replicas: 1 selector: matchLabels: app: order-service version: v2 template: metadata: labels: app: order-service version: v2 spec: containers: * name: order-service image: nginx:alpine ports: * containerPort: 80---apiVersion: v1kind: Servicemetadata: name: order-servicespec: selector: app: order-service ports: * port: 80 name: http---apiVersion: apps/v1kind: Deploymentmetadata: name: payment-servicespec: replicas: 2 selector: matchLabels: app: payment-service version: v1 template: metadata: labels: app: payment-service version: v1 spec: containers: * name: payment-service image: nginx:alpine ports: * containerPort: 80---apiVersion: v1kind: Servicemetadata: name: payment-servicespec: selector: app: payment-service ports: * port: 80 name: http---apiVersion: apps/v1kind: Deploymentmetadata: name: notification-servicespec: replicas: 1 selector: matchLabels: app: notification-service version: v1 template: metadata: labels: app: notification-service version: v1 spec: containers: * name: notification-service image: nginx:alpine ports: * containerPort: 80---apiVersion: v1kind: Servicemetadata: name: notification-servicespec: selector: app: notification-service ports: * port: 80 name: httpEOF ## Verify all pods have 2 containers each (app + Envoy sidecar)kubectl get pods -n swiggy-demo## Expected: Each pod shows 2/2 READY — that second container is the Envoy proxyStep 3: Configure Traffic Management with Virtual Services
Istio uses two custom resources to control traffic: DestinationRule defines the versions (subsets) of a service, and VirtualService defines the routing rules.
## Create DestinationRules — define v1 and v2 subsets for order-servicekubectl apply -n swiggy-demo -f - <<EOFapiVersion: networking.istio.io/v1alpha3kind: DestinationRulemetadata: name: order-servicespec: host: order-service trafficPolicy: connectionPool: tcp: maxConnections: 100 http: h2UpgradePolicy: UPGRADE outlierDetection: # Circuit breaker configuration consecutive5xxErrors: 3 # Eject after 3 consecutive errors interval: 30s # Check every 30 seconds baseEjectionTime: 30s # Keep ejected for 30 seconds minimum maxEjectionPercent: 50 # Never eject more than 50% of endpoints subsets: * name: v1 labels: version: v1 * name: v2 labels: version: v2---apiVersion: networking.istio.io/v1alpha3kind: DestinationRulemetadata: name: payment-servicespec: host: payment-service trafficPolicy: tls: mode: ISTIO_MUTUAL # Enforce mutual TLS for payment service subsets: * name: v1 labels: version: v1EOF ## Create VirtualService — start with 100% traffic to v1 (stable release)kubectl apply -n swiggy-demo -f - <<EOFapiVersion: networking.istio.io/v1alpha3kind: VirtualServicemetadata: name: order-servicespec: hosts: * order-service http: * name: primary route: * destination: host: order-service subset: v1 weight: 100 # 100% to v1 initially * destination: host: order-service subset: v2 weight: 0 # 0% to v2 initiallyEOFStep 4: Implement Canary Deployment
A canary deployment gradually shifts traffic from the old version to the new version. You start at 5%, watch for errors, then increase to 20%, 50%, and finally 100%. If errors appear at any stage you route back to 0% instantly.
## Start the canary — send 10% of traffic to v2kubectl apply -n swiggy-demo -f - <<EOFapiVersion: networking.istio.io/v1alpha3kind: VirtualServicemetadata: name: order-servicespec: hosts: * order-service http: * route: * destination: host: order-service subset: v1 weight: 90 # 90% to stable v1 * destination: host: order-service subset: v2 weight: 10 # 10% canary to v2EOF ## Generate test traffic to see canary in actionfor i in {1..100}; do kubectl exec -n swiggy-demo deployment/payment-service \ -- curl -s http://order-service/healthz > /dev/nulldone ## Watch the Kiali graph to see traffic split between v1 and v2## Access Kiali:kubectl port-forward -n istio-system svc/kiali 20001:20001## Open http://localhost:20001 in your browser## Navigate to Graph -> swiggy-demo namespace## You should see animated traffic flowing between services ## If v2 looks healthy, increase to 50%kubectl patch virtualservice order-service -n swiggy-demo \ --type='json' \ -p='[{"op": "replace", "path": "/spec/http/0/route/0/weight", "value": 50}, {"op": "replace", "path": "/spec/http/0/route/1/weight", "value": 50}]' ## Full rollout — 100% to v2kubectl patch virtualservice order-service -n swiggy-demo \ --type='json' \ -p='[{"op": "replace", "path": "/spec/http/0/route/0/weight", "value": 0}, {"op": "replace", "path": "/spec/http/0/route/1/weight", "value": 100}]' ## Emergency rollback — instant switch back to v1 if problems appearkubectl patch virtualservice order-service -n swiggy-demo \ --type='json' \ -p='[{"op": "replace", "path": "/spec/http/0/route/0/weight", "value": 100}, {"op": "replace", "path": "/spec/http/0/route/1/weight", "value": 0}]'TipCanary deployment with Istio is entirely configuration-based — you never touch the actual Kubernetes deployments. The pods running v1 and v2 keep running throughout. Only the VirtualService routing weights change. This means rollback is instant — change the weight back to 100/0 and the rollback is complete in milliseconds.
Step 5: Enable Mutual TLS Across All Services
Mutual TLS (mTLS) means both the client and server verify each other's identity using certificates. Istio manages all certificates automatically through its built-in Certificate Authority.
## Check current mTLS status in the namespaceistioctl x describe service order-service.swiggy-demo ## Enable strict mTLS for the entire namespace## This means ALL service-to-service communication must use mTLS## Any pod without a valid Istio certificate cannot communicatekubectl apply -f - <<EOFapiVersion: security.istio.io/v1beta1kind: PeerAuthenticationmetadata: name: default namespace: swiggy-demospec: mtls: mode: STRICT # Reject all non-mTLS trafficEOF ## Verify mTLS is working — check the proxy configistioctl proxy-config secret deployment/order-service-v1.swiggy-demo## Expected: Shows the certificate details including expiry and SAN ## Try to access a service from outside the mesh (should fail)kubectl run test-pod --image=curlimages/curl --rm -it \ --restart=Never -- \ curl http://order-service.swiggy-demo/healthz## Expected: Connection refused — non-mesh clients cannot connect ## Try from inside the mesh (should succeed)kubectl exec -n swiggy-demo deployment/payment-service \ -- curl -s http://order-service/healthz## Expected: Response from order-service — mesh clients can connectStep 6: Test Circuit Breaking
The circuit breaker in the DestinationRule automatically stops sending traffic to a pod that is returning errors. This prevents a failing pod from dragging down the entire service.
## The circuit breaker is already configured in the DestinationRule:## consecutive5xxErrors: 3 — eject after 3 consecutive 5xx errors## interval: 30s — check window## baseEjectionTime: 30s — how long to keep the pod ejected ## Simulate a failing pod by injecting a faultkubectl apply -n swiggy-demo -f - <<EOFapiVersion: networking.istio.io/v1alpha3kind: VirtualServicemetadata: name: payment-service-faultspec: hosts: * payment-service http: * fault: abort: percentage: value: 100 # 100% of requests return 500 httpStatus: 500 route: * destination: host: payment-service subset: v1EOF ## Send traffic to trigger the circuit breakerfor i in {1..20}; do kubectl exec -n swiggy-demo deployment/order-service-v1 \ -- curl -s -o /dev/null -w "%{http_code}\n" http://payment-service/done## After 3 consecutive 500 errors, Istio ejects the endpoint## Subsequent requests fail fast with 503 instead of waiting for timeout ## Check the circuit breaker stats in the Envoy proxykubectl exec -n swiggy-demo deployment/order-service-v1 \ -c istio-proxy -- \ pilot-agent request GET stats | grep outlier## Look for: outlier_detection.ejections_active > 0 ## Remove the fault injection to restore normal operationkubectl delete virtualservice payment-service-fault -n swiggy-demoValidation & Testing
## 1. Verify Istio is healthyistioctl analyze -n swiggy-demo## Expected: No validation issues found ## 2. Confirm all pods have Envoy sidecar (2 containers each)kubectl get pods -n swiggy-demo## Expected: All pods show 2/2 READY ## 3. Open Kiali and verify service graph shows all 3 services connectedkubectl port-forward -n istio-system svc/kiali 20001:20001## http://localhost:20001 -> Graph -> swiggy-demo ## 4. Open Jaeger to see distributed traceskubectl port-forward -n istio-system svc/tracing 16686:80## http://localhost:16686 -> Select service -> Find Traces ## 5. Verify mTLS is enforcedistioctl x describe service payment-service.swiggy-demo | grep mTLS## Expected: mTLS: STRICT ## 6. Run the canary from 0% to 100% in steps and verify traffic splits in Kiali## Follow Milestone 4 steps and watch the animated percentages in the Kiali graph ## 7. Verify Grafana shows service metricskubectl port-forward -n istio-system svc/grafana 3000:3000## http://localhost:3000 -> Istio Service Dashboard## Should show request rate, error rate, latency for all 3 servicesecho "Istio service mesh fully operational"Videos & Guides
Istio Service Mesh Tutorial — Complete Crash Course
Complete Istio tutorial covering installation, traffic management, canary deployments, mutual TLS, circuit breaking, and observability with Kiali and Jaeger.
Kiali — Service Mesh Observability
Official Kiali documentation for visualising and understanding your Istio service mesh — service graphs, traffic animation, configuration validation, and health indicators.
Istio Official Documentation
Official Istio documentation covering all concepts including VirtualService, DestinationRule, PeerAuthentication, and the full traffic management API reference.