Kontejnerë, mikroshërbime dhe rrjeta shërbimi

Në internet një bandë artikuj о rrjetë shërbimi (rrjetë shërbimi), dhe këtu është një tjetër. Hora! Por pse? Më pas, dua të shpreh mendimin tim se do të kishte qenë më mirë nëse rrjetat e shërbimit të shfaqeshin 10 vjet më parë, para ardhjes së platformave të kontejnerëve si Docker dhe Kubernetes. Nuk po them që këndvështrimi im është më i mirë ose më i keq se të tjerët, por meqenëse rrjetat e shërbimit janë kafshë mjaft komplekse, këndvështrime të shumta do të ndihmojnë për t'i kuptuar më mirë ato.

Do të flas për platformën dotCloud, e cila u ndërtua në mbi njëqind mikroshërbime dhe mbështeti mijëra aplikacione të kontejnerëve. Unë do të shpjegoj sfidat me të cilat u përballëm në zhvillimin dhe lëshimin e tij, dhe se si rrjetat e shërbimit mund (ose nuk mund) të ndihmonin.

Historia e dotCloud

Unë kam shkruar për historinë e dotCloud dhe zgjedhjet e arkitekturës për këtë platformë, por nuk kam folur shumë për shtresën e rrjetit. Nëse nuk doni të zhyteni në lexim artikulli i fundit në lidhje me dotCloud, këtu është thelbi me pak fjalë: është një platformë PaaS-si-shërbim që lejon klientët të ekzekutojnë një gamë të gjerë aplikacionesh (Java, PHP, Python...), me mbështetje për një gamë të gjerë të dhënash shërbimet (MongoDB, MySQL, Redis...) dhe një rrjedhë pune si Heroku: Ju ngarkoni kodin tuaj në platformë, ajo ndërton imazhe të kontejnerëve dhe i vendos ato.

Unë do t'ju tregoj se si trafiku u drejtua në platformën dotCloud. Jo sepse ishte veçanërisht i lezetshëm (edhe pse sistemi funksiononte mirë për kohën e tij!), por kryesisht sepse me mjete moderne një dizajn i tillë mund të zbatohet lehtësisht në një kohë të shkurtër nga një ekip modest nëse ata kanë nevojë për një mënyrë për të drejtuar trafikun midis një grupi të mikroshërbimeve ose një sërë aplikacionesh. Në këtë mënyrë, ju mund të krahasoni opsionet: çfarë ndodh nëse zhvilloni gjithçka vetë ose përdorni një rrjetë shërbimi ekzistues. Zgjedhja standarde: bëjeni vetë ose blini.

Drejtimi i trafikut për aplikacionet e pritura

Aplikimet në dotCloud mund të ekspozojnë pikat fundore HTTP dhe TCP.

Pikat fundore të HTTP shtohet në mënyrë dinamike në konfigurimin e grupit të balancuesit të ngarkesës Hipache. Kjo është e ngjashme me atë që bëjnë burimet sot Hyrje në Kubernetes dhe një balancues i ngarkesës si Traefik.

Klientët lidhen me pikat fundore të HTTP përmes domeneve të duhura, me kusht që emri i domenit të tregojë balancuesit e ngarkesës dotCloud. Asgje speciale.

Pikat fundore të TCP i lidhur me një numër porti, i cili më pas u kalohet të gjithë kontejnerëve në atë rafte nëpërmjet variablave të mjedisit.

Klientët mund të lidhen me pikat fundore TCP duke përdorur emrin e duhur të hostit (diçka si gateway-X.dotcloud.com) dhe numrin e portit.

Ky emër pritës zgjidhet në grupin e serverëve "nats" (nuk lidhet me NATYT), i cili do të drejtojë lidhjet hyrëse TCP në kontejnerin e duhur (ose, në rastin e shërbimeve të balancuara nga ngarkesa, në kontejnerët e duhur).

Nëse jeni njohur me Kubernetes, kjo ndoshta do t'ju kujtojë Shërbimet Porta e nyjeve.

Nuk kishte shërbime ekuivalente në platformën dotCloud ClusterIP: Për thjeshtësi, shërbimet u aksesuan në të njëjtën mënyrë si nga brenda ashtu edhe jashtë platformës.

Gjithçka ishte organizuar mjaft thjesht: implementimet fillestare të rrjeteve të rrugëtimit HTTP dhe TCP ishin ndoshta vetëm disa qindra rreshta Python secila. Algoritme të thjeshta (do të thosha naive) që u rafinuan ndërsa platforma u rrit dhe u shfaqën kërkesa shtesë.

