Containers, mikrotsjinsten en tsjinstmeshes

Op it ynternet in bûn artikels о tsjinst meshes (tsjinstmesh), en hjir is noch ien. Hoera! Wêrom? Dan wol ik myn miening sizze dat tsjinstmeshes 10 jier lyn better west hawwe, foar de komst fan kontenerplatfoarms lykas Docker en Kubernetes. Ik sis net dat myn eachpunt better of slimmer is as oaren, mar om't tsjinstmeshes frij komplekse bisten binne, sille meardere stânpunten helpe om se better te begripen.

Ik sil prate oer it dotCloud-platfoarm, dat waard boud op mear dan hûndert mikrotsjinsten en stipe tûzenen applikaasjes yn konteners. Ik sil de útdagings ferklearje dy't wy tsjinkamen by it ûntwikkeljen en lansearjen, en hoe't tsjinstmeshes kinne (of miskien net) helpe.

dotcloud skiednis

Ik haw al skreaun oer de skiednis fan dotCloud en de kar fan arsjitektuer foar dit platfoarm, mar haw net folle praat oer de netwurklaach. As jo ​​​​net lêze wolle lêste artikel oer dotCloud, hjir is de essinsje: it is in PaaS-platfoarm-as-a-tsjinst wêrmei kliïnten in breed oanbod fan applikaasjes kinne útfiere (Java, PHP, Python ...), mei stipe foar in breed oanbod fan gegevenstsjinsten ( MongoDB, MySQL, Redis ...) en in workflow lykas Heroku: jo uploade jo koade nei it platfoarm, it bout kontenerôfbyldings en set se yn.

