Në internet (service mesh), dhe ja një tjetër. Hurrah! Por përse? Sepse dëshiroj të paraqes mendimin tim që do të ishte më mirë nëse rrjetet e shërbimeve do të ishin shfaqur 10 vjet më parë, para se të shfaqeshin platformat e kontejnerëve si Docker dhe Kubernetes. Nuk po pretendoj se pika ime e fortë është më e mirë ose më e keqe se të tjerat, por pasi që rrjetet e shërbimeve janë krejt të ndërlikuara, shumësia e pikave të shikimit ndihmon për t'i kuptuar ato më mirë.
Do të flas për platformën dotCloud, e cila ishte ndërtuar mbi më shumë se njëqind mikroshërbime dhe mbështeste mijëra aplikacione në kontejnerë. Do të shpjegoj problemet me të cilat u përballëm gjatë zhvillimit dhe lansimit të saj, dhe si rrjetet e shërbimeve mund të kishin ndihmuar (ose jo).
Historia e dotCloud
Më parë kam shkruar për historinë e dotCloud dhe zgjedhjen e arkitekturës për këtë platformë, por pak kam folur për nivelin rrjetor. Nëse nuk doni të zhytni në lexim në lidhje me dotCloud, ja përmbledhja: është një platformë si shërbim PaaS që lejon klientët të lançojnë një gamë të gjerë aplikacionesh (Java, PHP, Python...), me mbështetje për një gamë të gjerë shërbimesh të dhënash (MongoDB, MySQL, Redis...) dhe një proces punimi si Heroku: ju ngarkoni kodin tuaj në platformë, ajo ndërtuon imazhet e kontejnerëve dhe i hedh ato në punë.
Do të flas për mënyrat se si u drejtohej trafiku në platformën dotCloud. Jo sepse ishte ndonjë gjë veçanërisht e shkëlqyer (ndonëse për kohën e saj, sistemi funksiononte mirë!), por kryesisht sepse me ndihmën e mjeteve moderne, një ekip modest mund ta realizojë lehtësisht një dizajn të tillë brenda një kohe të shkurtër, nëse u nevojitet një mënyrë për të drejtuar trafikun midis një sërë mikroshërbimesh ose aplikacionesh. Kështu, mund të krahasohen mundësitë: çfarë ndodh nëse zhvilloni gjithçka vetë apo përdorni një shërbim ekzistues. Zgjedhja standarde: ta bëni vetë ose ta blini.
Drejtimi i trafikut për aplikacionet e hostuara
Aplikacionet në dotCloud mund të ofrojnë pika fundore HTTP dhe TCP.
Pikat fundore HTTP shtohen dinamikisht në konfigurimin e klasterëve të balancuesve të ngarkesës . Kjo duket si ajo që burimet e sotme bëjnë në Kubernetes dhe një balancues ngarkese si .
Klientët lidhen me pikët e përfundimtare HTTP përmes domeve përkatëse, nëse emri i domenit tregon për balancuesit e ngarkesës dotCloud. Asgjë e veçantë.
Pikat e përfundimtare TCP janë të lidhura me numrin e portit, i cili pastaj transmetohet të gjithë konteinerëve të këtij stoku përmes variablave të ambientit.
Klientët mund të lidhen me pikat e përfundimtare TCP, duke përdorur emrin përkatës të hostit (diçka si gateway-X.dotcloud.com) dhe numrin e portit.
Ky emër hosti zgjidhet në një grup serverash “nats“ (nuk ka lidhje me ), të cilët do të rregullojnë lidhjet e ardhshme TCP në konteinerin e duhur (ose, në rastin e shërbimeve me balancim ngarkese, në konteinerët e duhur).
Nëse jeni të njohur me Kubernetes, ndoshta kjo do t'ju kujtojë shërbimet .
Në platformën dotCloud nuk kishte ekuivalente të shërbimeve : për thjeshtësi, qasja në shërbime ishte e njëjtë si nga brenda ashtu edhe nga jashtë platformës.
Gjithçka ishte organizuar mjaft thjesht: implementimet fillestare të rrjeteve të routing HTTP dhe TCP, ndoshta vetëm disa qindra rreshta Python. Algoritmet e thjeshta (do të thosha naive) që u përmirësuan me rritjen e platformës dhe shfaqjen e kërkesave shtesë.
Një rishikim i gjerë i kodit ekzistues nuk ishte i nevojshëm. Për më tepër, mund të përdorin direkt adresën e marrë përmes variableve të mjedisit.
Çfarë e ndan këtë nga një mesh shërbimi modern?
I kufizuar i dukshmërisë. Ne nuk kishim asnjë metrikë për rrjetin e routing TCP. Sa i përket routing HTTP, versionet më të vona kishin metrika të detajuara HTTP me kode gabimi dhe kohë përgjigjeje, por mesh shërbesha moderne shkojnë edhe më tej, duke ofruar integrim me sisteme të mbledhjes së metrikës, si p.sh. Prometheus.
Dukshmëria është e rëndësishme jo vetëm nga një perspektivë operacionale (për të ndihmuar në zgjidhjen e problemeve), por edhe gjatë lëshimit të funksioneve të reja. Këtu flasim për dhe .
Efikasitetin e routing po ashtu është e kufizuar. Në rrjetin e-routing dotCloud, gjithë trafik duhet të kalojë përmes një klasteri të nodove të dedikuara për routing. Kjo nënkuptonte potencialin e kalimeve të shumta mes kufijve AZ (zona të disponueshmërisë) dhe një rritje të konsiderueshme të vonesës. Kujtoj si zgjidhja problemet me kodin që bënte më shumë se njëqind kërkesa SQL për çdo faqe dhe për çdo kërkesë hapte një lidhje të re me serverin SQL. Kur ekzekutohet lokal, faqja ngarkohet menjëherë, por në dotCloud ngarkohet për disa sekonda, sepse për çdo lidhje TCP (dhe kërkesë SQL të mëvonshme) nevojiten dhjetëra milisekonda. Në këtë rast të veçantë problemi u zgjidh nga lidhjet e përhershme.
Shërbimet e mesh-it moderne e menaxhojnë më mirë këto probleme. Së pari, ata kontrollojnë se lidhjet janë të routing në burim. Rryma logjike është e njëjtë: klienti → mesh → shërbim, por tani mesh funksionon lokal, jo në nodet e largëta, kështu që lidhja klienti → mesh është lokale dhe shumë e shpejtë (mikrosekonda në vend të milisekundave).
Shërbimet moderne të mesh-it gjithashtu realizojnë algoritem më të mençur të balancimit të ngarkesës. Duke kontrolluar funksionimin e backend-eve, ata mund të dërgojnë më shumë trafik në backend-e më të shpejtë, që çon në një përmirësim të përgjithshëm të performancës.
Siguria edhe më mirë. Rrjeti i routing dotCloud funksiononte plotësisht në EC2 Classic dhe nuk e enkriptoi trafikun (duke supozuar se nëse dikush e kishte vënë një sniffer në trafikun e rrjetit të EC2, ju tashmë keni probleme të mëdha). Shërbimet moderne të mesh-it mbrojnë në mënyrë transparente të gjithë trafikun tonë, për shembull, me autentikimin e TLS së ndërsjellë dhe më pas enkriptimin.
Routing i trafikut për shërbimet e platformës
Mirë, ne diskutuam për trafikun ndërmjet aplikacioneve, por çfarë me platformën vetë dotCloud?
Platforma e vetë përbëhej nga rreth njëqind mikroshërbimesh që përgjigjeshin për funksionalitete të ndryshme. Disa merrnin kërkesa nga të tjerët, ndërsa disa ishin punëtorë të prapavijës që lidhnin me shërbime të tjera, por vetë nuk merrnin lidhje. Në çdo rast, çdo shërbim duhet të dijë pikat përfundimtare të adresave për të cilat duhet të conectohet.
Shumë shërbime të nivelit të lartë mund të përdorin rrjetin e routing-ut të përshkruar më sipër. Në fakt, shumë nga më shumë se njëqind mikroshërbime dotCloud janë deploy-uar si aplikacione të zakonshme në vetë platformën dotCloud. Por një numër i vogël shërbimesh të nivelit të ulët (veçanërisht ato që implementojnë këtë rrjet routing-u) kishin nevojë për diçka më të thjeshtë, me varësi më të vogla (pasi për të funksionuar nuk mund të varen nga vetvetja — problemi i njohur i pulës dhe vezës).
Këto shërbime të ulëta, të rëndësishme u deploy-uan duke filluar kontejnerë drejtpërdrejt në disa nyje kyçe. Në këtë rast, shërbimet standarde të platformës nuk u angazhuan: kompozuesi, planifikuesi dhe runner-i. Nëse dëshironi të krahasoni me platforma moderne kontejnerësh, kjo është si të filloni një avion të menaxhimit me docker run drejtpërdrejt në nyjë, në vend që të delegoni detyrën në Kubernetes. Kjo është mjaft e ngjashme me konceptin e , të cilat përdor ose në ngarkimin e një klasteri autonom.
Këto shërbime u ekspozuan në një mënyrë të thjeshtë dhe të ashpër: emrat dhe adresat e tyre ishin të listuara në një skedar YAML; dhe çdo klient duhej të merrte një kopje të këtij skedari YAML për të bërë deploy.
Në një anë, kjo është jashtëzakonisht e besueshme, sepse nuk kërkon mbështetje nga një depo të jashtme për çelësa/vlera, siç është Zookeeper (mos harroni, atëherë nuk kishte etcd ose Consul). Në anën tjetër, kjo e vështirësonte lëvizjen e shërbimeve. Çdo herë që lëviznim, të gjithë klientët duhet të merrnin një skedar YAML të përditësuar (dhe potencialisht të rinisnin). Nuk është shumë e përshtatshme!
Më pas, filluam të ndërtonim një skemë të re, ku çdo klient lidhej me një server të lokal proxy. Në vend të adresës dhe portit, mjafton të dijë vetëm numrin e portit të shërbimit dhe të lidhet përmes localhost. Serveri lokal proxy menaxhon këtë lidhje dhe e drejton atë në serverin aktual. Tani, kur backend lëviz në një makinë tjetër ose kur shkalon, në vend të përditësimit të të gjithë klientëve, është e mjaftueshme të përditësohen vetëm këto serverë lokal proxy; dhe rinisja nuk është më e nevojshme.
(Gjithashtu ishte planifikuar që trafiku të inkorporohej në lidhjet TLS dhe të vendoset një server proxy tjetër në anën e pranimit, si dhe të verifikohen certifikatat TLS pa përfshirjen e shërbimit të pranuar, i cili është konfiguruar për pranim lidhjesh vetëm në localhost. Më vonë për këtë).
Kjo është shumë e ngjashme me nga Airbnb, por ndryshimi thelbësor është se SmartStack është realizuar dhe është vendosur në prodhim, ndërsa sistemi i brendshëm i routimit të dotCloud u hoq në sirtar, kur dotCloud u shndërrua në Docker.
Unë personalisht e mendoj SmartStack si një nga pararendësit e sistemeve si Istio, Linkerd dhe Consul Connect, sepse të gjitha ndjekin një model të njëjtë:
- Nisja e proxy-t në çdo nyje.
- Klinet lidhen me proxy-në.
- Plani i menaxhimit përditëson konfigurimin e serverit proxy në rast të ndryshimit të back-end-eve.
- … Fitim!
Implementimi modern i mesh-it të shërbimeve
Nëse na nevojitet të implementojmë një rrjet të ngjashëm sot, mund të përdorim parimet e ngjashme. Për shembull, të konfigurojmë një zonë të brendshme DNS, duke lidhur emrat e shërbimeve me adresat në hapësirën 127.0.0.0/8. Pastaj të nisim HAProxy në çdo nyje të klasterit, duke pranuar lidhje nga çdo adresë shërbimi (në këtë nënrrjetë 127.0.0.0/8) dhe redirekton/ балансирует ngarkesën në backendet përkatëse. Konfigurimi i HAProxy mund të menaxhohet , duke lejuar ruajtjen e informacionit mbi backend në etcd ose Consul dhe automatikisht të dërgojë konfiguromin e përditësuar në HAProxy, kur është e nevojshme.
Kështu funksionon Istio! Por me disa ndryshime:
- Përdor në vend të HAProxy.
- Ruani konfigurimin e backendit përmes Kubernetes API në vend të etcd ose Consul.
- Shërbimeve u ndahen adresat në subnetin e brendshëm (adresat Kubernetes ClusterIP) në vend të 127.0.0.0/8.
- Ka një komponent shtesë (Citadel) për të shtuar verifikimin e ndërsjellë të TLS midis klientit dhe serverëve.
- Mbështet funksione të reja si shkeqja e zinxhirëve (circuit breaking), gjurmimi i shpërndarë, vendosja e canarinave dhe të tjera.
Le të shqyrtojmë në mënyrë të shkurtër disa dallime.
Envoy Proxy
Envoy Proxy është shkruar nga kompania Lyft [konkurrenti Uber në tregun e taksive — shën. përkth.] Ai është shumë i ngjashëm me proxy të tjera (p.sh., HAProxy, Nginx, Traefik…), por Lyft e shkroi versionin e vet, sepse iu deshën funksione që mungonin në proxy të tjera, dhe dukej më e arsyeshme të bënte një të ri sesa të zgjaste ekzistuesin.
Envoy mund të përdoret vetë. Nëse kam një shërbim konkret që duhet të lidhet me shërbime të tjera, mund ta konfiguroj atë për t'u lidhur me Envoy, dhe pastaj ta konfiguroj dhe rikonfiguroj dinamik me vendndodhjet e shërbimeve të tjera, duke fituar shumë funksione shtesë të shkëlqyera, për shembull, në lidhje me monitorimin. Në vend të një biblioteke klienti të personalizuar ose implementimi të kodit të gjurmimit të thirrjeve, ne drejtojmë trafikun në Envoy, i cili mbledh metrikat për ne.
Por Envoy është gjithashtu në gjendje të punojë si shtresa e të dhënave (data plane) për mesh-in e shërbimeve. Kjo do të thotë se tani për këtë mesh shërbimesh, Envoy konfigurohet nga shtresa e menaxhimit (control plane).
Shtresa e menaxhimit
Në shtresën e menaxhimit, Istio mbështetet në Kubernetes API. Kjo nuk ndryshon shumë nga përdorimi i confd, i cili mbështetet në etcd ose Consul për të parë një grup çelesh në depo. Istio përmes Kubernetes API shikon një grup burimesh Kubernetes.
Ndërkohë: personalisht më duket e dobishme kjo , i cili thotë:
Serveri Kubernetes API është një "server i mençur" që ofron ruajtje, menaxhim versionesh, verifikim, përditësim dhe semantikë të burimeve API.
Istio është projektuar për t'u përdorur me Kubernetes; dhe nëse dëshironi ta përdorni atë jashtë Kubernetes, ju duhet të nisin një instancë të serverit Kubernetes API (dhe shërbimit të ndihmës etcd).
Adresat e shërbimeve
Istio mbështetet në adresat ClusterIP që jep Kubernetes, prandaj 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 të caktuar në klasterin Kubernetes pa Istio kapet nga kube-proxy dhe dërgohet në pjesën e serverit të këtij proxy. Nese jeni të interesuar për detajet teknike, kube-proxy vendos rregulla iptables (ose balancues IPVS, varësisht si është konfiguruar), për të riparë adresat e destinacionit të lidhjeve që kalojnë përmes adresës ClusterIP.
Pasi të jetë instaluar Istio në klasterin Kubernetes, asgjë nuk ndryshon derisa të përfshihet shprehimisht për këtë konsumator ose madje për të gjithë hapësirën emri, përmes introduktimit të kontejnerit sidecar në pod të personalizuara. Ky kontejner do të nisë një instancë të Envoy dhe do të vendosë një sërë rregullash iptables për të kapur trafikun që shkon në shërbime të tjera dhe për ta drejtuar atë trafik në Envoy.
Kur integrohet me DNS-në e Kubernetes, kjo do të thotë që kodi ynë mund të lidhet me emrin e shërbimit, dhe gjithçka "thjesht funksionon". Në fjalë të tjera, kodi ynë lëshon kërkesa të tipit http://api/v1/users/4242, atëherë api rezolon kërkesën në 10.97.105.48, rregullat iptables kapin lidhjet me 10.97.105.48 dhe i ridrejtova ato në proxy-në lokale të Envoy, dhe kjo proxy lokale do ta drejtojë kërkesën në backend-in real të API-t. Uf!
Shtesa të tjera
Istio gjithashtu ofron enkriptim dhe autentikim end-to-end përmes mTLS (TLS të ndërsjellë). Kjo arrihet nga një komponent i quajtur Citadel.
Ka gjithashtu një komponent Mixer, të cilin Envoy mund ta kërkojë për çdo kërkesë, për të marrë një vendim të veçantë për këtë kërkesë në varësi të faktorëve të ndryshëm, siç janë headërat, ngarkesa e backend-it etj... (mos u shqetësoni: ka shumë mjete për të siguruar funksionalitetin e Mixer, dhe madje edhe nëse ai dështon, Envoy do të vazhdojë të funksionojë si proxy).
Dhe, sigurisht, përmendëm gjithashtu transparencën: Envoy mbledh një sasi të madhe metrikash, duke siguruar në të njëjtën kohë ndjekjen e distribuara. Në arkitekturën e mikrosherbimeve, nëse një kërkesë API duhet të kalojë nëpër mikrosherbimet A, B, C dhe D, atëherë kur hyn në sistem, ndjekja e distribuara do të shtojë një identifikues unik në kërkesë dhe do ta ruajë këtë identifikues përmes nëntë kërkesave tek të gjitha këto mikrosherbime, duke lejuar regjistrimin e të gjitha thirrjeve të lidhura, vonesave të tyre, etj.
Zhvilloni ose blini
Istio ka një reputacion si një sistem i komplikuar. Nga ana tjetër, ndërtimi i një rrjeti ruter që e përshkrova në fillim të këtij postimi është relativisht i thjeshtë me mjetet ekzistuese. Pra, a ka ndonjëKuptim që të krijoni një shërbim të përshtatshëm në vend të tij?
Nëse kemi nevoja modeste (nuk na nevojitet transparenca, prishësi i zinxhirit dhe nuanca të tjera), mendimet për zhvillimin e një instrumenti të vetë janë të pranishme. Por nëse përdorim Kubernetes, mund të mos na nevojitet as, sepse Kubernetes tashmë ofron mjetet bazë për zbulimin e shërbimeve dhe balancimin e ngarkesës.
Por këdo që ka kërkesa të avancuara, blerja e një shërbimi mesh duket si opsioni më i mirë. (Nuk është gjithmonë në të vërtetë "blerje", pasi Istio ofrohet me burim të hapur, por na nevojitet ende të investojmë në kohën e inxhinierisë për ta kuptuar, për ta vendosur dhe menaxhuar atë).
Çfarë të zgjidhni: Istio, Linkerd apo Consul Connect?
Derisa kemi folur vetëm për Istio, kjo nuk është e vetmja shërbim mesh. Një alternativë e njohur është , dhe ka gjithashtu .
Çfarë të zgjidhni?
Sinqerisht, nuk e di. Në këtë moment, nuk e konsideroj veten mjaft kompetent për të përgjigjur këtë pyetje. Ka disa me krahasimin e këtyre mjeteve dhe madje .
Një nga qasjet më premtuese është të përdorim një mjet si . Ai implementon një shtresë abstraksioni për të thjeshtuar dhe unifikuar API-të e ofruara nga meshat e shërbimeve. Në vend që të mësojmë API-të specifike (dhe, sipas mendimit tim, relativisht të ndërlikuara) të meshave të ndryshme të shërbimeve, ne mund të përdorim struktura më të thjeshta SuperGloo — dhe të kalojmë lehtë nga njëra në tjetrën, sikur të kishim një format ndërmjetës konfigurimi, që përshkruan ndërfaqet HTTP dhe backend-et, në gjendje të gjenerojë konfigurimin aktual për Nginx, HAProxy, Traefik, Apache…
Kam bërë pak eksperimente me Istio dhe SuperGloo, dhe në artikullin e ardhshëm dua të tregoj si të shtoj Istio ose Linkerd në një klaster ekzistues duke përdorur SuperGloo dhe se sa mirë do ta bëjë këtë, domethënë, të na lejojë të kalojmë nga një shërbim-mesh në tjetrin pa kaluar nëpër konfigurime të reja.
Burimi: habr.com
