Houers, mikrodienste en diensmaskers

Op die internet n klomp artikels о diensnetwerk (diensnet), en hier is nog een. Hoera! Maar hoekom? Dan wil ek my mening uitspreek dat dit beter sou gewees het as diensmaskers 10 jaar gelede verskyn het, voor die koms van houerplatforms soos Docker en Kubernetes. Ek sê nie dat my standpunt beter of slegter as ander is nie, maar aangesien diensmaas redelik komplekse diere is, sal verskeie standpunte help om hulle beter te verstaan.

Ek sal praat oor die dotCloud-platform, wat op meer as honderd mikrodienste gebou is en duisende houertoepassings ondersteun het. Ek sal die uitdagings verduidelik wat ons in die gesig gestaar het met die ontwikkeling en bekendstelling daarvan, en hoe diensnetwerke kon (of nie kon) help nie.

Geskiedenis van dotCloud

Ek het geskryf oor die geskiedenis van dotCloud en die argitektuurkeuses vir hierdie platform, maar ek het nie veel oor die netwerklaag gepraat nie. As jy nie in lees wil duik nie laaste artikel oor dotCloud, hier is die kern in 'n neutedop: dit is 'n PaaS-platform-as-'n-diens wat kliënte in staat stel om 'n wye reeks toepassings (Java, PHP, Python ...) te laat loop, met ondersteuning vir 'n wye reeks data dienste (MongoDB, MySQL, Redis ...) en 'n werkvloei soos Heroku: Jy laai jou kode op na die platform, dit bou houerbeelde en ontplooi dit.

Ek sal jou vertel hoe verkeer na die dotCloud-platform gelei is. Nie omdat dit besonder cool was nie (alhoewel die stelsel goed gewerk het vir sy tyd!), maar hoofsaaklik omdat met moderne gereedskap so 'n ontwerp maklik in 'n kort tyd deur 'n beskeie span geïmplementeer kan word as hulle 'n manier nodig het om verkeer tussen 'n klomp te stuur. van mikrodienste of 'n klomp toepassings. Op hierdie manier kan jy die opsies vergelyk: wat gebeur as jy alles self ontwikkel of 'n bestaande diensnetwerk gebruik. Die standaard keuse is om dit self te maak of dit te koop.

Verkeersroetering vir gehoste toepassings

Toepassings op dotCloud kan HTTP- en TCP-eindpunte blootstel.

HTTP eindpunte dinamies bygevoeg tot die lasbalanseerdergroepkonfigurasie Hipache. Dit is soortgelyk aan wat hulpbronne vandag doen Ingang in Kubernetes en 'n lasbalanseerder soos Traefik.

Kliënte koppel aan HTTP-eindpunte deur toepaslike domeine, mits die domeinnaam na dotCloud-lasbalanseerders verwys. Niks spesiaals.

TCP eindpunte geassosieer met 'n poortnommer, wat dan deur omgewingsveranderlikes aan alle houers in daardie stapel gestuur word.

Kliënte kan aan TCP-eindpunte koppel deur die toepaslike gasheernaam (iets soos gateway-X.dotcloud.com) en poortnommer te gebruik.

Hierdie gasheernaam word opgelos na die "nats"-bedienergroepering (nie verwant aan NATS), wat inkomende TCP-verbindings na die korrekte houer sal lei (of, in die geval van lasgebalanseerde dienste, na die korrekte houers).

As jy bekend is met Kubernetes, sal dit jou waarskynlik aan Dienste herinner NodePort.

Daar was geen ekwivalente dienste op die dotCloud-platform nie ClusterIP: Vir eenvoud is toegang tot dienste op dieselfde manier van binne en buite die platform verkry.

Alles was eenvoudig georganiseer: die aanvanklike implementering van HTTP- en TCP-roeteringnetwerke was waarskynlik slegs 'n paar honderd lyne Python elk. Eenvoudige (ek sou sê naïef) algoritmes wat verfyn is namate die platform gegroei het en bykomende vereistes verskyn het.

