Nel passato Abbiamo esaminato i componenti di base del Service Mesh Istio, ci siamo familiarizzati con il sistema e abbiamo risposto alle domande principali che sorgono di solito all'inizio dell'utilizzo di Istio. In questa parte, vedremo come organizzare la raccolta delle informazioni di tracing sulla rete.

La prima cosa che viene in mente a molti sviluppatori e amministratori di sistemi quando sentono le parole Service Mesh è il tracing. E in effetti, aggiungiamo a ogni nodo della rete un proxy speciale attraverso il quale passa tutto il traffico TCP. Sembra che ora sia possibile inviare facilmente informazioni su tutte le interazioni di rete. Sfortunatamente, nella realtà ci sono molte sfumature da considerare. Esaminiamole.
Fraintendimento numero uno: possiamo ottenere dati sul traffico di rete gratuitamente.
In realtà, relativamente gratuitamente possiamo solo ottenere i nodi connessi della nostra rete e il rate di dati che passa tra i servizi (praticamente solo il numero di byte per unità di tempo). Tuttavia, nella maggior parte dei casi, i nostri servizi comunicano attraverso un protocollo di livello applicativo, come HTTP, gRPC, Redis e così via. E naturalmente, vogliamo vedere le informazioni di tracing specifiche per questi protocolli, vogliamo vedere il rate delle richieste, non il rate dei dati. Vogliamo comprendere la latenza delle richieste rispetto al nostro protocollo. Infine, vogliamo vedere il percorso completo che la richiesta compie dall'ingresso nel nostro sistema fino alla ricezione della risposta da parte dell'utente. Questa operazione non è così semplice.
Iniziamo a esaminare come viene effettuata l'invio dei tracing span dal punto di vista architettonico in Istio. Come ricordiamo dalla prima parte, Istio ha un componente separato per la raccolta della telemetria, chiamato Mixer. Tuttavia, nella versione attuale 1.0.*, l'invio avviene direttamente dai server proxy, cioè dall'envoy proxy. L'envoy proxy supporta l'invio di tracing span tramite il protocollo zipkin out of the box. Altri protocolli possono essere collegati, ma solo tramite plugin. Con Istio otteniamo immediatamente un envoy proxy preconfigurato, in cui è supportato solo il protocollo zipkin. Se vogliamo utilizzare, ad esempio, il protocollo Jaeger e inviare tracing span via UDP, dobbiamo costruire la nostra immagine istio-proxy. Il supporto per plugin personalizzati per istio-proxy è presente, tuttavia è ancora in versione alpha. Pertanto, se vogliamo evitare un gran numero di configurazioni personalizzate, il ventaglio di tecnologie utilizzate per la memorizzazione e la ricezione di tracing span si riduce. Attualmente, possiamo utilizzare principalmente Zipkin o Jaeger, ma inviare tutto a un protocollo compatibile con zipkin (il che è significativamente meno efficiente). Il protocollo zipkin prevede l'invio di tutte le informazioni di tracing ai collector tramite il protocollo HTTP, il che è abbastanza costoso.
Come ho già detto, vogliamo tracciare i protocolli di livello applicativo. Ciò significa che i server proxy, che si trovano accanto a ciascun servizio, devono comprendere quale interazione sta avvenendo attualmente. Per impostazione predefinita, Istio configura un tipo TCP semplice per tutte le porte, il che significa che non verranno inviati tracce. Affinché le tracce vengano inviate, è necessario innanzitutto abilitare tale opzione nella configurazione principale del mesh e, cosa molto importante, denominare tutte le porte delle entità del servizio di kubernetes secondo il protocollo utilizzato nel servizio. Cioè, ad esempio, in questo modo:
apiVersion: v1
kind: Service
metadata:
name: nginx
spec:
ports:
- port: 80
targetPort: 80
name: http
selector:
app: nginxÈ possibile utilizzare anche nomi composti, come http-magic (Istio riconoscerà http e identificherà questa porta come endpoint http). Il formato è il seguente: proto-extra.
Per non dover modificare un numero elevato di configurazioni per definire il protocollo, si può utilizzare una soluzione temporanea: patchare il componente Pilot nel momento in cui sta eseguendo la logica di definizione del protocollo. Per capire se il protocollo è realmente definito correttamente, è necessario entrare in uno qualsiasi dei contenitori sidecar con l'envoy proxy e fare una richiesta alla porta dell'interfaccia admin di envoy con la posizione /config_dump. Nella configurazione risultante, bisogna guardare il campo operation del servizio desiderato. Viene utilizzato in Istio come identificatore di dove viene effettuata la richiesta. Per personalizzare in Istio il valore di questo parametro (che successivamente vedremo nel nostro sistema di tracing), è necessario specificare il flag serviceCluster durante l'avvio del contenitore sidecar. Ad esempio, può essere calcolato in questo modo dalle variabili ottenute dall'API downward di kubernetes:
Per capire se il protocollo è stato definito correttamente, è necessario accedere a uno dei contenitori sidecar con envoy proxy e fare una richiesta sulla porta dell'interfaccia admin di envoy con il percorso /config_dump. Nella configurazione risultante, è necessario controllare il campo operation per il servizio desiderato. Viene utilizzato in Istio come identificatore della destinazione della richiesta. Per personalizzare il valore di questo parametro in Istio (lo vedremo poi nel nostro sistema di tracciamento), è necessario specificare il flag serviceCluster al momento dell'avvio del contenitore sidecar. Ad esempio, può essere calcolato in questo modo dalle variabili ottenute dall'API downward di Kubernetes:
--serviceCluster ${POD_NAMESPACE}.$(echo ${POD_NAME} | sed -e 's/-[a-z0-9]*-[a-z0-9]*$//g')
Un buon esempio per comprendere come funziona il tracing in envoy è .
L'endpoint per l'invio degli span di tracing deve essere specificato anche nei flag di avvio dell'envoy proxy, ad esempio: --zipkinAddress tracing-collector.tracing:9411
Falso mito numero due: possiamo ottenere tracciamenti completi delle richieste nel sistema in modo economico, direttamente 'out of the box'
Purtroppo, non è così. La complessità dell'implementazione dipende dal modo in cui è già realizzato l'interazione tra i servizi. Perché?
Il fatto è che affinché l'istio-proxy comprenda la corrispondenza tra le richieste in ingresso a un servizio e quelle in uscita dallo stesso servizio, non è sufficiente semplicemente intercettare tutto il traffico. Serve un identificatore di correlazione. In HTTP, l'envoy proxy utilizza intestazioni speciali per capire quale richiesta al servizio genera specifiche richieste ad altri servizi. L'elenco di queste intestazioni include:
- x-request-id,
- x-b3-traceid,
- x-b3-spanid,
- x-b3-parentspanid,
- x-b3-sampled,
- x-b3-flags,
- x-ot-span-context.
Se hai un punto centrale, ad esempio un client di base, in cui puoi aggiungere questa logica, allora tutto va bene, dovrai solo attendere l'aggiornamento di questa libreria presso tutti i client. Ma se hai un sistema molto eterogeneo e non c'è un'unificazione nel modo in cui i servizi comunicano tra loro in rete, questo sarà probabilmente un grande problema. Senza l'aggiunta di una logica simile, tutte le informazioni sul tracing saranno 'monodimensionali'. In altre parole, otterremo tutte le interazioni tra servizi, ma non saranno collegate in catene uniche attraverso la rete.
Conclusione
Istio fornisce un comodo strumento per raccogliere informazioni sul tracing nella rete, tuttavia è importante capire che per l'implementazione sarà necessaria un'adattamento del proprio sistema tenendo conto delle peculiarità di Istio. Alla fine, occorre affrontare due questioni principali: definire il protocollo di livello applicativo (che deve essere supportato dall'envoy proxy) e configurare il passaggio di informazioni sulla correlazione delle richieste tra i servizi (tramite intestazioni, nel caso del protocollo HTTP). Quando queste questioni sono risolte, otteniamo uno strumento potente che consente di raccogliere informazioni sulla rete anche in sistemi molto eterogenei, scritti in molti linguaggi e framework diversi.
Nell'articolo successivo su Service Mesh esamineremo uno dei maggiori problemi di Istio: il grande consumo di memoria da parte di ciascun container proxy sidecar e discuteremo come affrontarlo.
Fonte: habr.com