Ik sil jo fertelle hoe't ferkear waard stjoerd nei it dotCloud-platfoarm. Net om't it bysûnder cool wie (hoewol't it systeem goed wurke foar syn tiid!), mar foaral om't mei help fan moderne ark sa'n ûntwerp maklik yn koarte tiid troch in beskieden team útfierd wurde kin as se in manier nedich hawwe om te rûte ferkear tusken in bosk mikrotsjinsten as in bosk applikaasjes. Sa kinne jo opsjes fergelykje: wat bart der as jo alles sels ûntwikkelje of in besteande tsjinstmesh brûke. Standert kar: meitsje jo eigen of keapje.

Ferkearsrouting foar hosted applikaasjes

Applikaasjes op dotCloud kinne HTTP- en TCP-einpunten bleatstelle.

HTTP-einpunten dynamysk tafoege oan de load balancer kluster konfiguraasje Hipache. Dit is gelyk oan wat boarnen hjoed dogge Ingress yn Kubernetes en in load balancer lykas Traefik.

Klanten ferbine mei HTTP-einpunten fia de passende domeinen, op betingst dat de domeinnamme wiist op dotCloud load balancers. Neat spesjaals.

TCP einpunten ferbûn mei in poarte nûmer, dat wurdt dan trochjûn oan alle konteners yn dy steapel fia omjouwingsfariabelen.

Klanten kinne ferbine mei TCP-einpunten mei de passende hostnamme (wat as gateway-X.dotcloud.com) en poartenûmer.

Dizze hostnamme wurdt oplost nei it "nats"-tsjinnerkluster (net relatearre oan NATS) dy't ynkommende TCP-ferbiningen nei de juste kontener sil rûte (of, yn it gefal fan load-balansearre tsjinsten, nei de juste konteners).

As jo ​​​​bekend binne mei Kubernetes, sil dit jo wierskynlik herinnerje oan tsjinsten NodePort.

D'r wie gjin tsjinsten lykweardich op it dotCloud-platfoarm ClusterIP: foar ienfâld barde tagong ta tsjinsten op deselde manier sawol fan binnen as bûten it platfoarm.

Alles wie gewoan ienfâldich organisearre: de oarspronklike ymplemintaasjes fan HTTP- en TCP-routingnetwurken wiene wierskynlik mar in pear hûndert rigels fan Python. Ienfâldige (ik soe sizze, naïve) algoritmen dy't binne ferfine mei de groei fan it platfoarm en it ûntstean fan ekstra easken.

Wiidweidige refactoring fan besteande koade wie net nedich. Yn't bysonder, 12 Faktor Apps kin direkt brûke it adres krigen fia omjouwingsfariabelen.

Hoe is dit oars as in moderne tsjinstmesh?

Limited sichtberens. Wy hiene hielendal gjin metriken foar it TCP-routingmesh. As it giet om HTTP-routing, hawwe mear resinte ferzjes detaillearre HTTP-metriken mei flaterkoades en antwurdtiden, mar moderne tsjinstmeshes geane noch fierder, en jouwe yntegraasje mei metriken-sammelsystemen lykas Prometheus, bygelyks.

Sichtberens is wichtich net allinich út in operasjoneel eachpunt (om problemen op te lossen), mar ek as nije funksjes wurde frijlitten. Prate oer feilich blau-griene ynset и ynset fan kanaries.

Routing effisjinsje is ek beheind. Yn it dotCloud-routingmesh moast alle ferkear troch in kluster fan tawijde routingknooppunten passe. Dit betsjutte potinsjeel oerstekke meardere AZ (beskikberens sône) grinzen en in signifikante ferheging fan latency. Ik herinner my probleemoplossingskoade dy't mear as hûndert SQL-fragen per side makke en in nije ferbining iepene mei de SQL-tsjinner foar elke fraach. As se lokaal rinne, laadt de side direkt, mar op dotCloud duorret it in pear sekonden om te laden, om't elke TCP-ferbining (en folgjende SQL-query) tsientallen millisekonden nimt. Yn dit bysûndere gefal hawwe persistente ferbiningen it probleem oplost.

Moderne tsjinstmeshes binne better yn it omgean mei sokke problemen. As earste kontrolearje se dat de ferbiningen wurde trochstjoerd yn boarne. De logyske stream is itselde: клиент → меш → сервис, mar no wurket it mesh lokaal en net op knooppunten op ôfstân, dus de ferbining клиент → меш is lokaal en tige fluch (mikrosekonden ynstee fan millisekonden).

Moderne tsjinstmeshes implementearje ek tûkere algoritmen foar load balancing. Troch de sûnens fan 'e backends te kontrolearjen, kinne se mear ferkear stjoere nei rappere backends, wat resulteart yn bettere algemiene prestaasjes.

Feiligens is ek better. It dotCloud-routingmesh rûn folslein op EC2 Classic en fersifere ferkear net (ûnder de oanname dat as immen it slagge om in sniffer op EC2 netwurkferkear te setten, jo al yn grutte problemen binne). Moderne tsjinstmeshes beskermje transparant al ús ferkear, bygelyks mei ûnderlinge TLS-ferifikaasje en folgjende fersifering.

Ferkearsrouting foar platfoarmtsjinsten

Okee, wy hawwe ferkear tusken applikaasjes besprutsen, mar hoe sit it mei it dotCloud-platfoarm sels?

It platfoarm sels bestie út sa'n hûndert mikrotsjinsten ferantwurdlik foar ferskate funksjes. Guon akseptearren oanfragen fan oaren, en guon wiene eftergrûnwurkers dy't ferbûn wiene mei oare tsjinsten, mar sels gjin ferbiningen akseptearren. Yn beide gefallen moat elke tsjinst de einpunten kenne fan 'e adressen wêrmei't it moat ferbine.

In protte tsjinsten op hege nivo kinne it hjirboppe beskreaune routingmesh brûke. Eins binne in protte fan 'e mear dan XNUMX dotCloud-mikrotsjinsten ynset as reguliere applikaasjes op it dotCloud-platfoarm sels. Mar in lyts oantal tsjinsten op leech nivo (benammen dejingen dy't dit routingmesh ymplementearje) hiene wat ienfâldiger nedich, mei minder ôfhinklikens (om't se net op harsels ôfhinklik koenen om te wurkjen - it goede âlde probleem mei hin en aaien).

Dizze essensjele tsjinsten op leech nivo waarden ynset troch konteners direkt op in pear kaaiknooppunten út te fieren. Tagelyk wiene de standert platfoarmtsjinsten net belutsen: linker, planner en runner. As jo ​​​​wolle fergelykje mei moderne kontenerplatfoarms, is it as it lansearjen fan in kontrôlefleanmasine mei docker run direkt op 'e knopen, ynstee fan delegearje de taak oan Kubernetes. It is aardich gelyk yn konsept statyske modules (pods), dy't brûkt kubeadm of bootkube by it opstarten fan in standalone kluster.

Dizze tsjinsten waarden op in ienfâldige en rûge manier bleatsteld: in YAML-bestân fermelde har nammen en adressen; en elke kliïnt moast in kopy fan dit YAML-bestân nimme foar ynset.

Oan de iene kant, dit is ekstreem betrouber, omdat it net nedich de stipe fan in eksterne kaai / wearde winkel, lykas Zookeeper (ûnthâld, etcd of Consul bestie net op dat stuit). Oan 'e oare kant makke it it lestich om tsjinsten te ferpleatsen. Elke kear dat in ferhuzing waard makke, moasten alle kliïnten in bywurke YAML-bestân krije (en mooglik opnij laden). Net hiel noflik!

Dêrnei begûnen wy in nij skema te ymplementearjen, wêrby't elke kliïnt ferbûn is mei in lokale proxy-tsjinner. Yn stee fan it adres en poarte, it moat allinnich witte it poarte nûmer fan de tsjinst, en ferbine fia localhost. De lokale proxy behannelet dizze ferbining en stjoert it troch nei de eigentlike tsjinner. No by it ferpleatsen fan de backend nei in oare masine of skaalfergrutting, ynstee fan it bywurkjen fan alle kliïnten, moatte allinich al dizze lokale proxy's bywurke wurde; en in trochstart is net mear nedich.

(It wie ek pland om ferkear yn TLS-ferbiningen yn te kapsulearjen en in oare proxy-tsjinner op 'e ûntfangende kant te ynstallearjen, en ek TLS-sertifikaten te kontrolearjen sûnder de dielname fan' e ûntfangende tsjinst, dy't konfigureare is om allinich ferbiningen te akseptearjen op localhost. Mear dêroer letter).

Dit is hiel gelyk oan smartstack fan Airbnb, mar it signifikante ferskil is dat SmartStack wurdt ymplementearre en ynset foar produksje, wylst it ynterne routingsysteem fan dotCloud waard ynpakt doe't dotCloud feroare yn Docker.

Ik persoanlik beskôgje SmartStack as ien fan 'e foargongers fan systemen lykas Istio, Linkerd en Consul Connect, om't se allegear itselde patroan folgje:

  • Run in proxy op elke knooppunt.
  • Klanten ferbine mei de proxy.
  • It kontrôlefleantúch fernijt de proxy-konfiguraasje as backends feroarje.
  • … Winst!

Moderne Service Mesh ymplemintaasje

As wy hjoed in ferlykber raster moatte ymplementearje, kinne wy ​​​​fergelykbere prinsipes brûke. Stel bygelyks in ynterne DNS-sône yn troch tsjinstnammen yn kaart te bringen nei adressen yn romte 127.0.0.0/8. Rin dan HAProxy op elke klusterknoop, akseptearje ferbiningen op elk tsjinstadres (op dat subnet 127.0.0.0/8) en trochferwizing / balânsjen fan de lading nei de passende backends. HAProxy-konfiguraasje kin wurde beheard confd, wêrtroch jo backend-ynformaasje kinne opslaan yn etcd as Consul en automatysk bywurke konfiguraasje nei HAProxy drukke as it nedich is.

Dit is hoe't Istio wurket! Mar mei wat ferskillen:

  • Uses Envoy Proxy ynstee fan HAProxy.
  • Besparret backend konfiguraasje fia Kubernetes API ynstee fan etcd of Consul.
  • Tsjinsten wurde tawiisd adressen op de ynterne subnet (Kubernetes ClusterIP adressen) ynstee fan 127.0.0.0/8.
  • Hat in ekstra komponint (Citadel) om ûnderlinge TLS-ferifikaasje ta te foegjen tusken kliïnt en servers.
  • Unterstützt nije funksjes lykas circuit breaking, ferspraat tracing, kanaryske ynset, ensfh.

Litte wy efkes sjen nei guon fan 'e ferskillen.

Envoy Proxy

Envoy Proxy waard skreaun troch Lyft [Uber's konkurrint yn 'e taksymerk - sawat. mei.]. It is op in protte manieren gelyk oan oare proxy's (bgl in besteande.

Envoy kin op himsels brûkt wurde. As ik in spesifike tsjinst haw dy't ferbine moat mei oare tsjinsten, kin ik it ynstelle om te ferbinen mei Envoy en Envoy dan dynamysk konfigurearje en opnij konfigurearje mei de lokaasje fan oare tsjinsten, wylst ik in protte geweldige ekstra's krije lykas sichtberens. Yn stee fan in oanpaste klant bibleteek of ynjeksje yn de oprop tracing koade, wy stjoere ferkear nei Envoy, en it sammelet metrics foar ús.

Mar Envoy is ek by steat om te wurkjen as data fleanmasine (data fleanmasine) foar de tsjinst mesh. Dit betsjut dat no foar dit tsjinstmesh Envoy is konfigureare kontrôle fleanmasine (kontrôlefleantúch).

Kontrole fleanmasine

Yn it kontrôlefleantúch fertrout Istio op de Kubernetes API. Dit is net hiel oars as it brûken fan confd, dy't fertrout op etcd of Consul om in set fan kaaien op te sykjen yn 'e gegevenswinkel. Istio sjocht troch in set fan Kubernetes-boarnen fia de Kubernetes API.

Tusken dit en dan: Ik persoanlik fûn dit nuttich Beskriuwing fan de Kubernetes APIdy't lêst:

De Kubernetes API-tsjinner is in "domme server" dy't opslach, ferzje, falidaasje, bywurking en API-boarne-semantyk biedt.

Istio is ûntwurpen om te wurkjen mei Kubernetes; en as jo it bûten Kubernetes wolle brûke, dan moatte jo in eksimplaar fan 'e Kubernetes API-tsjinner (en de etcd-helpertsjinst) begjinne.

Service Adressen

Istio fertrout op de ClusterIP-adressen dy't Kubernetes tawiist, sadat Istio-tsjinsten in ynterne adres krije (net yn it berik 127.0.0.0/8).

Ferkear nei in ClusterIP-adres foar in spesifike tsjinst yn in Kubernetes-kluster sûnder Istio wurdt ûnderskept troch kube-proxy en stjoerd nei de efterkant fan 'e proxy. As jo ​​​​ynteressearre binne yn 'e technyske details, set kube-proxy iptables-regels op (as IPVS-loadbalancers, ôfhinklik fan hoe't it is konfigureare) om de bestimmings-IP-adressen fan ferbiningen nei it ClusterIP-adres te herskriuwen.

As Istio ienris ynstalleare is op in Kubernetes-kluster, feroaret neat oant it eksplisyt ynskeakele is foar in opjûne konsumint, of sels de hiele nammeromte, troch in kontener yn te fieren sidecar oan oanpaste pods. Dizze kontener sil in Envoy-eksimplaar begjinne en in set fan iptables-regels ynstelle om ferkear te ûnderskeppen dat nei oare tsjinsten giet en dat ferkear omliede nei Envoy.

As yntegrearre mei Kubernetes DNS, betsjut dit dat ús koade kin ferbine mei tsjinst namme, en alles "gewoan wurket". Mei oare wurden, ús koade jout fragen lykas http://api/v1/users/4242dan api oplosse in fersyk foar 10.97.105.48, de iptables-regels ûnderskeppe ferbiningen fan 10.97.105.48 en omliede se nei de lokale Envoy-proxy, dy't it fersyk trochstjoert nei de eigentlike API-backend. Phew!

Ekstra franje

Istio leveret ek end-to-end fersifering en autentikaasje fia mTLS (mutual TLS). De komponint neamd Citadel.

Der is ek in komponint Mixer, dêr't gesant foar oanfreegje kin fan elk fersykje om in spesjaal beslút te nimmen oer dat fersyk ôfhinklik fan ferskate faktoaren lykas kopteksten, backend-laden, ensfh. as proxy).

En, fansels, hawwe wy sichtberens neamd: Envoy sammelt in enoarme hoemannichte metriken by it leverjen fan ferspraat tracing. Yn in arsjitektuer foar mikrotsjinsten, as in inkeld API-fersyk troch mikrotsjinsten A, B, C en D moat gean, dan sil by oanmelding, ferspraat tracing in unike identifier tafoegje oan it fersyk en dizze identifier opslaan fia subfersiken nei al dizze mikrotsjinsten, wêrtroch jo om alle relatearre petearen, har fertragingen, ensfh.

Untwikkelje of keapje

Istio hat in reputaasje om in kompleks systeem te wêzen. Yn tsjinstelling, it bouwen fan it routingmesh dat ik beskreaun oan it begjin fan dizze post is relatyf maklik mei besteande ark. Dat, hat it sin om ynstee jo eigen tsjinstmesh te meitsjen?

As wy beskieden behoeften hawwe (wy hawwe gjin sichtberens, in circuit breaker en oare subtiliteiten nedich), dan komme gedachten oer it ûntwikkeljen fan ús eigen ark. Mar as wy Kubernetes brûke, is it miskien net iens nedich, om't Kubernetes al de basisynstruminten leveret foar tsjinstûntdekking en loadbalancing.

Mar as wy avansearre easken hawwe, dan liket it "keapjen" fan in tsjinstmesh in folle bettere opsje. (Dit is net altyd in "oankeap", om't Istio iepen boarne is, mar wy moatte noch yngenieurtiid ynvestearje om it te begripen, yn te setten en te behearjen.)

Wat te kiezen: Istio, Linkerd of Consul Connect?

Oant no hawwe wy allinich praat oer Istio, mar it is net it ienige tsjinstmesh. It populêre alternatyf is Linkerd, mar der is mear Konsul Connect.

Wat te kiezen?

Om earlik te wêzen, ik wit it net. Op it stuit achtsje ik mysels net kompetint genôch om dizze fraach te beantwurdzjen. Der binne in pear nijsgjirrich artikels mei in ferliking fan dizze ark en sels benchmarks.

Ien kânsrike oanpak is it brûken fan in ark lykas supergloo. It ymplementearret in abstraksjelaach om de API's te ferienfâldigjen en te ferienigjen dy't wurde levere troch tsjinstmeshes. Ynstee fan it learen fan de spesifike (en, nei myn miening, relatyf komplekse) API's fan ferskate tsjinstmeshes, kinne wy ​​​​de ienfâldiger SuperGloo-konstruksjes brûke - en maklik fan de iene nei de oare wikselje, as hiene wy ​​in tuskenlizzende konfiguraasjeformaat dy't HTTP-ynterfaces en backends beskriuwt yn steat om de eigentlike konfiguraasje te generearjen foar Nginx, HAProxy, Traefik, Apache ...

Ik spile in bytsje mei Istio en SuperGloo, en yn it folgjende artikel wol ik sjen litte hoe't jo Istio of Linkerd taheakje kinne oan in besteande kluster mei SuperGloo, en hoe't de lêste har wurk sil dwaan, dat is, it lit jo wikselje fan ien tsjinstmesh nei in oar sûnder konfiguraasjes te herskriuwen.

Boarne: www.habr.com

Add a comment