Kontejneri, mikroservise i servisne mreže

Na internetu gomilu članci о servisna mreža (servisna mreža), a evo još jednog. Ura! Ali zašto? Zatim, želim izraziti svoje mišljenje da bi bilo bolje da su se servisne mreže pojavile prije 10 godina, prije pojave kontejnerskih platformi kao što su Docker i Kubernetes. Ne kažem da je moje gledište bolje ili lošije od drugih, ali pošto su servisne mreže prilično složene životinje, višestruka gledišta će pomoći da ih bolje razumijemo.

Govoriću o dotCloud platformi, koja je izgrađena na preko stotinu mikroservisa i podržava hiljade kontejnerskih aplikacija. Objasnit ću izazove s kojima smo se suočili prilikom njegovog razvoja i pokretanja, i kako bi servisne mreže mogle (ili nisu mogle) pomoći.

Istorija dotCloud-a

Pisao sam o istoriji dotCloud-a i izboru arhitekture za ovu platformu, ali nisam mnogo govorio o mrežnom sloju. Ako ne želite da uronite u čitanje zadnji članak o dotCloud-u, evo suštine ukratko: to je PaaS platforma-kao-usluga koja omogućava korisnicima pokretanje širokog spektra aplikacija (Java, PHP, Python...), uz podršku za širok spektar podataka usluge (MongoDB, MySQL, Redis...) i radni tok kao što je Heroku: Učitavate svoj kod na platformu, on gradi slike kontejnera i postavlja ih.

Reći ću vam kako je promet usmjeren na dotCloud platformu. Ne zato što je bio posebno cool (iako je sistem dobro funkcionisao za svoje vrijeme!), već prvenstveno zato što uz moderne alate takav dizajn može lako implementirati skroman tim za kratko vrijeme ako im je potreban način da usmjere promet između gomile mikroservisa ili gomile aplikacija. Na ovaj način možete uporediti opcije: šta će se dogoditi ako sve sami razvijete ili koristite postojeću servisnu mrežu. Standardni izbor je da ga napravite sami ili da ga kupite.

Usmjeravanje saobraćaja za hostovane aplikacije

Aplikacije na dotCloud-u mogu otkriti HTTP i TCP krajnje tačke.

HTTP krajnje tačke dinamički dodano u konfiguraciju klastera balansiranja opterećenja Hipache. Ovo je slično onome što resursi rade danas Ulaz u Kubernetesu i balanseru opterećenja poput Traefik.

Klijenti se povezuju na HTTP krajnje tačke preko odgovarajućih domena, pod uslovom da ime domene ukazuje na dotCloud balansere opterećenja. Ništa posebno.

TCP krajnje tačke povezan sa brojem porta, koji se zatim prosleđuje svim kontejnerima u tom steku preko varijabli okruženja.

Klijenti se mogu povezati na TCP krajnje tačke koristeći odgovarajuće ime hosta (nešto poput gateway-X.dotcloud.com) i broj porta.

Ovo ime hosta se rješava u klaster servera „nats“ (nije povezano sa NATS), koji će usmjeriti dolazne TCP veze u ispravan kontejner (ili, u slučaju usluga izbalansiranih opterećenja, u ispravne kontejnere).

Ako ste upoznati sa Kubernetesom, ovo će vas vjerovatno podsjetiti na usluge NodePort.

Nije bilo ekvivalentnih usluga na dotCloud platformi ClusterIP: Radi jednostavnosti, uslugama se pristupalo na isti način i iznutra i izvan platforme.

Sve je bilo organizovano prilično jednostavno: početne implementacije HTTP i TCP mreža za rutiranje su verovatno bile samo nekoliko stotina linija Pythona svaka. Jednostavni (rekao bih naivni) algoritmi koji su se usavršavali kako je platforma rasla i pojavili su se dodatni zahtjevi.

Nije bilo potrebno opsežno refaktoriranje postojećeg koda. posebno, 12 faktorskih aplikacija može direktno koristiti adresu dobijenu preko varijabli okruženja.

Po čemu se ovo razlikuje od moderne servisne mreže?

Ograničeno vidljivost. Uopšte nismo imali nikakve metrike za TCP mrežu rutiranja. Kada je u pitanju HTTP rutiranje, kasnije verzije uvele su detaljne HTTP metrike sa kodovima grešaka i vremenom odgovora, ali moderne mreže usluga idu još dalje, pružajući integraciju sa sistemima za prikupljanje metrika kao što je Prometheus, na primjer.

Vidljivost je važna ne samo iz operativne perspektive (kako bi se riješili problemi), već i prilikom objavljivanja novih funkcija. Radi se o sigurnom plavo-zeleno raspoređivanje и kanarinac raspoređivanje.