Nuk kërkohej një rifaktorim i gjerë i kodit ekzistues. Veçanërisht, Aplikacione me 12 faktorë mund të përdorë drejtpërdrejt adresën e marrë përmes variablave të mjedisit.

Si është kjo e ndryshme nga një rrjetë moderne e shërbimit?

E kufizuar dukshmëria. Nuk kishim fare metrikë për rrjetën e rrugëtimit TCP. Kur bëhet fjalë për drejtimin HTTP, versionet e mëvonshme prezantuan metrikë të detajuar HTTP me kode gabimi dhe kohë përgjigjeje, por rrjetat moderne të shërbimit shkojnë edhe më tej, duke siguruar integrim me sistemet e grumbullimit të metrikës si Prometheus, për shembull.

Dukshmëria është e rëndësishme jo vetëm nga një këndvështrim operacional (për të ndihmuar në zgjidhjen e problemeve), por edhe kur lëshohen veçori të reja. Bëhet fjalë për sigurinë vendosja blu-jeshile и vendosja e kanarinave.

Efikasiteti i rrugëzimit është gjithashtu i kufizuar. Në rrjetën e drejtimit të dotCloud, i gjithë trafiku duhej të kalonte përmes një grupi nyjesh të dedikuara rrugëtimi. Kjo nënkuptonte kalimin e mundshëm të kufijve të shumëfishtë AZ (Zona e disponueshmërisë) dhe rritje të ndjeshme të vonesës. Më kujtohet kodi i zgjidhjes së problemeve që bënte mbi njëqind pyetje SQL për faqe dhe hapte një lidhje të re me serverin SQL për çdo pyetje. Kur ekzekutohet në nivel lokal, faqja ngarkohet menjëherë, por në dotCloud duhen disa sekonda për t'u ngarkuar sepse çdo lidhje TCP (dhe pyetje pasuese SQL) merr dhjetëra milisekonda. Në këtë rast të veçantë, lidhjet e vazhdueshme e zgjidhën problemin.

Rrjetat moderne të shërbimit janë më të mira në trajtimin e problemeve të tilla. Para së gjithash, ata kontrollojnë që lidhjet janë të drejtuara në burim. Rrjedha logjike është e njëjtë: клиент → меш → сервис, por tani rrjeta funksionon në nivel lokal dhe jo në nyje të largëta, kështu që lidhja клиент → меш është lokal dhe shumë i shpejtë (mikrosekonda në vend të milisekondave).

Rrjetat moderne të shërbimit zbatojnë gjithashtu algoritme më të zgjuara të balancimit të ngarkesës. Duke monitoruar shëndetin e backend-eve, ata mund të dërgojnë më shumë trafik në backend më të shpejtë, duke rezultuar në përmirësim të performancës së përgjithshme.

siguri më mirë gjithashtu. Rrjeta e rrugëzimit dotCloud funksiononte tërësisht në EC2 Classic dhe nuk e kripton trafikun (bazuar në supozimin se nëse dikush arrin të vendosë një sniffer në trafikun e rrjetit EC2, ju tashmë ishit në telashe të mëdha). Rrjetat moderne të shërbimit mbrojnë në mënyrë transparente të gjithë trafikun tonë, për shembull, me vërtetimin e ndërsjellë TLS dhe enkriptimin pasues.

Drejtimi i trafikut për shërbimet e platformës

Mirë, ne kemi diskutuar trafikun midis aplikacioneve, por çfarë ndodh me vetë platformën dotCloud?

Vetë platforma përbëhej nga rreth njëqind mikroshërbime përgjegjëse për funksione të ndryshme. Disa pranuan kërkesa nga të tjerët, dhe disa ishin punëtorë të prapavijës që u lidhën me shërbime të tjera, por nuk pranuan vetë lidhjet. Në çdo rast, çdo shërbim duhet të dijë pikat fundore të adresave me të cilat duhet të lidhet.

Shumë shërbime të nivelit të lartë mund të përdorin rrjetën e rrugëzimit të përshkruar më sipër. Në fakt, shumë nga më shumë se njëqind mikroshërbimet e dotCloud janë vendosur si aplikacione të rregullta në vetë platformën dotCloud. Por një numër i vogël shërbimesh të nivelit të ulët (veçanërisht ato që zbatojnë këtë rrjetë të rrugëzimit) kishin nevojë për diçka më të thjeshtë, me më pak varësi (pasi nuk mund të vareshin nga vetja për të punuar - problemi i vjetër i mirë i pulës dhe vezëve).

