When you have dozens of microservices talking to each other, managing traffic, security, and observability becomes complex. A service mesh handles this at the infrastructure layer, so your applications don’t have to.
What Problems Does a Service Mesh Solve?# Without a mesh, every service needs to implement:
Retries and timeouts Circuit breakers Load balancing TLS certificates Metrics and tracing Access control With a mesh, the sidecar proxy handles all of this:
┌ │ │ │ │ │ └ ─ ─ ─ P ─ ─ o ┌ │ │ └ ─ ─ d ─ ─ ─ ─ ─ C ─ ─ ─ ─ o ─ ─ ─ ─ A n ─ ─ ─ ─ p t ─ ─ ─ ─ p a ─ ─ ─ ─ i ─ ─ ─ ─ n ─ ─ ─ ─ e ─ ─ ─ ─ r ─ ─ ─ ─ ─ ─ ─ ┐ │ │ ┘ ─ ─ ◄ ─ ─ ─ ─ ─ ─ ─ ─ ► ─ ─ ┌ │ │ └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ E ( ─ ─ ─ ─ n h ─ ─ ─ ─ v a ─ ─ ─ ─ o n ─ ─ ─ ─ y d ─ ─ ─ ─ l ─ ─ ─ ─ S e ─ ─ ─ ─ i s ─ ─ ─ ─ d ─ ─ ─ ─ e m ─ ─ ─ ─ c e ─ ─ ─ ─ a s ─ ─ ─ ─ r h ─ ─ ─ ─ ) ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ │ │ ┘ ─ ─ ◄ ─ ─ ─ ─ ┐ │ │ ┼ │ │ ┘ ─ ─ ► O t h e r S e r v i c e s
Installing Istio# 1
2
3
4
5
6
7
8
9
10
11
12
13
# Download Istio
curl -L https://istio.io/downloadIstio | sh -
cd istio-*
export PATH = $PWD /bin:$PATH
# Install with demo profile (includes observability)
istioctl install --set profile = demo -y
# Enable sidecar injection for namespace
kubectl label namespace default istio-injection= enabled
# Verify installation
kubectl get pods -n istio-system
Traffic Management# Canary Deployments# Route 10% of traffic to the new version:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# virtual-service.yaml
apiVersion : networking.istio.io/v1beta1
kind : VirtualService
metadata :
name : api-service
spec :
hosts :
- api-service
http :
- match :
- headers :
x-canary :
exact : "true"
route :
- destination :
host : api-service
subset : v2
- route :
- destination :
host : api-service
subset : v1
weight : 90
- destination :
host : api-service
subset : v2
weight : 10
---
# destination-rule.yaml
apiVersion : networking.istio.io/v1beta1
kind : DestinationRule
metadata :
name : api-service
spec :
host : api-service
subsets :
- name : v1
labels :
version : v1
- name : v2
labels :
version : v2
Timeouts and Retries# 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
apiVersion : networking.istio.io/v1beta1
kind : VirtualService
metadata :
name : api-service
spec :
hosts :
- api-service
http :
- route :
- destination :
host : api-service
timeout : 10s
retries :
attempts : 3
perTryTimeout : 3s
retryOn : gateway-error,connect-failure,refused-stream
Circuit Breaking# 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
apiVersion : networking.istio.io/v1beta1
kind : DestinationRule
metadata :
name : api-service
spec :
host : api-service
trafficPolicy :
connectionPool :
tcp :
maxConnections : 100
http :
h2UpgradePolicy : UPGRADE
http1MaxPendingRequests : 100
http2MaxRequests : 1000
outlierDetection :
consecutive5xxErrors : 5
interval : 30s
baseEjectionTime : 30s
maxEjectionPercent : 50
Fault Injection (Testing)# 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
apiVersion : networking.istio.io/v1beta1
kind : VirtualService
metadata :
name : api-service
spec :
hosts :
- api-service
http :
- fault :
delay :
percentage :
value : 10
fixedDelay : 5s
abort :
percentage :
value : 5
httpStatus : 503
route :
- destination :
host : api-service
Security: mTLS Everywhere# Enable Strict mTLS# 1
2
3
4
5
6
7
8
apiVersion : security.istio.io/v1beta1
kind : PeerAuthentication
metadata :
name : default
namespace : istio-system # Mesh-wide
spec :
mtls :
mode : STRICT
Authorization Policies# 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# Only allow frontend to call API
apiVersion : security.istio.io/v1beta1
kind : AuthorizationPolicy
metadata :
name : api-access
namespace : default
spec :
selector :
matchLabels :
app : api-service
action : ALLOW
rules :
- from :
- source :
principals : [ "cluster.local/ns/default/sa/frontend" ]
to :
- operation :
methods : [ "GET" , "POST" ]
paths : [ "/api/*" ]
---
# Deny all else (default deny)
apiVersion : security.istio.io/v1beta1
kind : AuthorizationPolicy
metadata :
name : deny-all
namespace : default
spec :
{} # Empty spec = deny all
JWT Validation at the Mesh# 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
apiVersion : security.istio.io/v1beta1
kind : RequestAuthentication
metadata :
name : jwt-auth
namespace : default
spec :
selector :
matchLabels :
app : api-service
jwtRules :
- issuer : "https://auth.example.com"
jwksUri : "https://auth.example.com/.well-known/jwks.json"
audiences :
- "api.example.com"
forwardOriginalToken : true
---
apiVersion : security.istio.io/v1beta1
kind : AuthorizationPolicy
metadata :
name : require-jwt
namespace : default
spec :
selector :
matchLabels :
app : api-service
action : ALLOW
rules :
- from :
- source :
requestPrincipals : [ "https://auth.example.com/*" ]
Observability# Automatic Metrics# Istio generates metrics for every request:
1
2
3
4
5
6
7
# View in Prometheus
istioctl dashboard prometheus
# Key metrics:
# - istio_requests_total
# - istio_request_duration_milliseconds
# - istio_tcp_connections_opened_total
Distributed Tracing# 1
2
3
4
5
6
7
8
9
# Enable tracing sampling
apiVersion : install.istio.io/v1alpha1
kind : IstioOperator
spec :
meshConfig :
enableTracing : true
defaultConfig :
tracing :
sampling : 100.0 # 100% for dev, lower for prod
1
2
# View traces in Jaeger
istioctl dashboard jaeger
Service Graph with Kiali# 1
2
3
4
5
# Install Kiali
kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.20/samples/addons/kiali.yaml
# Access dashboard
istioctl dashboard kiali
Gateway Configuration# Expose services to external traffic:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
apiVersion : networking.istio.io/v1beta1
kind : Gateway
metadata :
name : api-gateway
spec :
selector :
istio : ingressgateway
servers :
- port :
number : 443
name : https
protocol : HTTPS
tls :
mode : SIMPLE
credentialName : api-tls-cert
hosts :
- "api.example.com"
---
apiVersion : networking.istio.io/v1beta1
kind : VirtualService
metadata :
name : api-external
spec :
hosts :
- "api.example.com"
gateways :
- api-gateway
http :
- match :
- uri :
prefix : /v1
route :
- destination :
host : api-service
port :
number : 8080
Rate Limiting# 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
apiVersion : networking.istio.io/v1alpha3
kind : EnvoyFilter
metadata :
name : rate-limit
namespace : istio-system
spec :
workloadSelector :
labels :
istio : ingressgateway
configPatches :
- applyTo : HTTP_FILTER
match :
context : GATEWAY
listener :
filterChain :
filter :
name : "envoy.filters.network.http_connection_manager"
patch :
operation : INSERT_BEFORE
value :
name : envoy.filters.http.local_ratelimit
typed_config :
"@type": type.googleapis.com/udpa.type.v1.TypedStruct
type_url : type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimit
value :
stat_prefix : http_local_rate_limiter
token_bucket :
max_tokens : 100
tokens_per_fill : 100
fill_interval : 60s
filter_enabled :
runtime_key : local_rate_limit_enabled
default_value :
numerator : 100
denominator : HUNDRED
Debugging# 1
2
3
4
5
6
7
8
9
10
11
12
# Check sidecar injection
kubectl get pods -o jsonpath = '{.items[*].spec.containers[*].name}' | tr ' ' '\n' | grep istio
# Analyze configuration issues
istioctl analyze
# Debug specific workload
istioctl proxy-status
istioctl proxy-config routes deploy/api-service
# View Envoy config
kubectl exec -it deploy/api-service -c istio-proxy -- pilot-agent request GET config_dump
When to Use a Service Mesh# Good fit:
Many microservices (10+) Strong security requirements (mTLS, zero-trust) Complex traffic management needs Need deep observability without code changes Maybe skip:
Small number of services Simple traffic patterns Resource-constrained environments Team unfamiliar with Kubernetes A service mesh adds complexity and resource overhead. Start simple, add mesh when the problems it solves become painful. For many teams, that’s around 10-20 services where managing cross-cutting concerns manually becomes unsustainable.