Uitgebreide herfaktorering van bestaande kode was nie nodig nie. In die besonder, 12-faktor-toepassings kan direk die adres gebruik wat verkry is deur omgewingsveranderlikes.

Hoe verskil dit van 'n moderne diensnetwerk?

Beperk sigbaarheid. Ons het glad nie enige maatstawwe vir die TCP-roeteringnetwerk gehad nie. Wat HTTP-roetering betref, het latere weergawes gedetailleerde HTTP-statistieke met foutkodes en reaksietye bekendgestel, maar moderne diensnetwerke gaan selfs verder en bied integrasie met metrieke-insamelingstelsels soos Prometheus, byvoorbeeld.

Sigbaarheid is belangrik nie net vanuit 'n operasionele perspektief nie (om te help om probleme op te los), maar ook wanneer nuwe kenmerke vrygestel word. Dit gaan oor veilig blou-groen ontplooiing и kanarie ontplooiing.

Roetering doeltreffendheid is ook beperk. In die dotCloud-roeteringnetwerk moes alle verkeer deur 'n groep toegewyde roeteringnodusse gaan. Dit het beteken dat die grense van verskeie AZ (beskikbaarheidsone) moontlik sou oorgesteek word en dat die latensie aansienlik sou toeneem. Ek onthou die foutsporingskode wat meer as honderd SQL-navrae per bladsy gemaak het en 'n nuwe verbinding met die SQL-bediener vir elke navraag oopgemaak het. Wanneer dit plaaslik uitgevoer word, laai die bladsy onmiddellik, maar in dotCloud neem dit 'n paar sekondes om te laai omdat elke TCP-verbinding (en daaropvolgende SQL-navraag) tientalle millisekondes neem. In hierdie spesifieke geval het aanhoudende verbindings die probleem opgelos.

Moderne diensmaskers is beter om sulke probleme te hanteer. In die eerste plek kyk hulle of verbindings herlei word in die bron. Die logiese vloei is dieselfde: клиент → меш → сервис, maar nou werk die maas plaaslik en nie op afgeleë nodusse nie, dus die verbinding клиент → меш is plaaslik en baie vinnig (mikrosekondes in plaas van millisekondes).

Moderne diensnetwerke implementeer ook slimmer lasbalanseringsalgoritmes. Deur die gesondheid van backends te monitor, kan hulle meer verkeer na vinniger backends stuur, wat lei tot verbeterde algehele prestasie.