Këto shërbime të nivelit të ulët dhe kritike për misionin u vendosën duke drejtuar kontejnerët direkt në disa nyje kyçe. Në këtë rast, shërbimet standarde të platformës nuk janë përdorur: lidhës, planifikues dhe vrapues. Nëse doni të krahasoheni me platformat moderne të kontejnerëve, është si të drejtoni një aeroplan kontrolli me të docker run direkt në nyje, në vend që ta delegoni detyrën te Kubernetes. Është shumë e ngjashme në koncept module statike (pods), të cilin e përdor kubeadm ose bootkube kur nisni një grup të pavarur.

Këto shërbime u ekspozuan në një mënyrë të thjeshtë dhe të papërpunuar: një skedar YAML listonte emrat dhe adresat e tyre; dhe secili klient duhej të merrte një kopje të këtij skedari YAML për vendosje.

Nga njëra anë, është jashtëzakonisht i besueshëm sepse nuk kërkon mbështetjen e një dyqani të jashtëm të çelësave/vlerave si Zookeeper (mbani mend, etjd ose Konsulli nuk ekzistonte në atë kohë). Nga ana tjetër, vështirësoi lëvizjen e shërbimeve. Sa herë që bëhej një lëvizje, të gjithë klientët do të merrnin një skedar të përditësuar YAML (dhe potencialisht do të rindizeshin). Jo shumë komode!

Më pas, filluam të zbatonim një skemë të re, ku secili klient lidhej me një server lokal proxy. Në vend të një adrese dhe porti, duhet vetëm të dijë numrin e portit të shërbimit dhe të lidhet nëpërmjet localhost. Proxy lokal trajton këtë lidhje dhe e përcjell atë te serveri aktual. Tani, kur zhvendosni backend në një makinë tjetër ose shkallëzoni, në vend që të përditësoni të gjithë klientët, ju duhet vetëm të përditësoni të gjitha këto proxies lokale; dhe një rindezje nuk kërkohet më.

(Ishte planifikuar gjithashtu të përmbledhte trafikun në lidhjet TLS dhe të vendoste një server tjetër proxy në anën marrëse, si dhe të verifikonte certifikatat TLS pa pjesëmarrjen e shërbimit marrës, i cili është konfiguruar të pranojë lidhje vetëm në localhost. Më shumë për këtë më vonë).

Kjo është shumë e ngjashme me SmartStack nga Airbnb, por ndryshimi domethënës është se SmartStack zbatohet dhe vendoset në prodhim, ndërsa sistemi i brendshëm i rrugëtimit të dotCloud u la në sirtar kur dotCloud u bë Docker.

Unë personalisht e konsideroj SmartStack si një nga paraardhësit e sistemeve si Istio, Linkerd dhe Consul Connect sepse të gjithë ndjekin të njëjtin model:

  • Drejtoni një përfaqësues në secilën nyje.
  • Klientët lidhen me përfaqësuesin.
  • Plani i kontrollit përditëson konfigurimin e përfaqësuesit kur ndryshojnë backend-et.
  • ... Fitim!

Zbatimi modern i një rrjetë shërbimi

Nëse do të kishim nevojë për të zbatuar një rrjet të ngjashëm sot, ne mund të përdornim parime të ngjashme. Për shembull, konfiguroni një zonë të brendshme DNS duke hartuar emrat e shërbimeve me adresat në hapësirë 127.0.0.0/8. Më pas ekzekutoni HAProxy në secilën nyje në grup, duke pranuar lidhje në secilën adresë shërbimi (në atë nënrrjet 127.0.0.0/8) dhe ridrejtimin/balancimin e ngarkesës në bazën e duhur. Konfigurimi i HAProxy mund të kontrollohet konfd, duke ju lejuar të ruani informacionin e backend në etcd ose Consul dhe të shtyni automatikisht konfigurimin e përditësuar në HAProxy kur është e nevojshme.