Efikasnost rutiranja takođe je ograničen. U dotCloud mreži rutiranja, sav promet je morao proći kroz klaster namjenskih čvorova za usmjeravanje. To je značilo potencijalno prelazak višestrukih granica AZ (Zona dostupnosti) i značajno povećanje latencije. Sjećam se koda za rješavanje problema koji je pravio preko stotinu SQL upita po stranici i otvarao novu vezu sa SQL serverom za svaki upit. Kada se pokreće lokalno, stranica se učitava trenutno, ali u dotCloud-u je potrebno nekoliko sekundi da se učita jer svaka TCP veza (i kasniji SQL upit) traje desetine milisekundi. U ovom konkretnom slučaju, uporne veze su riješile problem.

Moderne servisne mreže bolje se nose s takvim problemima. Prije svega, provjeravaju da li su veze rutirane u izvoru. Logički tok je isti: клиент → меш → сервис, ali sada mreža radi lokalno, a ne na udaljenim čvorovima, tako da je veza клиент → меш je lokalna i vrlo brza (mikrosekunde umjesto milisekundi).

Moderne servisne mreže također implementiraju pametnije algoritme za balansiranje opterećenja. Praćenjem zdravlja backend-a, oni mogu poslati više prometa bržim backendovima, što rezultira poboljšanim ukupnim performansama.

Sigurnost bolje takođe. DotCloud mreža usmjeravanja je u potpunosti radila na EC2 Classic i nije šifrirala promet (na osnovu pretpostavke da ako je neko uspio staviti njuškalo na EC2 mrežni promet, već ste bili u velikoj nevolji). Moderne servisne mreže transparentno štite sav naš promet, na primjer, uz međusobnu TLS autentifikaciju i naknadnu enkripciju.

Usmjeravanje prometa za usluge platforme

U redu, razgovarali smo o saobraćaju između aplikacija, ali šta je sa samom dotCloud platformom?

Sama platforma se sastojala od stotinjak mikroservisa odgovornih za različite funkcije. Neki su prihvatili zahtjeve drugih, a neki su bili pozadinski radnici koji su se povezivali s drugim servisima, ali nisu sami prihvatili veze. U svakom slučaju, svaka usluga mora znati krajnje tačke adresa na koje treba da se poveže.

Mnoge usluge visokog nivoa mogu koristiti gore opisanu mrežu usmjeravanja. U stvari, mnoge od više od stotinu mikroservisa dotCloud-a su raspoređene kao redovne aplikacije na samoj dotCloud platformi. Ali malom broju servisa niskog nivoa (posebno onih koji implementiraju ovu mrežu rutiranja) bilo je potrebno nešto jednostavnije, sa manje zavisnosti (pošto nisu mogli zavisiti od sebe da rade - stari dobri problem kokoške i jaja).

Ove usluge niskog nivoa, kritične za misiju, bile su raspoređene pokretanjem kontejnera direktno na nekoliko ključnih čvorova. U ovom slučaju nisu korištene standardne platformske usluge: linker, planer i runner. Ako želite da se uporedite sa modernim kontejnerskim platformama, to je kao da pokrećete kontrolni plan docker run direktno na čvorove, umjesto delegiranja zadatka na Kubernetes. Prilično je sličan konceptu statički moduli (podi), koji koristi kubeadm ili bootkube prilikom pokretanja samostalnog klastera.

Ovi servisi su izloženi na jednostavan i grub način: YAML fajl je naveo njihova imena i adrese; i svaki klijent je morao uzeti kopiju ove YAML datoteke za implementaciju.

S jedne strane, izuzetno je pouzdan jer ne zahtijeva podršku eksternog skladišta ključeva/vrijednosti kao što je Zookeeper (zapamtite, etcd ili Consul u to vrijeme nisu postojali). S druge strane, to je otežavalo premještanje usluga. Svaki put kada se napravi potez, svi klijenti bi dobili ažurirani YAML fajl (i potencijalno ponovno pokretanje). Nije baš udobno!

Nakon toga, počeli smo implementirati novu šemu, gdje se svaki klijent povezao na lokalni proxy server. Umjesto adrese i porta, potrebno je samo znati broj porta servisa i povezati se putem localhost. Lokalni proxy upravlja ovom vezom i prosljeđuje je stvarnom serveru. Sada, kada premještate pozadinu na drugu mašinu ili skalirate, umjesto da ažurirate sve klijente, trebate samo ažurirati sve ove lokalne proksije; i ponovno pokretanje više nije potrebno.

