Istio Service Mesh: Installation, Traffic Management, and mTLS
What Problem Istio Solves
In a Kubernetes cluster without a service mesh, services communicate directly — no encryption, no circuit breaking, no traffic splitting, no visibility into what's talking to what. Every team must implement these in application code.
Istio solves this at the infrastructure layer:
- mTLS everywhere: all service-to-service traffic encrypted and authenticated by default
- Traffic management: canary deployments, retries, circuit breaking — in YAML, not code
- Observability: distributed traces, per-service metrics, and service topology — automatic
- Policy enforcement: rate limits and access control without application changes
The mechanism: Istio injects an Envoy sidecar container into every pod. All traffic flows through the sidecar, which Istio configures via its xDS control plane (Istiod).
Installation
Istio's recommended install method is istioctl:
# Download istioctl
curl -L https://istio.io/downloadIstio | ISTIO_VERSION=1.24.0 sh -
export PATH="$PATH:$PWD/istio-1.24.0/bin"
# Verify
istioctl version
# Install with the default profile (good for production)
istioctl install --set profile=default -y
# Profiles available:
# minimal — control plane only (no ingress gateway)
# default — control plane + ingress gateway
# demo — includes egress gateway, higher resource limits
# production — production-hardened settings
Verify installation:
kubectl get pods -n istio-system
# NAME READY STATUS RESTARTS
# istiod-xxx 1/1 Running 0
# istio-ingressgateway-xxx 1/1 Running 0
istioctl verify-install
Enabling Sidecar Injection
Istio injects sidecars automatically when the namespace is labeled:
# Enable injection for a namespace
kubectl label namespace default istio-injection=enabled
# Verify label
kubectl get namespace default --show-labels
# Restart existing pods to inject sidecars
kubectl rollout restart deployment -n default
# Verify sidecars are injected (pods should show 2/2 containers)
kubectl get pods -n default
# NAME READY STATUS RESTARTS
# myapp-xxx 2/2 Running 0 ← app + envoy sidecar
To check a specific pod:
kubectl describe pod myapp-xxx | grep -A5 "Containers:"
# Shows: myapp (your app) + istio-proxy (Envoy sidecar)
Automatic mTLS
Once sidecars are injected, Istio enables PERMISSIVE mode by default — accepts both plain and mTLS traffic. Switch to STRICT mode to require mTLS for all communication in a namespace:
# strict-mtls.yaml
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: default
namespace: default # apply to entire namespace
spec:
mtls:
mode: STRICT
kubectl apply -f strict-mtls.yaml
# Verify mTLS is working
istioctl x describe pod myapp-xxx
# Should show: "mTLS: yes"
# Check from the Kiali dashboard (if installed) or via CLI
istioctl x authn tls-check myapp-xxx.default
After enabling STRICT mode, pods in default namespace can only receive traffic from other Istio-sidecar-injected pods with valid certificates.
VirtualService: Traffic Routing
VirtualService configures routing rules for traffic directed at a Kubernetes service:
# virtualservice.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: myapp
namespace: default
spec:
hosts:
- myapp # Kubernetes service name
http:
- match:
- headers:
x-canary:
exact: "true"
route:
- destination:
host: myapp
subset: v2
- route:
- destination:
host: myapp
subset: v1
weight: 90
- destination:
host: myapp
subset: v2
weight: 10
The subset references a DestinationRule:
# destinationrule.yaml
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: myapp
namespace: default
spec:
host: myapp
subsets:
- name: v1
labels:
version: v1 # matches pods with label version=v1
- name: v2
labels:
version: v2
trafficPolicy:
connectionPool:
tcp:
maxConnections: 100
http:
http1MaxPendingRequests: 100
http2MaxRequests: 1000
outlierDetection:
consecutive5xxErrors: 5
interval: 30s
baseEjectionTime: 30s
Apply both:
kubectl apply -f destinationrule.yaml
kubectl apply -f virtualservice.yaml
Retries and Timeouts
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: myapp
spec:
hosts:
- myapp
http:
- route:
- destination:
host: myapp
timeout: 30s
retries:
attempts: 3
perTryTimeout: 10s
retryOn: "5xx,gateway-error,connect-failure,retriable-4xx"
Ingress Gateway
The Istio Ingress Gateway replaces (or supplements) a Kubernetes Ingress for external traffic:
# gateway.yaml
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: myapp-gateway
namespace: default
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 443
name: https
protocol: HTTPS
tls:
mode: SIMPLE
credentialName: myapp-tls # Kubernetes TLS secret
hosts:
- app.example.com
- port:
number: 80
name: http
protocol: HTTP
hosts:
- app.example.com
tls:
httpsRedirect: true # redirect HTTP to HTTPS
# Bind VirtualService to Gateway
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: myapp
spec:
hosts:
- app.example.com
gateways:
- myapp-gateway
- mesh # also applies within the mesh
http:
- route:
- destination:
host: myapp
port:
number: 80
Observability
Install the Istio add-ons (telemetry stack):
# From the Istio installation directory
kubectl apply -f samples/addons/prometheus.yaml
kubectl apply -f samples/addons/grafana.yaml
kubectl apply -f samples/addons/kiali.yaml
kubectl apply -f samples/addons/jaeger.yaml
# Port-forward to access dashboards
kubectl port-forward -n istio-system svc/kiali 20001:20001
kubectl port-forward -n istio-system svc/grafana 3000:3000
kubectl port-forward -n istio-system svc/jaeger-query 16686:16686
Kiali shows the service topology graph — which services are talking to which, error rates, latency, and mTLS status.
Debugging
# Check Envoy proxy config for a pod
istioctl proxy-config all myapp-xxx.default
# Check routes
istioctl proxy-config route myapp-xxx.default
# Check clusters (upstreams)
istioctl proxy-config cluster myapp-xxx.default
# Check listeners
istioctl proxy-config listener myapp-xxx.default
# Analyze config for issues
istioctl analyze -n default
# Dump Envoy access log
kubectl logs myapp-xxx -c istio-proxy --tail=50
# Check service-to-service connectivity
kubectl exec -it myapp-xxx -- curl http://other-service/api/health
Common Issues
Pods stuck in 2/2 but sidecar not working: Check istioctl x authn tls-check — may be a namespace label issue.
Traffic not routed to VirtualService: Ensure the hosts in VirtualService matches the Kubernetes Service name exactly, and the Gateway is referenced correctly.
mTLS error "RBAC: access denied": An AuthorizationPolicy is denying the traffic. Check with:
istioctl x authz check myapp-xxx.default
High latency after Istio installation: The Envoy sidecar adds ~1ms per hop. For extremely latency-sensitive workloads, exclude the namespace from injection.
Was this article helpful?
Senior Kubernetes Architect
10+ years orchestrating containers in production. Battle-tested opinions on everything from pod scheduling to service mesh. I've seen clusters burn and helped rebuild them better.
Related Articles
Istio Observability and Authorization: Distributed Tracing, Metrics, and Access Policies
How to use Istio's built-in observability — distributed tracing with Jaeger, Prometheus metrics, Kiali service graph — and enforce zero-trust access control with AuthorizationPolicies.
Envoy Proxy: Architecture, xDS Configuration, and Getting Started
An introduction to Envoy Proxy's architecture — listeners, clusters, filters, and the xDS dynamic configuration API. Covers static configuration for standalone use and how Envoy fits into service meshes like Istio.
Envoy Traffic Management: Retries, Timeouts, Canary Deployments, and Rate Limiting
Advanced Envoy traffic management — configuring retries with exponential backoff, per-request timeouts, weighted canary routing, global rate limiting, and fault injection for resilience testing.
Fix Kubernetes OOMKilled: Pod Keeps Getting Killed for Memory
Diagnose and fix OOMKilled errors in Kubernetes pods — understand memory limits, identify leaks, and configure resource requests correctly.
The Complete Guide to Kubernetes Deployment Strategies: Rolling, Blue-Green, Canary, and Progressive Delivery
A comprehensive guide to every Kubernetes deployment strategy — rolling updates, blue-green, canary, and progressive delivery with Argo Rollouts and Flagger.
Istio Installation & Architecture: Your First Service Mesh
Install Istio on Kubernetes, understand the control plane architecture, deploy your first sidecar proxy, and configure namespace injection.
More in Kubernetes
View all →Kubernetes Vertical Pod Autoscaler: Automating Resource Request Tuning In Production
Let me be direct with you: most Kubernetes clusters I audit are hemorrhaging money because of poorly configured resource requests. I've seen teams running...
Fix Helm 'UPGRADE FAILED: has no deployed releases'
Fix the Helm 'UPGRADE FAILED: has no deployed releases' error when a previous install failed and left the release in a broken state.
Fix Kubernetes 'Evicted' Pods Filling Up the Node
Clean up Kubernetes evicted pods and fix the underlying disk pressure or resource exhaustion that causes pod evictions.
Fix Kubernetes ImagePullBackOff: Container Image Won't Pull
Resolve ImagePullBackOff and ErrImagePull errors in Kubernetes — fix registry credentials, image tags, and network access issues.