Kjo është pak a shumë se si funksionon Istio! Por me disa dallime:

  • Përdorimet Përfaqësuesi i të dërguarit në vend të HAProxy.
  • Ruan konfigurimin e backend-it nëpërmjet Kubernetes API në vend të etcd ose Consul.
  • Shërbimeve u ndahen adresa në nënrrjetin e brendshëm (adresat Kubernetes ClusterIP) në vend të 127.0.0.0/8.
  • Ka një komponent shtesë (Citadel) për të shtuar vërtetimin e ndërsjellë TLS midis klientit dhe serverëve.
  • Mbështet veçori të reja si ndërprerja e qarkut, gjurmimi i shpërndarë, vendosja e kanarinës, etj.

Le të hedhim një vështrim të shpejtë në disa nga ndryshimet.

Përfaqësuesi i të dërguarit

Envoy Proxy u shkrua nga Lyft [konkurrenti i Uber në tregun e taksive - përafërsisht. korsi]. Është i ngjashëm në shumë mënyra me proxy-et e tjera (p.sh. HAProxy, Nginx, Traefik...), por Lyft shkroi të tyren sepse atyre u duheshin veçori që u mungonin proxy-ve të tjerë dhe dukej më e zgjuar të bëhej një e re sesa të zgjerohej ajo ekzistuese.

I dërguari mund të përdoret më vete. Nëse kam një shërbim specifik që duhet të lidhet me shërbime të tjera, mund ta konfiguroj që të lidhet me Envoy dhe më pas të konfiguroj dhe rikonfiguroj në mënyrë dinamike Envoy me vendndodhjen e shërbimeve të tjera, duke marrë shumë funksionalitete shtesë të shkëlqyera, siç është dukshmëria. Në vend të një biblioteke klienti të personalizuar ose injektimit të gjurmëve të thirrjeve në kod, ne dërgojmë trafik te Envoy dhe ai mbledh metrikë për ne.

Por i dërguari është gjithashtu i aftë të punojë si plani i të dhënave (aeroplani i të dhënave) për rrjetën e shërbimit. Kjo do të thotë që Envoy tani është konfiguruar për këtë rrjetë shërbimi avioni i kontrollit (avioni i kontrollit).

Avioni i kontrollit

Për planin e kontrollit, Istio mbështetet në Kubernetes API. Kjo nuk është shumë e ndryshme nga përdorimi i confd, i cili mbështetet në etcd ose Konsul për të parë grupin e çelësave në dyqanin e të dhënave. Istio përdor Kubernetes API për të parë një grup burimesh Kubernetes.

Midis kësaj dhe pastaj: Unë personalisht e gjeta këtë të dobishme Përshkrimi i Kubernetes APIe cila lexon:

Serveri Kubernetes API është një "server memec" që ofron ruajtje, versionim, vërtetim, përditësim dhe semantikë për burimet API.

Istio është krijuar për të punuar me Kubernetes; dhe nëse dëshironi ta përdorni jashtë Kubernetes, atëherë duhet të ekzekutoni një shembull të serverit API të Kubernetes (dhe shërbimin ndihmës etcd).

Adresat e shërbimit

Istio mbështetet në adresat ClusterIP që Kubernetes cakton, kështu që shërbimet Istio marrin një adresë të brendshme (jo në intervalin 127.0.0.0/8).

Trafiku në adresën ClusterIP për një shërbim specifik në një grup Kubernetes pa Istio përgjohet nga kube-proxy dhe dërgohet në backend-in e atij përfaqësuesi. Nëse jeni të interesuar për detajet teknike, kube-proxy vendos rregullat iptables (ose balancuesit e ngarkesës IPVS, në varësi të mënyrës se si është konfiguruar) për të rishkruar adresat IP të destinacionit të lidhjeve që shkojnë në adresën ClusterIP.

Pasi Istio të instalohet në një grup Kubernetes, asgjë nuk ndryshon derisa të aktivizohet në mënyrë eksplicite për një konsumator të caktuar, apo edhe të gjithë hapësirën e emrave, duke futur një kontejner sidecar në pods me porosi. Ky kontejner do të rrotullojë një shembull të Envoy dhe do të vendosë një sërë rregullash iptables për të kapur trafikun që shkon në shërbime të tjera dhe do ta ridrejtojë atë trafik tek i Dërguari.

Kur integrohet me Kubernetes DNS, kjo do të thotë që kodi ynë mund të lidhet me emrin e shërbimit dhe gjithçka "thjesht funksionon". Me fjalë të tjera, kodi ynë lëshon pyetje si http://api/v1/users/4242atëherë api zgjidh kërkesën për 10.97.105.48, rregullat iptables do të përgjojnë lidhjet nga 10.97.105.48 dhe do t'i përcjellin ato tek përfaqësuesi lokal i Envoy, dhe ai përfaqësues lokal do ta përcjellë kërkesën në API-në aktuale të backend. Eh!