(Također je planirano da se inkapsulira promet u TLS konekcijama i stavi drugi proxy server na stranu primaoca, kao i da se verificiraju TLS certifikati bez sudjelovanja servisa primaoca, koji je konfiguriran da prihvata veze samo na localhost. Više o tome kasnije).

Ovo je vrlo slično SmartStack od Airbnb-a, ali značajna razlika je u tome što je SmartStack implementiran i raspoređen u proizvodnju, dok je dotCloud-ov interni sistem rutiranja odbačen kada je dotCloud postao Docker.

Ja lično smatram da je SmartStack jedan od prethodnika sistema kao što su Istio, Linkerd i Consul Connect jer svi slijede isti obrazac:

  • Pokrenite proxy na svakom čvoru.
  • Klijenti se povezuju na proxy.
  • Kontrolna ravan ažurira proxy konfiguraciju kada se pozadinska strana promijeni.
  • ... Profit!

Moderna implementacija servisne mreže

Ako bismo danas trebali implementirati sličnu mrežu, mogli bismo koristiti slične principe. Na primjer, konfigurirajte internu DNS zonu mapiranjem naziva usluga u adrese u prostoru 127.0.0.0/8. Zatim pokrenite HAProxy na svakom čvoru u klasteru, prihvatajući veze na svakoj adresi usluge (u toj podmreži 127.0.0.0/8) i preusmjeravanje/balansiranje opterećenja na odgovarajuće pozadine. HAProxy konfiguracija se može kontrolirati confd, omogućavajući vam da pohranite pozadinske informacije u etcd ili Consul i automatski prebacite ažuriranu konfiguraciju na HAProxy kada je to potrebno.

Ovo je otprilike način na koji Istio radi! Ali uz neke razlike:

  • Koristi Proxy izaslanik umjesto HAProxy.
  • Čuva pozadinsku konfiguraciju preko Kubernetes API-ja umjesto etcd-a ili Consul-a.
  • Servisima se dodeljuju adrese na internoj podmreži (IP adrese Kubernetes klastera) umesto 127.0.0.0/8.
  • Ima dodatnu komponentu (Citadel) za dodavanje međusobne TLS autentifikacije između klijenta i servera.
  • Podržava nove funkcije kao što su prekid strujnog kola, distribuirano praćenje, postavljanje kanarinca, itd.

Pogledajmo na brzinu neke od razlika.

Proxy izaslanik

Envoy Proxy je napisao Lyft [Uberov konkurent na tržištu taksija - cca. lane]. Po mnogo čemu je sličan drugim proksijima (npr. HAProxy, Nginx, Traefik...), ali Lyft je napisao njihov jer su im bile potrebne karakteristike koje su nedostajale drugim proksijima, i činilo se da je pametnije napraviti novi, a ne proširiti postojeći.

Envoy se može koristiti samostalno. Ako imam određenu uslugu koja se treba povezati s drugim uslugama, mogu je konfigurirati da se poveže s Envoy-om, a zatim dinamički konfigurirati i rekonfigurirati Envoy s lokacijom drugih usluga, dok dobijem puno sjajnih dodatnih funkcionalnosti, kao što je vidljivost. Umjesto prilagođene klijentske biblioteke ili ubacivanja tragova poziva u kod, šaljemo promet u Envoy, a on prikuplja metriku za nas.

Ali Envoy je takođe sposoban da radi kao data plane (ravan podataka) za servisnu mrežu. To znači da je Envoy sada konfiguriran za ovu servisnu mrežu kontrolni avion (kontrolna ravnina).

Kontrolni avion

Za kontrolnu ravan, Istio se oslanja na Kubernetes API. Ovo se ne razlikuje mnogo od korištenja confd-a, koji se oslanja na etcd ili Consul za pregled skupa ključeva u skladištu podataka. Istio koristi Kubernetes API za pregled skupa Kubernetes resursa.

Između ovoga i tada: Lično sam ovo smatrao korisnim Kubernetes API opiskoji glasi:

Kubernetes API server je „glupi server“ koji nudi skladištenje, verzionisanje, validaciju, ažuriranje i semantiku za API resurse.

Istio je dizajniran za rad sa Kubernetesom; a ako želite da ga koristite izvan Kubernetesa, onda morate pokrenuti instancu Kubernetes API servera (i etcd helper service).

Servisne adrese

Istio se oslanja na ClusterIP adrese koje Kubernetes dodeljuje, tako da Istio usluge dobijaju internu adresu (nije u opsegu 127.0.0.0/8).

