În trecut, Am analizat componentele de bază ale Service Mesh Istio, ne-am familiarizat cu sistemul și am răspuns la întrebările fundamentale care apar de obicei la începutul activității cu Istio. În această parte, ne vom concentra asupra modului de organizare a colectării informațiilor de tracing în rețea.

Primul lucru care vine în mintea multor dezvoltatori și administratori de sistem atunci când aud termenul Service Mesh este tracing. Și, de fapt, adăugăm un server proxy special în fiecare nod al rețelei, prin care trece tot traficul TCP. Pare că acum putem trimite cu ușurință informații despre toate interacțiunile rețelei. Din păcate, în realitate, apar o mulțime de nuanțe care trebuie luate în considerare. Să le analizăm.
Mitul numărul unu: putem obține gratuit date despre parcursul în rețea.
De fapt, relativ gratuit putem obține doar nodurile conectate prin săgeți ale sistemului nostru și rata datelor care trece între servicii (practic, doar numărul de byte pe unitatea de timp). Totuși, în cele mai multe cazuri, serviciile noastre comunică printr-un protocol de nivel aplicativ, cum ar fi, HTTP, gRPC, Redis și așa mai departe. Și, desigur, vrem să vedem informații de tracing exact pentru aceste protocoale, dorim să vedem rata cererilor, nu rata datelor. Vrem să înțelegem latența cererilor pentru protocolul nostru. În cele din urmă, vrem să vedem întregul parcurs al cererii, de la intrarea în sistemul nostru până la primirea răspunsului de către utilizator. Această sarcină nu este atât de simplă de rezolvat.
Pentru început, să examinăm cum arată trimiterea span-urilor de tracing din perspectiva arhitecturii în Istio. După cum ne amintim din prima parte, Istio are un component separat pentru colectarea telemetriei, numit Mixer. Cu toate acestea, în versiunea actuală 1.0.* trimiterea se face direct de la serverele proxy, mai exact, de la envoy proxy. Envoy proxy suportă trimiterea span-urilor de tracing prin protocolul zipkin din cutie. Alte protocoale pot fi integrate, dar doar printr-un plugin. Cu Istio, primim imediat envoy proxy configurat și pregătit, care suportă doar protocolul zipkin. Dacă dorim să folosim, de exemplu, protocolul Jaeger și să trimitem span-uri de tracing prin UDP, atunci va trebui să compilăm propria imagine istio-proxy. Suportul pentru plugin-uri personalizate pentru istio-proxy există, dar este încă în versiune alpha. Prin urmare, dacă dorim să evităm un număr mare de configurări personalizate, cercul tehnologiilor utilizate pentru stocarea și primirea span-urilor de tracing se micșorează. Din principalele sisteme, practic, acum putem utiliza fie Zipkin, fie Jaeger, dar totul trebuie trimis printr-un protocol compatibil cu zipkin (ceea ce este semnificativ mai puțin eficient). Protocolul zipkin preconizează trimiterea tuturor informațiilor de tracing către colectoare prin protocolul HTTP, ceea ce este destul de costisitor.
Așa cum am spus, dorim să facem tracing pentru protocoalele de nivel aplicativ. Asta înseamnă că serverele proxy, care sunt aproape de fiecare serviciu, trebuie să înțeleagă ce interacțiune are loc în prezent. În mod implicit, Istio configurează pentru toate porturile un tip TCP simplu, ceea ce înseamnă că nu vor fi trimise trace-uri. Pentru ca trace-urile să fie trimise, trebuie, în primul rând, să activăm această opțiune în configurația principală mesh și, ceea ce este foarte important, să denumim toate porturile entităților de tip service din Kubernetes conform protocolului utilizat în serviciu. Adica, de exemplu, astfel:
apiVersion: v1
kind: Service
metadata:
name: nginx
spec:
ports:
- port: 80
targetPort: 80
name: http
selector:
app: nginxDe asemenea, putem folosi nume compuse, de exemplu http-magic (Istio va vedea http și va recunoaște acest port ca fiind un endpoint http). Formatul este astfel: proto-extra.
Pentru a nu modifica un număr mare de configurații pentru a determina protocolul, putem folosi o soluție temporară murdară: să patch-uim componenta Pilot în momentul în care aceasta tocmai . În final, va trebui să schimbăm această logică în standard și să trecem la convenția de denumire a tuturor porturilor.
Pentru a înțelege dacă protocolul a fost definit corect, trebuie să intri în oricare dintre containerele sidecar cu envoy proxy și să faci o cerere pe portul interfeței admin a envoy cu locația /config_dump. În configurația obținută, trebuie să te uiți la câmpul operation al serviciului dorit. Acesta este folosit în Istio ca identificator al locului unde se face cererea. Pentru a personaliza în Istio valoarea acestui parametru (îl vom vedea ulterior în sistemul nostru de tracing), trebuie să specificăm la pornirea containerului sidecar flagul serviceCluster. De exemplu, acesta poate fi calculat astfel din variabilele obținute din downward API kubernetes:
--serviceCluster ${POD_NAMESPACE}.$(echo ${POD_NAME} | sed -e 's\-[a-z0-9]*\-[a-z0-9]*$//g')
Un exemplu bun pentru a înțelege cum funcționează tracing în envoy este .
Endpoint-ul pentru trimiterea tracing span-urilor trebuie de asemenea specificat în flagurile de pornire ale envoy proxy, de exemplu: --zipkinAddress tracing-collector.tracing:9411
Mitul numărul doi: putem obține fără costuri trace-uri complete ale trecerii cererilor prin sistem din cutie.
Din păcate, nu este așa. Complexitatea implementării depinde de modul în care ai realizat deja interacțiunea serviciilor. De ce?
Este vorba că, pentru ca istio-proxy să poată înțelege coresponderea cererilor de intrare într-un serviciu cu cele de ieșire din același serviciu, nu este suficient să interceptăm tot trafic. Este necesar un identificator de legătură. În HTTP envoy proxy se utilizează antete speciale pe baza cărora envoy înțelege care cerere particulară către serviciu generează cereri specifice în alte servicii. Lista acestor antete:
- x-request-id,
- x-b3-traceid,
- x-b3-spanid,
- x-b3-parentspanid,
- x-b3-sampled,
- x-b3-flags,
- x-ot-span-context.
Dacă ai un punct unic, de exemplu, un client de bază în care poți adăuga această logică, atunci totul e perfect, va trebui doar să aștepți actualizarea acestei biblioteci la toți clienții. Dar dacă ai un sistem foarte heterogen și nu există o unificare în modul în care serviciile comunică între ele prin rețea, atunci aceasta va fi probabil o mare problemă. Fără adăugarea unei astfel de logici, toată informația de tracing va fi doar «unidimensională». Adică vom obține toate interacțiunile inter-serviciu, dar acestea nu vor fi legate în lanțuri unice de trecere prin rețea.
Concluzie
Istio oferă un instrument convenabil pentru colectarea de informații de tracing în rețea, dar trebuie să înțelegem că implementarea necesită adaptarea sistemului propriu și luarea în considerare a particularităților implementării Istio. În final, trebuie să rezolvăm două aspecte principale: definirea protocolului de aplicație (care trebuie să fie acceptat de envoy proxy) și configurarea redirecționării informațiilor despre corelarea cererilor în serviciu din cererile din serviciu (folosind header-e, în cazul protocolului HTTP). Odată ce aceste întrebări sunt rezolvate, obținem un instrument puternic care permite colectarea transparentă a informațiilor din rețea, chiar și în sisteme foarte heterogene, scrise în multe limbaje și cadre diferite.
În următorul articol despre Service Mesh, vom analiza una dintre cele mai mari probleme ale Istio – consumul ridicat de memorie RAM de către fiecare container proxy sidecar și vom discuta despre cum se poate lupta cu aceasta.
Sursa: habr.com