frills shtesë

Istio gjithashtu ofron kriptim dhe vërtetim nga fundi në fund nëpërmjet mTLS (TLS reciproke). Një komponent i quajtur Kala.

Ekziston edhe një komponent mikser, të cilin i Dërguari mund ta kërkojë i secilit kerkoni per te marre nje vendim te vecante per ate kerkese ne varesi te faktoreve te ndryshem si titujt, ngarkesa e backend-it, etj... (mos u shqetesoni: ka shume menyra per ta mbajtur Mixer-in te funksionoje, dhe edhe nese ai prishet, Envoy do te vazhdoje te punoje gjobë si përfaqësues) .

Dhe, sigurisht, përmendëm dukshmërinë: I dërguari mbledh një sasi të madhe metrikash ndërsa ofron gjurmim të shpërndarë. Në një arkitekturë të mikroshërbimeve, nëse një kërkesë e vetme API duhet të kalojë përmes mikroshërbimeve A, B, C dhe D, atëherë pas hyrjes, gjurmimi i shpërndarë do të shtojë një identifikues unik në kërkesë dhe do ta ruajë këtë identifikues përmes nënkërkesave për të gjitha këto mikroshërbime, duke lejuar të gjitha thirrjet e lidhura do të kapen, vonesat, etj.

Zhvilloni ose blini

Istio ka një reputacion si kompleks. Në të kundërt, ndërtimi i rrjetës së rrugëzimit që përshkrova në fillim të këtij postimi është relativisht i thjeshtë duke përdorur mjetet ekzistuese. Pra, a ka kuptim të krijoni rrjetën tuaj të shërbimit?

Nëse kemi nevoja modeste (nuk kemi nevojë për dukshmëri, ndërprerës dhe hollësi të tjera), atëherë mendimet vijnë për të zhvilluar mjetin tonë. Por nëse përdorim Kubernetes, ai mund të mos jetë as i nevojshëm sepse Kubernetes tashmë ofron mjete bazë për zbulimin e shërbimit dhe balancimin e ngarkesës.

Por nëse kemi kërkesa të avancuara, atëherë "blerja" e një rrjetë shërbimi duket të jetë një opsion shumë më i mirë. (Kjo nuk është gjithmonë një "blerje" sepse Istio është me burim të hapur, por ne ende duhet të investojmë kohë inxhinierike për ta kuptuar, vendosur dhe menaxhuar atë.)

A duhet të zgjedh Istio, Linkerd apo Consul Connect?

Deri tani kemi folur vetëm për Istio, por kjo nuk është e vetmja rrjetë shërbimi. Alternativa popullore - Linkerd, dhe ka më shumë Konsulli Lidhu.

Çfarë duhet të zgjidhni?

Sinqerisht, nuk e di. Për momentin nuk e konsideroj veten mjaft kompetent për t'iu përgjigjur kësaj pyetjeje. Janë disa interesante artikuj me një krahasim të këtyre mjeteve dhe madje standardet.

Një qasje premtuese është përdorimi i një mjeti si SuperGloo. Ai zbaton një shtresë abstraksioni për të thjeshtuar dhe unifikuar API-të e ekspozuara nga rrjetat e shërbimit. Në vend që të mësojmë API-të specifike (dhe, për mendimin tim, relativisht komplekse) të rrjetave të ndryshme të shërbimeve, ne mund të përdorim konstruksionet më të thjeshta të SuperGloo - dhe të kalojmë lehtësisht nga njëri në tjetrin, sikur të kishim një format konfigurimi të ndërmjetëm që përshkruan ndërfaqet dhe mbështetësit HTTP të aftë të gjenerimit të konfigurimit aktual për Nginx, HAProxy, Traefik, Apache...

Jam marrë pak me Istio dhe SuperGloo dhe në artikullin vijues dua të tregoj se si të shtosh Istio ose Linkerd në një grup ekzistues duke përdorur SuperGloo dhe se si ky i fundit e kryen punën, domethënë, ju lejon të kaloni nga një rrjetë shërbimi në tjetrën pa mbishkrimin e konfigurimeve.

Burimi: www.habr.com

Shto një koment