Saobraćaj do ClusterIP adrese za određenu uslugu u Kubernetes klasteru bez Istio-a presreće kube-proxy i šalje se na pozadinu tog proxyja. Ako vas zanimaju tehnički detalji, kube-proxy postavlja iptables pravila (ili IPVS balansere opterećenja, ovisno o tome kako je konfigurisan) da prepiše odredišne ​​IP adrese veza koje idu na ClusterIP adresu.

Jednom kada se Istio instalira na Kubernetes klaster, ništa se ne mijenja dok se izričito ne omogući za datog potrošača, ili čak za cijeli imenski prostor, uvođenjem kontejnera sidecar u prilagođene mahune. Ovaj kontejner će pokrenuti instancu Envoy-a i postaviti skup iptables pravila za presretanje saobraćaja koji ide na druge servise i preusmjeriti taj promet na Envoy.

Kada je integrisan sa Kubernetes DNS-om, to znači da se naš kod može povezati prema nazivu usluge i sve „jednostavno radi“. Drugim riječima, naš kod izdaje upite poput http://api/v1/users/4242onda api riješiti zahtjev za 10.97.105.48, iptables pravila će presresti veze od 10.97.105.48 i proslijediti ih lokalnom proxy poslužitelju Envoy, a taj lokalni proxy će proslijediti zahtjev stvarnom backend API-ju. Phew!

Dodatni ukrasi

Istio također pruža end-to-end enkripciju i autentifikaciju putem mTLS-a (mutual TLS). Komponenta pod nazivom citadela.

Tu je i komponenta Mikser, što Izaslanik može zatražiti svake od njih zahtjev za donošenje posebne odluke o tom zahtjevu u zavisnosti od različitih faktora kao što su zaglavlja, pozadinsko opterećenje, itd... (ne brinite: postoji mnogo načina da Mixer nastavi raditi, pa čak i ako se sruši, Envoy će nastaviti raditi u redu kao punomoćnik).

I, naravno, spomenuli smo vidljivost: Envoy prikuplja ogromnu količinu metrike dok pruža distribuirano praćenje. U arhitekturi mikroservisa, ako jedan API zahtjev mora proći kroz mikroservise A, B, C i D, tada će po prijavi distribuirano praćenje dodati jedinstveni identifikator zahtjevu i pohraniti ovaj identifikator kroz podzahtjeve za sve ove mikroservise, omogućavajući svi povezani pozivi koji se snimaju, kašnjenja, itd.

Razvijte ili kupite

Istio ima reputaciju da je kompleksan. Nasuprot tome, izgradnja mreže za usmjeravanje koju sam opisao na početku ovog posta je relativno jednostavna korištenjem postojećih alata. Dakle, ima li smisla umjesto toga kreirati vlastitu servisnu mrežu?

Ako imamo skromne potrebe (ne trebamo vidljivost, prekidač i druge suptilnosti), onda dolaze misli na razvoj vlastitog alata. Ali ako koristimo Kubernetes, možda neće biti ni potreban jer Kubernetes već nudi osnovne alate za otkrivanje usluga i balansiranje opterećenja.

Ali ako imamo napredne zahtjeve, onda se čini da je “kupovina” servisne mreže mnogo bolja opcija. (Ovo nije uvijek "kupovina" jer je Istio open source, ali još uvijek moramo uložiti inženjersko vrijeme da ga razumijemo, implementiramo i upravljamo njime.)

Da li da izaberem Istio, Linkerd ili Consul Connect?

Do sada smo govorili samo o Istio-u, ali ovo nije jedina servisna mreža. Popularna alternativa - Linkerd, i ima još toga Consul Connect.

Šta birati?

Iskreno, ne znam. Trenutno se ne smatram dovoljno kompetentnim da odgovorim na ovo pitanje. Ima ih nekoliko zanimljivo članci uz poređenje ovih alata i čak mjerila.

Jedan obećavajući pristup je korištenje alata kao što je SuperGloo. Implementira sloj apstrakcije da pojednostavi i objedini API-je izložene servisnim mrežama. Umjesto da učimo specifične (i, po mom mišljenju, relativno složene) API-je različitih servisnih mreža, možemo koristiti jednostavnije konstrukcije SuperGloo-a - i lako se prebacivati ​​s jedne na drugu, kao da imamo srednji konfiguracijski format koji opisuje HTTP sučelja i pozadinske mreže sposobne generiranja stvarne konfiguracije za Nginx, HAProxy, Traefik, Apache...

Malo sam se bavio Istiom i SuperGlooom, au sljedećem članku želim pokazati kako dodati Istio ili Linkerd u postojeći klaster koristeći SuperGloo, i kako ovaj drugi obavlja posao, odnosno omogućava vam da pređete sa jedna servisna mreža u drugu bez prepisivanja konfiguracija.

izvor: www.habr.com

Dodajte komentar