sekuriteit beter ook. Die dotCloud routing mesh het geheel en al op EC2 Classic gehardloop en nie verkeer geënkripteer nie (gebaseer op die aanname dat as iemand daarin kon slaag om 'n snuffel op EC2 netwerkverkeer te plaas, jy reeds in groot moeilikheid was). Moderne diensnetwerke beskerm al ons verkeer deursigtig, byvoorbeeld met wedersydse TLS-verifikasie en daaropvolgende enkripsie.

Roeter verkeer vir platformdienste

Goed, ons het verkeer tussen toepassings bespreek, maar wat van die dotCloud-platform self?

Die platform self het bestaan ​​uit ongeveer honderd mikrodienste wat vir verskeie funksies verantwoordelik was. Sommige het versoeke van ander aanvaar, en sommige was agtergrondwerkers wat aan ander dienste gekoppel het, maar nie self verbindings aanvaar het nie. In elk geval moet elke diens weet wat die eindpunte is van die adresse waarmee dit moet koppel.

Baie hoëvlakdienste gebruik dalk die roeteringnetwerk wat hierbo beskryf word. Trouens, baie van dotCloud se meer as honderd mikrodienste is as gereelde toepassings op die dotCloud-platform self ontplooi. Maar 'n klein aantal laevlak-dienste (veral dié wat hierdie roete-netwerk implementeer) het iets eenvoudiger nodig gehad, met minder afhanklikhede (aangesien hulle nie op hulself kon staatmaak om te werk nie - die goeie ou hoender-en-eierprobleem).

Hierdie lae-vlak, missie-kritieke dienste is ontplooi deur houers direk op 'n paar sleutel nodusse te laat loop. In hierdie geval is standaard platformdienste nie gebruik nie: skakelaar, skeduleerder en hardloper. As jy met moderne houerplatforms wil vergelyk, is dit soos om 'n beheervliegtuig mee te bestuur docker run direk op die nodusse, in plaas daarvan om die taak aan Kubernetes te delegeer. Dit is redelik soortgelyk in konsep statiese modules (peule), wat dit gebruik kubeadm of bootkube wanneer 'n selfstandige groepie begin.

Hierdie dienste is op 'n eenvoudige en kru wyse blootgelê: 'n YAML-lêer het hul name en adresse gelys; en elke kliënt moes 'n kopie van hierdie YAML-lêer neem vir ontplooiing.

Aan die een kant is dit uiters betroubaar omdat dit nie die ondersteuning van 'n eksterne sleutel/waarde winkel soos Zookeeper vereis nie (onthou, ens of Consul het nie op daardie tydstip bestaan ​​nie). Aan die ander kant het dit dit moeilik gemaak om dienste te verskuif. Elke keer as 'n skuif gemaak is, sal alle kliënte 'n opgedateerde YAML-lêer ontvang (en moontlik herlaai). Nie baie gemaklik nie!

Daarna het ons begin om 'n nuwe skema te implementeer, waar elke kliënt aan 'n plaaslike instaanbediener gekoppel is. In plaas van 'n adres en poort, hoef dit net die poortnommer van die diens te ken, en verbind via localhost. Die plaaslike instaanbediener hanteer hierdie verbinding en stuur dit aan na die werklike bediener. Nou, wanneer jy die agterkant na 'n ander masjien skuif of skaal, in plaas daarvan om alle kliënte op te dateer, hoef jy net al hierdie plaaslike gevolmagtigdes op te dateer; en 'n herlaai is nie meer nodig nie.

(Daar is ook beplan om die verkeer in TLS-verbindings in te kapsel en 'n ander instaanbediener aan die ontvangkant te plaas, asook om TLS-sertifikate te verifieer sonder die deelname van die ontvangsdiens, wat opgestel is om verbindings slegs op localhost. Meer hieroor later).

Dit is baie soortgelyk aan SmartStack van Airbnb, maar die beduidende verskil is dat SmartStack geïmplementeer en na produksie ontplooi word, terwyl dotCloud se interne roeteringstelsel van die hand gewys is toe dotCloud Docker geword het.

Ek beskou SmartStack persoonlik as een van die voorgangers van stelsels soos Istio, Linkerd en Consul Connect omdat hulle almal dieselfde patroon volg:

  • Begin 'n instaanbediener op elke nodus.
  • Kliënte koppel aan die instaanbediener.
  • Die beheervlak werk die proxy-konfigurasie op wanneer backends verander.
  • ... Wins!

Moderne implementering van 'n diensnetwerk

As ons vandag 'n soortgelyke rooster moes implementeer, kan ons soortgelyke beginsels gebruik. Stel byvoorbeeld 'n interne DNS-sone op deur diensname na adresse in die spasie te karteer 127.0.0.0/8. Begin dan HAProxy op elke nodus in die groepering, en aanvaar verbindings by elke diensadres (in daardie subnet 127.0.0.0/8) en herlei/balanseer die vrag na die toepaslike agterkant. HAProxy-konfigurasie kan beheer word confd, wat jou toelaat om backend-inligting in etcd of Consul te stoor en outomaties opgedateerde konfigurasie na HAProxy te stoot wanneer nodig.

Dit is omtrent hoe Istio werk! Maar met 'n paar verskille:

  • Gebruike Gesant-volmag in plaas van HAProxy.
  • Stoor backend-konfigurasie via Kubernetes API in plaas van etcd of Consul.
  • Dienste kry adresse op die interne subnet (Kubernetes ClusterIP-adresse) in plaas van 127.0.0.0/8.
  • Het 'n bykomende komponent (Citadel) om wedersydse TLS-verifikasie tussen die kliënt en bedieners by te voeg.
  • Ondersteun nuwe kenmerke soos stroombaanbreking, verspreide opsporing, kanarie-ontplooiing, ens.

Kom ons kyk vinnig na sommige van die verskille.

Gesant-volmag

Envoy Proxy is geskryf deur Lyft [Uber se mededinger in die taximark - ongeveer. baan]. Dit is in baie opsigte soortgelyk aan ander gevolmagtigdes (bv. HAProxy, Nginx, Traefik...), maar Lyft het hulle s'n geskryf omdat hulle kenmerke nodig gehad het wat ander gevolmagtigdes ontbreek, en dit het slimmer gelyk om 'n nuwe een te maak eerder as om die bestaande een uit te brei.

Envoy kan op sy eie gebruik word. As ek 'n spesifieke diens het wat aan ander dienste moet koppel, kan ek dit instel om aan Envoy te koppel, en dan Envoy dinamies opstel en herkonfigureer met die ligging van ander dienste, terwyl ek baie wonderlike bykomende funksionaliteit kry, soos sigbaarheid. In plaas van 'n pasgemaakte kliëntbiblioteek of om oproepspore in die kode in te spuit, stuur ons verkeer na Envoy, en dit samel statistieke vir ons in.

Maar Envoy is ook in staat om as datavlak (datavlak) vir die diensnetwerk. Dit beteken dat Envoy nou vir hierdie diensnetwerk opgestel is beheer vliegtuig (beheervliegtuig).

Beheer vliegtuig

Vir die beheervlak maak Istio staat op die Kubernetes API. Dit verskil nie baie van die gebruik van confd nie, wat staatmaak op etcd of Consul om die stel sleutels in die data stoor te sien. Istio gebruik die Kubernetes API om 'n stel Kubernetes-hulpbronne te sien.

Tussen dit en dan: Ek persoonlik het dit nuttig gevind Kubernetes API beskrywingwat lui:

Die Kubernetes API-bediener is 'n "dom bediener" wat berging, weergawe, validering, opdatering en semantiek vir API-bronne bied.

Istio is ontwerp om met Kubernetes te werk; en as jy dit buite Kubernetes wil gebruik, moet jy 'n instansie van die Kubernetes API-bediener (en die etcd-helperdiens) laat loop.

Diensadresse

Istio maak staat op ClusterIP-adresse wat Kubernetes toeken, dus ontvang Istio-dienste 'n interne adres (nie in die reeks nie) 127.0.0.0/8).

Verkeer na die ClusterIP-adres vir 'n spesifieke diens in 'n Kubernetes-kluster sonder Istio word deur kube-instaanbediener onderskep en na daardie instaanbediener se agterkant gestuur. As jy belangstel in die tegniese besonderhede, stel kube-proxy iptables-reëls (of IPVS-laaibalanseerders, afhangende van hoe dit opgestel is) op om die bestemmings-IP-adresse van verbindings wat na die ClusterIP-adres gaan, te herskryf.

Sodra Istio op 'n Kubernetes-kluster geïnstalleer is, verander niks totdat dit uitdruklik vir 'n gegewe verbruiker, of selfs die hele naamruimte, geaktiveer word deur 'n houer bekend te stel. sidecar in pasgemaakte peule. Hierdie houer sal 'n instansie van Envoy opstel en 'n stel iptables-reëls opstel om verkeer wat na ander dienste gaan, te onderskep en daardie verkeer na Envoy te herlei.

Wanneer dit met Kubernetes DNS geïntegreer word, beteken dit dat ons kode met diensnaam kan koppel en alles "werk net." Met ander woorde, ons kode gee navrae soos http://api/v1/users/4242dan api versoek op te los vir 10.97.105.48, sal die iptables-reëls verbindings vanaf 10.97.105.48 onderskep en dit aanstuur na die plaaslike Gesant-instaanbediener, en daardie plaaslike instaanbediener sal die versoek aanstuur na die werklike agterkant-API. Pff!

Bykomende fieterjasies

Istio bied ook end-tot-end-enkripsie en verifikasie via mTLS (mutual TLS). 'n Komponent genoem Citadel.

Daar is ook 'n komponent Mixer, waarvoor gesant kan aanvra elkeen versoek om 'n spesiale besluit oor daardie versoek te neem, afhangende van verskeie faktore soos kopskrifte, agterkantlading, ens... (moenie bekommerd wees nie: daar is baie maniere om Mixer aan die gang te hou, en selfs as dit ineenstort, sal Envoy aanhou werk boete as gevolmagtigde).

En natuurlik het ons sigbaarheid genoem: Envoy samel 'n groot hoeveelheid statistieke in terwyl hulle verspreide opsporing verskaf. In 'n mikrodienste-argitektuur, as 'n enkele API-versoek deur mikrodienste A, B, C en D moet gaan, sal verspreide opsporing 'n unieke identifiseerder by die versoek voeg by aanmelding en hierdie identifiseerder stoor deur middel van subversoeke na al hierdie mikrodienste, wat dit moontlik maak alle verwante oproepe wat vasgelê moet word, vertragings, ens.

Ontwikkel of koop

Istio het 'n reputasie om kompleks te wees. Daarteenoor is die bou van die roeteringnetwerk wat ek aan die begin van hierdie pos beskryf het, relatief eenvoudig met behulp van bestaande gereedskap. So, maak dit sin om eerder jou eie diensnetwerk te skep?

As ons beskeie behoeftes het (ons het nie sigbaarheid, 'n stroombreker en ander subtiliteite nodig nie), dan kom gedagtes by die ontwikkeling van ons eie instrument. Maar as ons Kubernetes gebruik, is dit dalk nie eens nodig nie, want Kubernetes verskaf reeds basiese gereedskap vir diensontdekking en vragbalansering.

Maar as ons gevorderde vereistes het, is dit blykbaar 'n baie beter opsie om 'n diensnetwerk te "aankoop". (Dit is nie altyd 'n "koop" nie, want Istio is oopbron, maar ons moet steeds ingenieurstyd belê om dit te verstaan, te ontplooi en te bestuur.)

Moet ek Istio, Linkerd of Consul Connect kies?

Tot dusver het ons net oor Istio gepraat, maar dit is nie die enigste diensmaas nie. Gewilde alternatief - Linkerd, en daar is meer Konsul Connect.

Wat om te kies?

Eerlik, ek weet nie. Op die oomblik ag ek myself nie bevoeg genoeg om hierdie vraag te beantwoord nie. Daar is 'n paar interessant artikels met 'n vergelyking van hierdie gereedskap en selfs maatstawwe.

Een belowende benadering is om 'n instrument soos supergloo. Dit implementeer 'n abstraksielaag om die API's wat deur diensmaskers blootgestel word, te vereenvoudig en te verenig. In plaas daarvan om die spesifieke (en, na my mening, relatief komplekse) API's van verskillende diensmaskers te leer, kan ons SuperGloo se eenvoudiger konstrukte gebruik - en maklik van die een na die ander oorskakel, asof ons 'n intermediêre konfigurasieformaat het wat HTTP-koppelvlakke en backends beskryf van die generering van die werklike konfigurasie vir Nginx, HAProxy, Traefik, Apache ...

Ek het 'n bietjie met Istio en SuperGloo gewoel, en in die volgende artikel wil ek wys hoe om Istio of Linkerd by 'n bestaande cluster te voeg deur SuperGloo te gebruik, en hoe laasgenoemde die werk gedoen kry, dit wil sê, laat jou toe om van een diensnetwerk na 'n ander sonder om konfigurasies te oorskryf.

Bron: will.com

Voeg 'n opmerking