Service Mesh: Istio vs Linkerd, mTLS e Traffic Management
In un'architettura a microservizi su Kubernetes, ogni servizio comunica con decine di altri. Chi garantisce che queste comunicazioni siano cifrate? Chi gestisce il retry automatico quando un servizio e momentaneamente irraggiungibile? Chi fornisce le metriche di latenza e tasso di errore per ogni coppia sorgente-destinazione? Senza un service mesh, rispondere a queste domande richiede codice custom in ogni servizio.
Un service mesh risolve questi problemi a livello di infrastruttura, trasparente all'applicazione. I due player dominanti in ambiente Kubernetes sono Istio, il piu ricco di funzionalita, e Linkerd, progettato per semplicita e overhead minimo. Questo articolo mostra come installare entrambi, configurare mTLS automatico, gestire il traffico con canary deployment e circuit breaking, e quando scegliere l'uno o l'altro.
Cosa Imparerai
- Come funziona un service mesh: data plane (sidecar) e control plane
- mTLS automatico: cosa significa, come verificarlo, come gestire le eccezioni
- Istio: installazione, VirtualService, DestinationRule, canary e blue/green
- Linkerd: installazione lightweight, SMI TrafficSplit, extensions
- Circuit breaking con Istio OutlierDetection
- Retry e timeout a livello di infrastruttura
- Osservabilita: metriche golden signals dal service mesh
- Istio vs Linkerd: quando scegliere quale
Come Funziona un Service Mesh
Il service mesh si basa sull'iniezione automatica di un sidecar proxy (Envoy per Istio, Linkerd2-proxy per Linkerd) in ogni Pod. Il sidecar intercetta tutto il traffico in entrata e uscita dal container dell'applicazione, senza richiedere modifiche al codice.
Il data plane e l'insieme di tutti i sidecar proxy che gestiscono il traffico effettivo. Il control plane (Istiod per Istio, linkerd-control-plane per Linkerd) distribuisce la configurazione ai proxy, gestisce i certificati per mTLS e raccoglie telemetria.
Confronto Istio vs Linkerd
| Caratteristica | Istio | Linkerd |
|---|---|---|
| Sidecar proxy | Envoy (C++, 50-100 MB) | linkerd2-proxy (Rust, 10-20 MB) |
| Overhead memoria per Pod | 100-200 MB | 20-30 MB |
| Latency overhead P99 | 2-5 ms | 0.5-1 ms |
| mTLS automatico | Si (cert-manager o built-in) | Si (rotazione automatica 24h) |
| Traffic management | Completo (VirtualService, DR) | Base (HTTPRoute, TrafficSplit) |
| L7 policy | HTTP, gRPC, TCP | HTTP, gRPC |
| Ingress | Gateway API + Istio Gateway | Gateway API |
| Curva di apprendimento | Ripida | Moderata |
| Maturita produzione | Alta (Google, Airbnb) | Alta (Shopify, Microsoft) |
Istio: Installazione e Configurazione Base
Installazione con istioctl
# Scarica e installa istioctl
curl -L https://istio.io/downloadIstio | ISTIO_VERSION=1.22.0 sh -
export PATH=$PWD/istio-1.22.0/bin:$PATH
# Installa Istio con profilo di produzione
istioctl install --set profile=production -y
# Il profilo production abilita:
# - HA con multiple repliche del control plane
# - Affinity rules per distribuire su nodi diversi
# - Risorse CPU/memoria adeguate
# - Solo le feature necessarie (no addon come Kiali, Jaeger)
# Abilita l'iniezione automatica del sidecar nel namespace
kubectl label namespace production istio-injection=enabled
# Verifica lo stato del mesh
istioctl proxy-status
# Analizza la configurazione per possibili problemi
istioctl analyze --namespace production
mTLS con Istio: PeerAuthentication e DestinationRule
Istio implementa il mTLS automatico tra tutti i Pod con sidecar iniettato. Con PeerAuthentication si puo rendere il mTLS STRICT (obbligatorio) a livello di namespace o di mesh intero:
# mtls-strict.yaml
# Abilita mTLS STRICT per tutto il namespace production
apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata:
name: default-mtls
namespace: production
spec:
mtls:
mode: STRICT # DISABLE, PERMISSIVE, STRICT
---
# Eccezione: un servizio legacy che non ha sidecar
apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata:
name: legacy-service-exception
namespace: production
spec:
selector:
matchLabels:
app: legacy-service
mtls:
mode: PERMISSIVE # accetta anche connessioni plain-text
# Verifica mTLS
kubectl exec -n production frontend-pod -c istio-proxy -- \
pilot-agent request GET /config_dump | grep -A5 "tls_context"
# Visualizza lo stato mTLS con istioctl
istioctl x describe pod frontend-pod.production
VirtualService: Routing e Traffic Splitting
Il VirtualService definisce come il traffico verso un servizio viene instradato, con regole basate su header HTTP, pesi, path matching:
# virtual-service-canary.yaml
# Canary deployment: 90% traffico a v1, 10% a v2
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: api-service-vs
namespace: production
spec:
hosts:
- api-service # nome del Kubernetes Service
http:
# Routing per header: dev e QA ricevono sempre v2
- match:
- headers:
x-user-group:
exact: "beta-testers"
route:
- destination:
host: api-service
subset: v2
# Traffico generale: 90/10 split
- route:
- destination:
host: api-service
subset: v1
weight: 90
- destination:
host: api-service
subset: v2
weight: 10
# Timeout e retry a livello di infrastruttura
timeout: 5s
retries:
attempts: 3
perTryTimeout: 2s
retryOn: "5xx,reset,connect-failure,retriable-4xx"
---
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: api-service-dr
namespace: production
spec:
host: api-service
trafficPolicy:
connectionPool:
tcp:
maxConnections: 100
http:
http2MaxRequests: 1000
maxRequestsPerConnection: 10
loadBalancer:
simple: LEAST_CONN # ROUND_ROBIN, RANDOM, LEAST_CONN
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2
Circuit Breaker con OutlierDetection
Il circuit breaker rimuove temporaneamente gli host "unhealthy" dal load balancing pool quando superano soglie di errore definite:
# destination-rule-circuit-breaker.yaml
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: payment-service-circuit-breaker
namespace: production
spec:
host: payment-service
trafficPolicy:
connectionPool:
tcp:
maxConnections: 50
connectTimeout: 3s
http:
http1MaxPendingRequests: 100
http2MaxRequests: 500
maxRetries: 3
outlierDetection:
# Rimuovi un host se in 10 secondi riceve 5 errori 5xx
consecutiveGatewayErrors: 5
consecutive5xxErrors: 5
interval: 10s
# Tienilo fuori per 30 secondi
baseEjectionTime: 30s
# Massimo 50% degli host puo essere rimosso
maxEjectionPercent: 50
# Analizza solo richieste con 100ms o piu di latenza
minHealthPercent: 50
Istio Gateway per il Traffico Ingress
# istio-gateway.yaml
apiVersion: networking.istio.io/v1
kind: Gateway
metadata:
name: production-gateway
namespace: istio-system
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 443
name: https
protocol: HTTPS
tls:
mode: SIMPLE
credentialName: wildcard-tls-cert # Secret con cert TLS
hosts:
- "*.federicocalo.dev"
- port:
number: 80
name: http
protocol: HTTP
tls:
httpsRedirect: true # redirect tutto HTTP a HTTPS
hosts:
- "*.federicocalo.dev"
---
# Collega il Gateway al VirtualService
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: api-gateway-vs
namespace: production
spec:
hosts:
- "api.federicocalo.dev"
gateways:
- istio-system/production-gateway
- mesh # anche per traffico interno al mesh
http:
- route:
- destination:
host: api-service
port:
number: 8080
AuthorizationPolicy: Controllo degli Accessi
# authorization-policy.yaml
# Solo il frontend puo chiamare il backend
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: backend-access-policy
namespace: production
spec:
selector:
matchLabels:
app: backend
action: ALLOW
rules:
- from:
- source:
principals:
- "cluster.local/ns/production/sa/frontend-service-account"
to:
- operation:
methods: ["GET", "POST"]
paths: ["/api/v1/*"]
---
# Blocca tutto il resto (default deny)
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: deny-all
namespace: production
spec:
action: DENY
# Nessun selector = si applica a tutti i Pod nel namespace
# Nessuna rule = blocca tutto
Linkerd: Installazione e Configurazione
Linkerd privilegia la semplicita operativa e le performance. Il suo proxy scritto in Rust ha un overhead di ~1ms di latenza P99 e ~20MB di memoria per Pod, rendendolo ideale per cluster con molti microservizi o vincoli di risorse.
Installazione Linkerd
# Installa Linkerd CLI
curl --proto '=https' --tlsv1.2 -sSfL https://run.linkerd.io/install | sh
export PATH=$HOME/.linkerd2/bin:$PATH
# Prerequisiti: verifica che il cluster sia compatibile
linkerd check --pre
# Installa il control plane
linkerd install --crds | kubectl apply -f -
linkerd install | kubectl apply -f -
# Verifica installazione
linkerd check
# Abilita injection sul namespace
kubectl annotate namespace production linkerd.io/inject=enabled
# Installa l'estensione Viz per osservabilita
linkerd viz install | kubectl apply -f -
linkerd viz check
linkerd viz dashboard &
Canary con Linkerd e HTTPRoute (Gateway API)
# linkerd-canary-httproute.yaml
# Linkerd usa la Gateway API per il traffic splitting
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: api-service-canary
namespace: production
spec:
parentRefs:
- name: api-service
kind: Service
group: core
port: 80
rules:
- backendRefs:
- name: api-service-v1
port: 80
weight: 90
- name: api-service-v2
port: 80
weight: 10
# Monitora il canary con linkerd viz
linkerd viz stat httproute/api-service-canary -n production
linkerd viz routes deploy/api-service-v2 -n production
Osservabilita con Linkerd
# Visualizza metriche golden signals per tutti i deployment
linkerd viz stat deploy -n production
# Output tipico:
# NAME MESHED SUCCESS RPS LATENCY_P50 LATENCY_P99 TCP_CONN
# api-service 4/4 99.8% 245 1ms 12ms 42
# backend-service 3/3 98.2% 180 3ms 45ms 28
# payment-service 2/2 100.0% 65 8ms 89ms 12
# Visualizza il traffico per un singolo Pod
linkerd viz tap pod/api-service-xyz -n production
# Genera un report di osservabilita
linkerd viz check --proxy -n production
Istio Telemetry: Metriche, Tracing e Logging
Istio emette automaticamente le golden signals (latenza, traffico, errori, saturazione) per ogni coppia source-destination. Le metriche sono esposte in formato Prometheus e visibili in Grafana con le dashboard ufficiali Istio.
# telemetry-config.yaml
# Configura il sampling per il distributed tracing
apiVersion: telemetry.istio.io/v1
kind: Telemetry
metadata:
name: mesh-tracing
namespace: istio-system
spec:
tracing:
- providers:
- name: tempo # o jaeger, zipkin
randomSamplingPercentage: 1.0 # campiona 1% del traffico in produzione
---
# Metriche custom per un servizio specifico
apiVersion: telemetry.istio.io/v1
kind: Telemetry
metadata:
name: payment-service-metrics
namespace: production
spec:
selector:
matchLabels:
app: payment-service
metrics:
- providers:
- name: prometheus
overrides:
- match:
metric: REQUEST_COUNT
tagOverrides:
destination_version:
value: "request.headers['x-version'] | 'unknown'"
# Importa le dashboard Grafana ufficiali Istio
# Dashboard ID: 7639 (Mesh Overview), 11829 (Service), 12378 (Workload)
Service Mesh vs Cilium eBPF: Quando Usarli
Con l'avvento di Cilium, che offre mTLS e L7 policy senza sidecar (via eBPF nel kernel), la scelta si e complicata. Ecco una guida pratica:
| Scenario | Scelta Consigliata | Motivo |
|---|---|---|
| Microservizi con traffic management avanzato (canary, header-based routing) | Istio | VirtualService/DestinationRule insostituibili |
| Sicurezza mTLS con overhead minimo | Linkerd o Cilium | Proxy Rust o eBPF minimale |
| Cluster con centinaia di microservizi, risorse limitate | Linkerd o Cilium mTLS | Overhead sidecar moltiplicato per ogni Pod |
| Multi-cluster o multi-cloud | Istio | Mesh federation built-in |
| Team nuovo a service mesh | Linkerd | Curva di apprendimento nettamente inferiore |
Best Practices per il Service Mesh
Checklist per il Service Mesh in Produzione
- Inizia in modalita PERMISSIVE: abilita mTLS in PERMISSIVE prima di renderlo STRICT, per identificare servizi che non hanno ancora il sidecar
- Imposta timeout su tutti i VirtualService: senza timeout, una dipendenza lenta blocca l'intera catena di chiamate
- Circuit breaker per ogni dipendenza esterna: database, API esterne, servizi di pagamento
- Usa retry solo per errori idempotenti: non fare retry automatico su POST senza idempotency key, altrimenti crei ordini duplicati
- Monitora il sidecar CPU/memoria: in cluster con molti Pod, l'overhead aggregato del sidecar puo essere significativo
- Testa il failover: disabilita manualmente un pod e verifica che il circuit breaker e i retry funzionino come atteso
- Mantieni aggiornato il mesh: le versioni di Istio e Linkerd hanno cicli di vita brevi (6-12 mesi); pianifica upgrade regolari
Anti-Pattern Comuni
- Retry infiniti con amplificazione: se A richiama B con 3 retry, e B richiama C con 3 retry, un singolo errore genera 9 tentativi verso C (retry storm)
- Timeout troppo generosi: un timeout di 60 secondi su una API critica significa che durante un'outage tutti i thread/goroutine dell'applicazione sono bloccati per 60s
- Ignorare il control plane overhead: Istiod consuma CPU/memoria significativa per ogni proxy connesso; in cluster con 1000+ Pod, serve un nodo dedicato
- Injection selettiva senza piano: se solo alcuni Pod hanno il sidecar, il mTLS STRICT fallisce per le comunicazioni verso Pod senza sidecar
Conclusioni e Prossimi Passi
Il service mesh ha smesso di essere un "nice to have" e e diventato un requisito per qualsiasi architettura a microservizi seria. mTLS automatico, osservabilita granulare, circuit breaking e traffic management dichiarativo risolvono problemi reali che senza un service mesh richiederebbero codice custom in ogni servizio.
La scelta tra Istio e Linkerd dipende dalle esigenze: Istio per scenari complessi con traffic management avanzato e multi-cluster, Linkerd per semplicita operativa e overhead minimo. In entrambi i casi, l'investimento iniziale nell'apprendimento e nella configurazione e ripagato dalla riduzione di codice infrastrutturale nelle applicazioni e dalla visibilita senza precedenti sul traffico interno al cluster.
Prossimi Articoli della Serie Kubernetes at Scale
Articoli Precedenti
Serie Correlate
- Kubernetes Networking: Cilium con eBPF - alternativa al service mesh per mTLS
- Observability e OpenTelemetry - tracing distribuito integrato con Istio
- Platform Engineering - service mesh come piattaforma interna

Commenti
Caricamento commenti...
Accedi per commentare