Kuma Service Mesh – Parte 2
Funzionalità Avanzate in Kuma 2.13.x
Pascal Carone
8/4/202518 min read
Indice
Introduzione
Resilienza con Kuma
Gestione del traffico in ingresso (Ingress)
Ambienti Multi-Zone
Conclusione
Introduzione
Nella prima parte di questo blog abbiamo visto le basi dell’installazione e dell’uso di Kuma come service mesh su Kubernetes, concentrandoci su funzionalità fondamentali come l’injection dei sidecar, il zero-trust security con mTLS e le Traffic Permission per controllare il traffico. In questa seconda parte, esploriamo invece caratteristiche avanzate introdotte o migliorate in Kuma versione 2.13.x, aggiornando tutti gli esempi agli oggetti “moderni” oggi supportati. Questi oggetti Mesh sostituiscono le policy legacy (come Timeout, Retry, FaultInjection, TrafficRoute, ecc.) e offrono un modo più consistente e potente per gestire traffico, resilienza e multi-tenancy all’interno del mesh. Manteniamo un approccio tecnico e teorico: oltre alla configurazione, evidenzieremo i vantaggi concettuali che Kuma porta nella gestione del traffico applicativo, nella resilienza dei servizi e nel supporto di scenari multi-tenancy su Kubernetes.
Nuove risorse di policy Mesh (Timeout, Retry, Circuit Breaker, Rate Limit)
Con le recenti versioni di Kuma, molte delle policy di traffico “classiche” sono state rimpiazzate da equivalenti Mesh (prefissati da “Mesh”). Queste nuove risorse, MeshTimeout, MeshRetry, MeshCircuitBreaker e MeshRateLimit, adottano un nuovo algoritmo di matching basato su targetRef, più espressivo e unificato tra ambienti Kubernetes e Universal. In pratica, le policy Mesh permettono di riferirsi a servizi (o insiemi di servizi) in modo dichiarativo (es. kind: MeshService, kind: Mesh per l’intero mesh) come bersaglio o sorgente della policy, eliminando le ambiguità e la dipendenza da TrafficRoute che alcune vecchie policy avevano.
Nota: Le vecchie risorse come Timeout, Retry, CircuitBreaker, RateLimit rimangono supportate per retrocompatibilità ma non vanno combinate con le nuove omologhe Mesh nella stessa mesh. È consigliabile migrare alle nuove policy Mesh, che Kuma applica con precedenza su eventuali policy legacy esistenti.
Quando viene creato un nuovo mesh, Kuma genera automaticamente delle policy Mesh di default per quel mesh. Ad esempio, vengono aggiunti oggetti MeshTimeout, MeshRetry e MeshCircuitBreaker con configurazioni di base (spesso chiamati “all-default”) per garantire un comportamento predefinito uniforme. Queste policy di default si applicano globalmente (es. timeout di default per tutte le richieste nel mesh) ma possono poi essere override da policy più specifiche definite dall’utente. Ciò favorisce la multi-tenancy: più mesh isolati possono coesistere nello stesso control plane, ciascuno con le proprie regole predefinite e custom, senza conflitti.
Di seguito facciamo una overview di ciascuna risorsa Mesh e forniamo un esempio di manifest YAML compatibile con Kuma 2.13.x per illustrarne l’uso. Gli esempi mostrano policy a livello di mesh o di servizio, con valori ipotetici. In tutti i casi, i termini tecnici (es. campi YAML) rimangono in inglese per aderenza alla sintassi di Kuma.
MeshTimeout – Timeout di richieste e connessioni
Una policy MeshTimeout permette di configurare i timeout per le richieste e connessioni tra servizi. In un service mesh, usare correttamente i timeout è fondamentale per evitare che chiamate a servizi lenti o non rispondenti consumino indefinitamente risorse (waiting threads, connessioni aperte, ecc.) propagando il problema. Con MeshTimeout possiamo definire timeout a livello di applicazione (HTTP, gRPC) e a livello di trasporto (TCP) in modo centralizzato.
Ad esempio, il seguente YAML configura un timeout per tutte le chiamate dal servizio frontend verso il servizio backend (entrambi all’interno dello stesso mesh). Impostiamo un timeout HTTP di 2 secondi sulle risposte e un timeout di connessione TCP di 5 secondi:
In questo esempio abbiamo usato targetRef per individuare il servizio backend (incluso il namespace e porta nel nome, secondo la convenzione di Kuma su Kubernetes) come destinatario della policy. La sezione from indica che la regola si applica al traffico proveniente dal servizio frontend verso quel backend. Il blocco default contiene i valori di timeout da applicare: un connectionTimeout generale e, sotto la chiave http, specifici timeout per richieste HTTP. Questo significa che ogni chiamata HTTP che il frontend manda al backend aspetterà al massimo 2 secondi la risposta; inoltre, se la connessione TCP non si stabilisce entro 5 secondi verrà interrotta. (Sono disponibili anche idleTimeout e altri parametri non mostrati qui, per brevità.)
I vantaggi concettuali sono chiari: grazie a MeshTimeout possiamo garantire che nessuna chiamata rimanga in sospeso troppo a lungo, confinando così eventuali problemi di latenza. In combinazione con altri meccanismi (retry, circuit breaking), i timeout contribuiscono a una resilienza maggiore dell’applicazione, evitando che risorse vengano esaurite in attesa di servizi non responsivi.
MeshRetry – Retry delle richieste fallite
La policy MeshRetry definisce le strategie di retry (ritentativo) per le chiamate tra servizi in caso di fallimento. In un’architettura distribuita, poter ritentare automaticamente una richiesta fallita (ad esempio a causa di un errore transitorio del servizio remoto o di un timeout) aumenta la probabilità di successo percepita dall’utente finale e rende il sistema più tollerante ai fault temporanei. Kuma permette di configurare i retry in modo granulare per protocolli HTTP, gRPC e TCP (ad esempio specificando su quali codici di stato HTTP effettuare retry, il numero di tentativi massimi, e la strategia di backoff esponenziale con jitter).
Un esempio di MeshRetry YAML, simile a quanto presente nella documentazione ufficiale, può essere il seguente. Configuriamo che il servizio frontend ritenti fino a 3 volte le chiamate verso il servizio backend quando queste falliscono con errori di tipo 5xx (errori server):
In questo manifest, targetRef identifica i client a cui applicare la policy (nel nostro caso tutti i dataplane con label app: frontend). Tramite to indichiamo che la regola vale quando quei client chiamano il servizio backend. Sotto http specifichiamo la politica di retry: massimo 3 tentativi (numRetries: 3) con un intervallo base di 50ms (che crescerà esponenzialmente ad ogni tentativo, con tetto a 1s). Il campo retryOn definisce le condizioni che innescano il retry, in questo caso qualsiasi risposta con status code 5xx.
Come funziona il backoff? Kuma/Envoy utilizza un algoritmo di backoff esponenziale con jitter. Ad esempio, con base 50ms: il primo retry avviene dopo un ritardo casuale tra 0 e 50ms; il secondo tra 0 e 150ms; il terzo tra 0 e 350ms, e così via. Il jitter evita sincronizzazioni indesiderate tra richieste ritentate. Inoltre, MeshRetry supporta la funzionalità rate-limited backoff: se il servizio remoto risponde con header come Retry-After o X-RateLimit-Reset, questi valori possono essere usati per calibrare il timing del retry successivo.
Grazie ai retry configurabili, Kuma aumenta la resilienza applicativa: transient faults possono essere superati senza impatto per l’utente finale. Chiaramente vanno usati con cautela – introdurre troppi retry può aggravare la congestione – ma impostati correttamente (magari con timeout e circuit breaking) costituiscono un potente pattern di fault tolerance.
MeshCircuitBreaker – Circuit Breaking (isolamento dei guasti)
La policy MeshCircuitBreaker implementa il pattern del circuit breaker, ovvero un meccanismo per isolare i guasti e prevenire effetti a cascata nel sistema. In pratica, un circuit breaker monitora le interazioni con un servizio e, al superamento di determinate soglie di errore, “apre il circuito” interrompendo temporaneamente le chiamate verso quel servizio. Ciò evita di sovraccaricare un servizio già in difficoltà e protegge i client dal rimanere bloccati in attesa. Kuma configura i circuit breaker sfruttando le funzionalità di outlier detection di Envoy, con vari tipi di detector (per errori consecutivi locali o “gateway”, percentuale di errori, success rate, ecc.).
Supponiamo di voler proteggere il servizio backend: possiamo definire una policy che, se un’istanza di backend continua a fallire le richieste, venga considerata “rotta” e isolata per un certo periodo. Un YAML di esempio:
In questo scenario, il circuit breaker è applicato al servizio backend: qualunque client nel mesh (to: Mesh) nel chiamarlo sarà soggetto a queste regole di outlier detection. Abbiamo abilitato un detector localOriginFailures con soglia consecutive: 5, il che significa che se Envoy riscontra 5 fallimenti consecutivi di tipo local origin (es. time-out, reset di connessione, errori locali generati dal proxy perché l’upstream non risponde) allora l’istanza di backend problematica verrà isolata (ejection). Potremmo configurare anche gatewayFailures (per contare errori 502/503/504 provenienti dall’upstream) o altri detector più avanzati, ma qui usiamo un criterio semplice: 5 timeout consecutivi fanno scattare il circuito.
Parametri come interval, baseEjectionTime e maxEjectionPercent ci consentono di rifinire il comportamento: ad esempio, interval è la finestra di osservazione (di default Envoy usa 10s), baseEjectionTime è il tempo per cui un host resta isolato al primo ejection (questo tempo può aumentare se persistono i problemi), e maxEjectionPercent può limitare la percentuale di istanze isolabili in un cluster (qui 100% significa che, in caso estremo, tutte le istanze di backend potrebbero venire isolate se tutte falliscono oltre la soglia).
Concettualmente, il vantaggio è proteggere il sistema: con circuit breaking, un servizio malfunzionante viene messo in quarantena, evitando che i client continuino a inviargli traffico inutile. Questo libera le risorse dei client (che riceveranno errori immediati invece di restare in attesa) e concede al servizio guasto il tempo di recuperare. Kuma semplifica l’adozione di questo pattern a livello mesh, applicandolo automaticamente a tutti i proxy senza dover cambiare il codice delle applicazioni.
MeshRateLimit – Limitazione di velocità (throttling)
La policy MeshRateLimit consente di applicare un rate limiting centralizzato, cioè limitare il numero di richieste o connessioni che un servizio può accettare in un determinato intervallo di tempo. È uno strumento cruciale per evitare l’overload di servizi critici: ad esempio, possiamo garantire che un servizio non riceva più di 100 richieste al secondo per istanza, rifiutando (o ritardando) quelle in eccesso con un codice di errore appropriato. MeshRateLimit supporta sia traffico HTTP (e HTTP/2) sia TCP, e internamente utilizza il filtro di Envoy di local rate limiting (implementazione token bucket). Il limite configurato è per istanza di servizio: se il servizio ha N pod, il throughput totale consentito è limite × N.
Vediamo un esempio concreto. Configuriamo una policy di rate limit per il servizio backend che ne consenta al massimo 50 richieste HTTP al secondo per istanza da parte di qualsiasi client nel mesh. In caso di superamento, le richieste eccedenti riceveranno uno status 429 Too Many Requests:
In questo manifest, indichiamo come target il servizio backend. La sezione from: Mesh significa che consideriamo tutte le richieste verso backend indipendentemente dalla provenienza (potremmo anche specificare fonti particolari, ad es. applicare limiti diversi a diversi client). Il blocco http definisce la politica: requestRate con num: 50 e interval: 1s configura un limite di 50 richieste al secondo. La sotto-sezione onRateLimit ci permette di definire l’azione quando il limite è raggiunto: nel nostro caso restituiamo 429 (il default sarebbe 429 comunque, ma lo specifichiamo) e potremmo aggiungere header per segnalare il throttling se volessimo.
Con questa policy attiva, Envoy su ogni instance di backend conterà le richieste entranti e oltre il 50-esimo nel secondo corrente inizierà a rifiutarle fino al reset del contatore nel secondo successivo. Multi-tenancy: notiamo che il rate limit è confinato al mesh default (grazie alla label). Se avessimo più mesh per diversi team o ambienti, ognuno potrebbe avere i propri rate limit su servizi magari omonimi, senza influenzarsi a vicenda – un esempio del vantaggio multi-tenant delle risorse Mesh (ogni mesh è isolato con proprie quote di traffico, regole di resilienza, ecc.).
Fault Injection e resilienza avanzata
Oltre a gestire i fault in produzione, Kuma offre la possibilità di iniettare artificialmente dei guasti nel traffico per testare la resilienza delle applicazioni (fault injection). Questa funzionalità è preziosa in scenari di chaos engineering: possiamo simulare errori e ritardi per vedere come i servizi reagiscono e verificare che meccanismi come retry e circuit breaker funzionino a dovere.
Nelle versioni recenti, anche la fault injection è disponibile come risorsa Mesh dedicata, chiamata MeshFaultInjection (attualmente indicata come experimental nei docs). Il funzionamento è simile alla vecchia policy FaultInjection: si possono configurare percentuali di errore (es. far fallire intenzionalmente X% delle richieste) o di ritardo (delay artificiale di Y ms su X% delle chiamate) su specifiche rotte.
Esempio 1, Abort faults: immaginiamo di voler simulare che tutte le richieste dal servizio source al servizio destination restituiscano un errore 500 interno. Possiamo applicare una MeshFaultInjection così:
Una volta applicata questa policy, tutte le chiamate HTTP da source a destination verranno interrotte immediatamente dal proxy e il client riceverà una risposta con codice 500. Nel nostro esempio, infatti, se un Pod source prova a chiamare destination, otteniamo nel suo output un chiaro messaggio di fault injection: “fault filter abort”. Questo conferma che Kuma ha forzato l’errore simulato.
Nel laboratorio originale, dopo aver applicato una MeshFaultInjection simile, eseguendo curl dal pod source verso destination, il comando tornava subito un errore 500 con la stringa "fault filter abort" nel payload.
Possiamo modificare dinamicamente questi parametri. Ad esempio, potremmo voler simulare errori solo su una percentuale delle richieste (per testare il comportamento in caso di errori intermittenti). Impostando percentage: 50 e magari un diverso codice di errore, metà delle richieste andranno a buon fine (codice 200) e metà restituiranno l’errore configurato, come verificato anche nel lab (alternanza di esiti 200 e 529 in una serie di tentativi).
Esempio 2, Delay faults: un altro tipo di fault injection è l’aggiunta di ritardo artificiale alle risposte. Ciò consente di testare come l’applicazione reagisce a servizi lenti (timeout e retry dovrebbero intervenire correttamente). Supponiamo di voler introdurre un ritardo di 5 secondi sul servizio destination quando viene chiamato dal servizio source2. Il manifest sarà simile:
Con questa configurazione, ogni richiesta da source2 a destination verrà ritardata di 5 secondi esatti. Effettuando un curl da source2 misurando il tempo (time curl ...), osserveremo approssimativamente 5 secondi di ritardo aggiuntivo nell’elaborazione, come confermato dall’output (tempo reale ~5.25s in un esempio). Questo permette di verificare ad esempio che il client source2 gestisca correttamente la latenza (magari frontend attiverà un timeout se configurato a meno di 5s).
Pulizia: Le fault injection sono ovviamente pensate per test, quindi vanno rimosse prima di tornare in produzione. Come mostrato anche nel lab, si possono cancellare facilmente con kubectl delete meshfaultinjection ... quando non servono più.
In definitiva, grazie a MeshFaultInjection possiamo indurre condizioni avverse in maniera controllata, per poi constatare come i nostri meccanismi di resilienza (timeout, retry, circuit breaker, etc.) reagiscono. Il valore concettuale è un miglioramento della confidenza nel sistema in produzione: testando le reazioni ai guasti, costruiamo applicazioni più robuste.
Ingress nel mesh: MeshGateway e MeshGatewayRoute
Un altro tema avanzato importante è l’esposizione dei servizi interni del mesh verso l’esterno (ingress). Kuma fornisce un proprio modo di definire gateway ingress (detti built-in gateway) attraverso le risorse MeshGateway e MeshGatewayRoute, introdotte nelle versioni recenti in linea con il Kubernetes Gateway API. Questi oggetti sostituiscono l’approccio legacy basato su Ingress generici o su ZoneIngress usati per il traffico nord-sud, fornendo una soluzione nativa al mesh per gestire ingress con Envoy.
In sintesi, un MeshGateway rappresenta la configurazione di un listener di ingress (porta, protocollo, TLS) e si associa a uno o più gateway pods (Envoy dedicati) che faranno effettivamente da ingress. Una MeshGatewayRoute definisce invece le regole di routing dal gateway verso i servizi interni (ad esempio, mapping di URL host/path a servizi del mesh). Vediamo come il tutto funziona, accompagnato da un esempio di configurazione.
Deploy di un Gateway Ingress (builtin)
Per prima cosa, occorre l’istanza del gateway (il proxy Envoy ingress) nel cluster. Questo si fa creando un oggetto MeshGatewayInstance (in Kuma 2.13 tale risorsa potrebbe ancora chiamarsi così, come mostrato nel materiale) che essenzialmente istruisce Kuma a eseguire un dataplane proxy in modalità gateway. Ad esempio:
In questo manifest, creiamo un gateway Envoy chiamato app-gateway nel namespace gateway-ns, associato al mesh gateway-mesh. Usiamo un LoadBalancer per ottenere un IP pubblico (o un NodePort a seconda dell’ambiente) e assegniamo un tag di servizio app_gateway al dataplane. Applicando questo YAML, Kuma lancerà un pod Envoy di ingress (app-gateway-*****) e un Service app-gateway di tipo LoadBalancer. Possiamo verificare infatti la presenza di un pod in esecuzione e un IP esterno assegnato.
A questo punto, il gateway è in ascolto ma non sa ancora come smistare il traffico. Se provassimo a contattare l’IP esterno ora, vedremmo un messaggio di default: “This is a Kuma MeshGateway. No routes match this MeshGateway!”. Significa che Envoy sta rispondendo ma non trova alcuna route configurata per instradare le richieste in arrivo.
Configurazione del MeshGateway e delle route
Il passo successivo è definire un oggetto MeshGateway che associa il listener (porta, protocollo) al gateway Envoy creato. Ecco un esempio:
In questo YAML, stiamo dicendo: “sul mesh gateway-mesh, configura un listener HTTP sulla porta 80 per il gateway con servizio app_gateway”. La sezione selectors serve proprio a fare match tra il MeshGateway e i dataplane (MeshGatewayInstance) che devono implementarlo, tramite il tag kuma.io/service. Applichiamo questa risorsa e, in pochi secondi, il pod app-gateway comincerà ad ascoltare sulla porta 80 come definito (il Service LB app-gateway esporrà la 80 esternamente).
Infine, occorre creare la MeshGatewayRoute che instrada le richieste ricevute verso uno o più servizi del mesh interni. Ad esempio, se vogliamo che tutto il traffico HTTP in ingresso venga inoltrato a un servizio interno chiamato gateway-deployment (supponiamo sia un’applicazione web nel mesh), configureremo:
In questa route definiamo una regola: per qualsiasi richiesta HTTP in ingresso (prefisso / significa tutte le path), instrada il traffico verso il backend denominato gateway-deployment_gateway-ns_svc_8080 con peso 1 (potremmo elencare più backends per fare load-balancing o split). Il backend va identificato con il nome di servizio Kuma del deployment interno che vogliamo esporre; nell’esempio il servizio Kubernetes gateway-deployment nel namespace gateway-ns esposto sulla porta 8080 corrisponde al nome gateway-deployment_gateway-ns_svc_8080. La selectors in testa collega la route al gateway app_gateway (lo stesso tag usato nel MeshGateway sopra).
Applichiamo anche questa risorsa. A questo punto, il nostro gateway Envoy ha una route valida. Se recuperiamo l’External IP del Service app-gateway e facciamo una richiesta HTTP, dovremmo finalmente raggiungere l’applicazione interna. Ad esempio, effettuando curl http://<EXTERNAL-IP>:80/ otteniamo la risposta dal servizio interno (nell’esempio di laboratorio, l’app rispondeva con il proprio HOSTNAME, confermando che la richiesta è arrivata ad uno dei pod di gateway-deployment).
In sintesi, il flusso è questo:


Possiamo immaginare il gateway mesh come un Ingress Controller gestito dal service mesh stesso: offre ingress HTTP (anche TCP) che rispetta le regole del mesh, applica policy di sicurezza e osservabilità di Kuma e permette di collegare facilmente traffico nord-sud con i nostri servizi microservizi. Un vantaggio concettuale è la coerenza: si riutilizza Envoy (lo stesso data plane del mesh) anche per l’ingress, con configurazione unificata. Inoltre, le MeshGatewayRoute possono instradare non solo in base al path ma anche ad altri attributi (host, header) similmente alle HTTPRoute del Gateway API standard.
Nota: Kuma supporta anche l’integrazione con il Kubernetes Gateway API ufficiale (Gateway, GatewayClass, HTTPRoute) se si preferisce quella via, oppure l’uso di gateway “delegati” (ad esempio Kong come ingress esterno). In questo blog ci siamo concentrati sul gateway builtin di Kuma per brevità.
Pattern Multi-Zone: Global/Zone Control Plane e ZoneEgress
Un’ultima serie di funzionalità avanzate da considerare riguarda la distribuzione di Kuma in ambienti multi-cluster o multi-datacenter, ossia il deployment Multi-Zone. Questo pattern architetturale permette di avere un unico service mesh logico che copre più cluster Kubernetes (o anche ambienti Universal su VM), mantenendo isolamento dei failure domain e un controllo centralizzato. I componenti chiave del multi-zone sono il Global Control Plane, i Zone Control Plane per ogni zona, e i ruoli di ZoneIngress e ZoneEgress per veicolare il traffico tra zone.
Concetto di Zone: Una zone in Kuma può corrispondere a un cluster Kubernetes, a una VPC cloud, a un data center fisico, ecc. Ogni zone ha un Control Plane locale (modalità zone) e una serie di dataplane proxy. Il Control Plane global (modalità global) gestisce la configurazione a livello mesh e funge da single source of truth per policy e stati. I Zone CP si connettono al Global CP per sincronizzare le risorse. Questo consente di avere multi-tenancy e ambienti eterogenei: “Il tuo ambiente mesh può includere multiple isolated service meshes (multi-tenancy), con workload in region diverse, cloud diverse o datacenter differenti”. In Kuma i concetti di zone e cluster sono astratti via: i dataplane troveranno i servizi indipendentemente da dove girano, e possiamo distribuire un’app su più zone per ottenere failover automatico in caso di down di un’intera zona (ad esempio, se un cluster va offline, il traffico verrà servito dai dataplane dell’altra zona perché condividono lo stesso kuma.io/service).
Per implementare tutto ciò, Kuma utilizza due tipi speciali di dataplane proxy:
ZoneIngress: un proxy (Envoy) che riceve traffico in entrata da altre zone e lo instrada ai servizi locali. Ogni zone registra presso il Global CP un proprio ZoneIngress (di solito creato automaticamente all’installazione del CP zone). Le altre zone sapranno quindi come raggiungere i servizi di questa zone tramite il suo ingress.
ZoneEgress: un proxy introdotto di recente, responsabile del traffico in uscita dalla zone verso altre zone o verso servizi esterni al mesh. In pratica, i dataplane non contattano direttamente i ZoneIngress remoti, ma delegano al proprio ZoneEgress locale le connessioni fuori zona. Ciò permette di isolare e controllare meglio il traffico esterno e semplifica la gestione di firewall/VPC (basta aprire verso l’egress). Il ZoneEgress è uno per zona e non è associato a un workload specifico, funziona per tutti i mesh presenti. Quando abilitato, tutto il traffico inter-zone passa attraverso l’Egress locale (che poi parla con l’Ingress della zona di destinazione) e anche le chiamate a servizi esterni definiti in Kuma vengono dirottate sull’Egress locale. In altre parole, l’Egress diventa il punto unico di uscita del mesh per quella zona.
Vediamo un diagramma ASCII semplificato della topologia multi-zone con questi componenti:


