Introduction
Istio is a service mesh that adds observability, traffic management, and security to microservices without changing application code. In a microservices architecture with dozens of services, managing things like mutual TLS between services, circuit breakers, retries, and distributed tracing becomes complex. Istio handles all of this at the infrastructure level using sidecar proxies (Envoy). This guide teaches you to deploy and use Istio effectively.
How Istio Works
Istio injects a sidecar proxy (Envoy) alongside every pod:
Without Istio: With Istio:
┌──────────────┐ ┌────────────────────────┐
│ Service A │─────────────│ Service A │ Envoy │
└──────────────┘ └────────────────────────┘
│ │
▼ ▼ (intercepted)
┌──────────────┐ ┌────────────────────────┐
│ Service B │ │ Envoy │ Service B │
└──────────────┘ └────────────────────────┘
All traffic passes through Envoy sidecars, which:
- Enforce mTLS between services
- Collect metrics and traces
- Apply routing rules and retriesInstalling Istio
# Download Istio
curl -L https://istio.io/downloadIstio | sh -
cd istio-1.20.0
export PATH=$PWD/bin:$PATH
# Install with demo profile (good for learning)
istioctl install --set profile=demo -y
# Verify installation
kubectl get pods -n istio-system
# Enable automatic sidecar injection for a namespace
kubectl label namespace default istio-injection=enabled
# Verify injection is working (deploy test app)
kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml
kubectl get pods # Should see 2 containers per pod (app + istio-proxy)Traffic Management
Istio uses VirtualService and DestinationRule to control traffic:
# VirtualService: defines routing rules
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: myapp
spec:
hosts:
- myapp
http:
# Canary: 10% traffic to v2
- route:
- destination:
host: myapp
subset: v1
weight: 90
- destination:
host: myapp
subset: v2
weight: 10
---
# DestinationRule: defines subsets (versions)
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: myapp
spec:
host: myapp
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2
trafficPolicy:
connectionPool:
http:
http2MaxRequests: 1000
outlierDetection: # Circuit breaker
consecutive5xxErrors: 5
interval: 30s
baseEjectionTime: 30sRetries and Timeouts
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: payment-service
spec:
hosts:
- payment-service
http:
- timeout: 5s # Total timeout for request
retries:
attempts: 3 # Retry up to 3 times
perTryTimeout: 2s # Each try max 2s
retryOn: "connect-failure,reset,503"
route:
- destination:
host: payment-servicemTLS Between Services
# Enable strict mTLS for all services in namespace
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: default
namespace: production
spec:
mtls:
mode: STRICT # All traffic must use mTLS
---
# Allow specific service to use permissive (during migration)
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: legacy-service
namespace: production
spec:
selector:
matchLabels:
app: legacy
mtls:
mode: PERMISSIVEAuthorization Policies
# Only allow frontend to call backend
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: backend-policy
namespace: production
spec:
selector:
matchLabels:
app: backend
rules:
- from:
- source:
principals: ["cluster.local/ns/production/sa/frontend"]
- to:
- operation:
methods: ["GET", "POST"]
paths: ["/api/*"]Observability with Kiali
Kiali provides a dashboard showing the service mesh topology:
# Install observability addons
kubectl apply -f samples/addons/
# Access Kiali dashboard
istioctl dashboard kiali
# Access Grafana (Istio metrics)
istioctl dashboard grafana
# Access Jaeger (distributed tracing)
istioctl dashboard jaegerKiali shows:
- Service dependency graph with traffic flow
- Error rates and latency per service
- mTLS status between services
- Traffic split percentages for canary deployments
Ingress Gateway
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
name: myapp-gateway
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 443
name: https
protocol: HTTPS
tls:
mode: SIMPLE
credentialName: myapp-tls-cert
hosts:
- app.company.com
---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: myapp-ingress
spec:
hosts:
- app.company.com
gateways:
- myapp-gateway
http:
- route:
- destination:
host: myapp
port:
number: 8080Debugging Istio Issues
# Check sidecar injection
kubectl get pod myapp-xxx -o jsonpath='{.spec.containers[*].name}'
# Should show: myapp istio-proxy
# Check proxy configuration
istioctl proxy-config cluster myapp-xxx.default
# Check if mTLS is working
istioctl x check-inject -n production
# View Envoy access logs
kubectl logs myapp-xxx -c istio-proxy | head -20
# Analyze configuration for issues
istioctl analyze -n production
# Check traffic policies applied
istioctl proxy-config listener myapp-xxx.defaultIstio adds significant operational complexity but pays off in large microservice deployments where you need consistent security, observability, and traffic control across dozens of services. Start with observability only (no policy enforcement) before enabling mTLS and authorization policies.