Nell’illustrazione: Abbiamo un Global CP che coordina due Zone CP. Ogni Zone CP gestisce i dataplane locali e fa girare un ZoneIngress (per ricevere traffico da altre zone) e, se abilitato, un ZoneEgress (per inviare traffico fuori dalla zona). I dataplane (DP) all’interno di una zona comunicano fra loro direttamente (richieste intra-zone), ma quando il servizio A (in Zone1) deve chiamare il servizio B (in Zone2), la richiesta viene intercettata dal ZoneEgress di Zone1, il quale stabilisce una connessione mTLS verso il ZoneIngress di Zone2. Da lì, il traffico raggiunge il DP del servizio B. Il Global CP diffonde a tutti i CP zone le informazioni necessarie (quali servizi sono attivi in quali zone, e gli indirizzi dei rispettivi ingress).
Abilitazione di ZoneEgress: di default Kuma non avvia un Egress proxy nelle installazioni multi-zone, a meno che non venga richiesto. Per abilitare lo ZoneEgress in Kubernetes, occorre installare il control plane zone con l’opzione --egress-enabled (se si usa kumactl install control-plane) oppure impostare egress.enabled: true nel Helm chart. Questo creerà un deployment aggiuntivo kuma-zone-egress nella namespace di Kuma. Inoltre, per forzare i dataplane a usare l’egress, bisogna impostare a livello di Mesh la proprietà routing.zoneEgress: true (e assicurarsi che mTLS sia attivo, in quanto richiesto per identificare zone e servizi). Un esempio di configurazione mesh:
Con zoneEgress: true, come riportato nella documentazione, “la comunicazione cross-zone e verso servizi esterni verrà forzata a passare attraverso lo ZoneEgress”. Se l’egress è abilitato a livello mesh ma in una zona non è presente (non deployato), le comunicazioni verso fuori falliranno – quindi va abilitato con coerenza.
Vantaggi del multi-zone: Questo pattern offre sia alta disponibilità geografica sia una gestione centralizzata. Il Global CP funge da pannello di controllo unico (l’admin applica policy e crea mesh solo sul global), mentre i Zone CP gestiscono localmente l’orchestrazione dei proxy. In caso di caduta di una zone, il resto del mesh continua a funzionare e può fare failover (come detto, se servizi analoghi girano in più zone, Kuma effettua automaticamente failover instradando traffico alla zone rimanente). Dal punto di vista della multi-tenancy, un deployment multi-zone può anche isolare mesh differenti per area (ad es. un mesh per ambienti di test in un cluster isolato, un mesh per prod in un altro cluster, ma comunque gestiti insieme dal global CP). Inoltre, l’introduzione dello ZoneEgress semplifica la gestione della sicurezza e compliance: tutto il traffico uscente passa da un punto controllato dove si possono applicare osservabilità, policy aggiuntive o filtri (ed è un punto in cui applicare restrizioni di rete verso l’esterno).
Configurazione del Control Plane, upgrade e best practice per produzione
Come ultimo argomento, dedichiamo qualche cenno alla gestione del Control Plane di Kuma e alle considerazioni per l’ambiente di produzione.
Configurazione del Control Plane: Kuma CP è altamente configurabile tramite parametri sia in kumactl (per installazioni rapide) sia via Helm chart (in ambiente Kubernetes). Ad esempio, abbiamo visto come impostare la modalità (global/zone) e l’abilitazione di egress/ingress. Altre configurazioni tipiche includono l’utilizzo di un datastore esterno: di default in modalità standalone (single-zone) Kuma usa un datastore in-memory nel pod del CP, mentre in multi-zone il global CP richiede un datastore persistente (Postgres) per mantenere lo stato condiviso. È possibile configurare Postgres anche in single-zone per durabilità maggiore. Tramite il Control Plane Configuration (file conf o values di Helm) si possono regolare molti parametri operativi: porte, impostazioni di garbage collection delle policies, risorse di sistema, certmanager per CA custom, integrazione con monitoring, etc. Assicurarsi di configurare il CP con risorse adeguate (CPU/RAM) e replica se necessario (il CP supporta modalità HA attiva/attiva con leader election su Postgres). Kuma fornisce anche un riferimento completo di configurazione per il control plane.
Upgrade del mesh: Aggiornare Kuma è generalmente semplice, ma in produzione va pianificato con attenzione. L’approccio consigliato è seguire la guida ufficiale di upgrade: aggiornare prima i Control Plane (global e poi zone) alla nuova versione, verificare che siano compatibili con i dataplane esistenti (Kuma tende a mantenere compatibilità verso le versioni precedenti degli envoy dataplane). I dataplane proxy si riconnetteranno al control plane aggiornato e scaricheranno le nuove configurazioni; volendo un upgrade completo, si possono poi progressivamente riavviare i pod applicativi per ottenere sidecar con la nuova versione (se l’upgrade di Kuma include anche Envoy). Per cambi di major version o di policy format, consultare sempre le note di versione e gli upgrade specific notes fornite da Kuma. Nel contesto delle policy Mesh, Kuma 2.x introduce la possibilità di migrare gradualmente usando la modalità “shadow”: si applica la nuova policy Mesh con un’etichetta kuma.io/effect: shadow così che non influisca realmente, si confronta l’effetto previsto tramite l’API di inspect, e poi si rimuove l’etichetta promuovendola effettiva. Questo consente upgrade/migrazione senza impatto da policy legacy a nuove.
Osservabilità e tuning: In produzione è fondamentale attivare l’osservabilità del mesh. Kuma semplifica questo tramite le policy di MeshMetrics, MeshTrace e MeshAccessLog (che però esulano dal nostro tema attuale) e offrendo out-of-the-box integrazioni con Prometheus/Grafana, OpenTelemetry, Datadog, etc. È buona norma abilitare il scraping Prometheus del control plane e dei dataplane, nonché raccogliere i Kuma CP metrics (esposte su :5680) per tenere d’occhio le performance. Il controllo di mTLS automatico e certificati builtin va bene per iniziare, ma in ambienti enterprise potrebbe essere opportuno integrare una CA esterna o rotate periodicamente i certificati (Kuma supporta rotazione configurabile già di default ogni anno per CA e ogni giorno per DP certificate, come visto nel lab).
Best practice multi-tenancy: Kuma supporta multi-tenancy sia attraverso più mesh logici in uno stesso cluster sia separando ambienti in zone diverse. Sfruttare i Mesh multipli per isolare contesti (es. mesh “prod”, “stage”, “dev” separati) permette di applicare policy differenti (ad esempio permessive in dev, restrittive in prod) senza interferenze – tutto gestito dallo stesso control plane. È importante anche gestire i permessi: usare role-based access control (Kubernetes RBAC integrato con Kuma) per limitare chi può modificare certe mesh o policy è cruciale in ambienti condivisi.
Supporto e stabilità: Kuma dalla versione 2.x è un progetto maturo (CNCF Sandbox) e derivato da Kong Mesh per uso enterprise. In contesti di produzione, si può contare su un ciclo di rilascio stabile e sul supporto della community e di Kong per bugfix e features. Prima di portare in prod nuove funzionalità come MeshGateway o ZoneEgress è consigliato testarle a fondo in staging, dato che alcune potrebbero essere relativamente recenti (ad esempio MeshGateway è stabile da diverse versioni, MeshFaultInjection è ancora experimental).
Conclusione
In conclusione, Kuma 2.13.x offre un panorama completo di strumenti per gestire il traffico applicativo con un grado di controllo fine e una visibilità elevata. Dalle policy di resilienza (timeout, retry, circuit breaking) ai gateway ingress integrati, fino al supporto multi-cluster con un autentico mesh globale, Kuma consente di costruire architetture microservizi robuste, scalabili e multi-tenant. Il tutto mantenendo la semplicità d’uso caratteristica di Kuma: gran parte della complessità (mTLS, routing cross-zone, default policies) viene gestita automaticamente dal control plane, lasciando ai team di concentrarsi sulla definizione delle regole di alto livello. Questo conclude la nostra esplorazione avanzata – con Kuma, anche scenari complessi come failover geografico o ingress centralizzati diventano alla portata, con pochi manifest YAML e benefici tangibili in termini di affidabilità e sicurezza del sistema.
