Interneti (service mesh), ja siin on veel üks. Hurraa! Aga miks? Sest ma tahan väljendada oma arvamust, et oleks olnud parem, kui teenuse-võrgud oleksid ilmunud 10 aastat tagasi, enne konteinerite platvormide nagu Docker ja Kubernetes tulekut. Ma ei väida, et minu arvamus on parem või halvem kui teised, kuid kuna teenuse-võrgud on üsna keerulised loomad, aitab erinevate vaatenurkade mitmekesisus neid paremini mõista.
Räägin dotCloud platvormist, mis ehitati enam kui sajast mikroteenusest ja toetas tuhandeid rakendusi konteinerites. Selgitan, milliste probleemidega me silmitsi seisisime selle arendamisel ja käivitamisel, ja kuidas teenuse-võrgud oleksid võinud aidata (või mitte).
dotCloudi ajalugu
Olen juba kirjutanud dotCloudi ajaloost ja selle platvormi arhitektuuri valimisest, kuid vähe olen rääkinud võrgukihtidest. Kui te ei soovi süveneda lugemisse dotCloudist lühidalt: see on platvormi teenus (PaaS), mis võimaldab klientidel käitada laia valikut rakendusi (Java, PHP, Python...), toetades mitmesuguseid andmete teenuseid (MongoDB, MySQL, Redis...) ning töövoogu nagu Heroku: laadite oma koodi platvormile, see loob konteinerite pildid ja rakendab need.
Räägin, kuidas suunati liiklust dotCloudi platvormile. Mitte sellepärast, et see oleks olnud eriti hea (kuigi oma aja kohta töötas süsteem hästi!), vaid eelkõige seetõttu, et tänapäevaste tööriistade abil võib sellise disaini kiiresti teostada väike meeskond, kui neil on vajalik liikluse suunamise meetod mitmete mikroteenuste või rakenduste vahel. Seega võib võrrelda valikuid: mis juhtub, kui kõik ise välja töötada või kasutada olemasolevat teenuse meetodit. Tavaline valik: teha ise või osta.
Liikluse suunamine hostitud rakendustele
dotCloudis töötavad rakendused saavad pakkuda HTTP ja TCP lõpp-punkte.
HTTP lõpp-punktid lisatakse dünaamiliselt koormuse tasakaalusüsteemi konfiguratsiooni . See on sarnane sellele, mida täna teevad ressursid Kuberneteses ja koormuse tasakaalustaja nagu .
Kliendid ühinevad HTTP-lõpp-punktidega vastavate domeenide kaudu, tingimusel et domeeninimi osutab dotCloud'i koormuse tasakaalustajatele. Pole midagi erilist.
TCP-lõpp-punktid on seotud sadamanumbriga, mis edastatakse seejärel kõigile selle stack'i konteineritele keskkonnamuutujate kaudu.
Kliendid saavad ühineda TCP-lõpp-punktidega, kasutades vastavat hosti (midagi nagu gateway-X.dotcloud.com) ja sadamanumbrit.
See hosti nimi lahendatakse “nats“ serverite klastriks (ei ole seotud ), mis suunavad sissetulevad TCP-ühendused õigesse konteinerisse (või, tasakaalustamise korral, õigesse konteinerite gruppi).
Kui olete Kubernetesega tuttav, siis tõenäoliselt meenutab see teile teenuseid .
dotCloud platvormil ei olnud teenuste ekvivalenti : lihtsuse huvides toimus juurdepääs teenustele võrdselt nii seest kui väljast platvormile.
Kõik oli korraldatud piisavalt lihtsalt: algsed HTTP- ja TCP-routing-implementatsioonid, tõenäoliselt vaid paar sada rida Pythonis. Lihtsad (ütleksin, et naiivsed) algoritmid, mida toodi uuendades ja platvormi kasvades, koos uute nõudmistega.
Olemasoleva koodi ulatuslik refaktoreerimine ei olnud vajalik. Konkreetsemalt, võivad otse kasutada aadressi, mis on saadud keskkonnamuutujate kaudu.
Kuidas see erineb tänapäevasest teenuste mõõdust?
Piiratud ülevaatus. Meil polnud üldse mingeid mõõdikuid TCP routing-ile. Mis puutub HTTP routing-isse, siis hilisemates versioonides ilmusid detailsemad HTTP mõõdikud koos veakoodide ja reageerimise ajaga, kuid kaasaegsed teenuste mõõdud lähevad veel kaugemale, pakkudes integreerimist mõõdikumise kogumissüsteemidega, nagu Prometheus, näiteks.
Ülevaatus on oluline mitte ainult operatiivses mõttes (et aidata probleemide lahendamisel), vaid ka uute funktsioonide väljalaskmisel. Jutt on ohutust ja .
Routing efektiivsus on ka piiratud. dotCloud'i marsruutimisvõrgus pidi kogu liiklus minema läbi pühendatud marsruutimistõlgete klastri. See tähendas, et potentsiaalselt voolas see üle mitme AZ (saadavuse tsoon) piiri ja põhjustas märkimisväärse viivituse. Mäletan, et lahendasin probleeme koodiga, mis tegi üle saja SQL-päringu lehe jaoks ja avas iga päringu jaoks uue ühenduse SQL-serveriga. Kohalikus käivitamises laadib leht kohe, kuid dotCloud’is võtab laadimine mitu sekundit, sest iga TCP-ühenduse (ja sellele järgnenud SQL-päringu) jaoks kulub kümneid millisekunde. Antud juhul lahendati probleem püsivate ühendustega.
Kaasaegsed teenuste mesh'id tegelevad paremini selliste probleemidega. Esiteks kontrollivad nad, et ühendused marsruutivad allikast. Loogiline voog on sama: klient → mesh → teenus, aga nüüd töötab mesh lokaalselt, mitte kaugetes sõlmedes, seega on ühendus klient → mesh kohalik ja väga kiire (mikrosekundid, mitte millisekundid).
Tänapäeva teenusevõrgud rakendavad ka nutikamaid koormuse jaotamise algoritme. Kontrollides tagapasuste töökorrasolekut, saavad nad suunata rohkem liiklust kiirematele tagapasustele, mis tõstab üldist jõudlust.
Ohutus ka paremini. dotCloudi marsruutimisvõrk töötas täielikult EC2 Classicul ja ei krüpteerinud liiklust (eeldades, et kui kellelgi õnnestus paigaldada sniffer EC2 võrgu liikluse peale, on teil juba tõsised probleemid). Tänapäeva teenusevõrgud kaitsevad kogu meie liiklust läbipaistvalt, näiteks vastastikuse TLS-autentimise ja sellele järgnevate krüpteerimiste abil.
Teenuseliidese liikluse marsruutimine
Nüüd, kui oleme arutanud liiklust rakenduste vahel, mis on olukord dotCloudi endaga?
Isegi platvorm koosnes umbes sajast mikroteenusest, mis vastutasid erinevate funktsioonide eest. Üks teenus võttis vastu päringuid teistelt, samas kui mõned olid taustatöötajad, mis ühendusid teiste teenustega, kuid ei võtnud ise ühendusi vastu. Igatahes peab iga teenus teadma nende aadresside lõpp-punktide kohta, millega ühendust võtta.
Paljude kõrgtehnoloogiliste teenuste puhul saab kasutada ülaltoodud suunamisvõrku. Tegelikult on enam kui sada dotCloudi mikroteenust välja pandud tavapäraste rakendustena dotCloudi platvormil. Kuid väike hulk madala taseme teenuseid (eriti need, mis rakendavad seda suunamisvõrku) vajas midagi lihtsamat, väiksemate sõltuvustega (kuna nad ei tohtinud sõltuda iseendast — vana hea kana ja muna probleem).
Need madala taseme, olulised teenused korraldati konteinerite käivitamise kaudu otse mitmetel peamistel sõlmedel. Sel juhul ei kaasatud platvormi standardteenuseid: koostaja, ajakava ja tööde teostaja. Kui soovite võrrelda kaasaegsete konteinerite platvormidega, sarnaneb see juhtimisplaani käivitamisega docker run otseselt sõlmedes, selle asemel et delegeerida ülesannet Kubernetesile. See sarnaneb rohkem mõistega , mida kasutab või iseseisva klastrite käivitamisel.
Need teenused eksponeeriti lihtsal ja toorel viisil: YAML-failis loetleti nende nimed ja aadressid; iga klient pidi reklaamimiseks võtma koopia sellest YAML-failist.
Esiteks, see on äärmiselt usaldusväärne, kuna see ei nõua välist võtme/väärtuse salvestust, nagu Zookeeper (ärge unustage, et sellel ajal ei olnud veel olemas etcd ega Consul). Teisest küljest, see raskendas teenuste liigutamist. Iga kord, kui teenused liiguti, pidid kõik kliendid saama värskendatud YAML-faili (ja potentsiaalselt taaskäivituma). See pole just mugav!
Hiljem hakkasime rakendama uut skeemi, kus iga klient ühendas end kohaliku proksiserveriga. Aadressi ja pordi asemel piisab tal teada vaid teenuse pordinumbrit ja ühendada läbi localhost. Kohalik proksiserver haldab seda ühendust ja suunab selle tegelikule serverile. Nüüd, kui taustal liigutatakse teisele masinale või skaleeritakse, ei pea kõik kliendid värskendama; piisab vaid nende kohalike prokside värskendamisest ning taaskäivitamine ei ole enam vajalik.
(Samuti oli plaanis kapseldada liiklus TLS-ühendustes ja paigaldada veel üks vahejaam vastuvõtupoolele ning kontrollida TLS-sertifikaate ilma vastuvõtuteenuse osalusel, mis on seadistatud ühenduste vastuvõtmiseks ainult localhost. Sellest rohkem hiljem).
See meenutab väga Airbnb-st, kuid oluline erinevus seisneb selles, et SmartStack on ellu viidud ja juurutatud tootmisse, samas kui dotCloudi sisemine marsruutimissüsteem pandi kasti, kui dotCloud muutus Dockeriks.
Arvan, et SmartStack on üks eelkäijaid selliste süsteemide nagu Istio, Linkerd ja Consul Connect puhul, kuna kõik need järgivad ühte mustrit:
- Vahejaama käitamine igas sõlmes.
- Kliendid ühenduvad vahejaamaga.
- Halduskiht värskendab vahejaama konfiguratsiooni, kui backendid muutuvad.
- … Kasum!
Kaasaegne teenuste võrgustiku rakendus
Kui me peame sarnast võrku tänapäeval rakendama, siis saame kasutada sarnaseid põhimõtteid. Näiteks seadistada sise-DNS tsoon, seostades teenuste nimed aadressidega selles ruumis 127.0.0.0/8. Siis käivitame HAProxy igas klastrisõlmes, võttes ühendusi iga teenuse aadressil (selles alamvõrkus 127.0.0.0/8) ja suunates/jaotades koormust vastavatele tagasüsteemidele. HAProxy konfiguratsiooni saab hallata , võimaldades salvestada teavet tagasüsteemi kohta etcd-s või Consulis ning automaatselt edastada uuendatud konfiguratsiooni HAProxy-le, kui see on vajalik.
Nii töötab ligikaudu Istio! Kuid mõningate eranditega:
- Kasutab asemel HAProxy.
- Salvestab tagasüsteemi konfiguratsiooni Kubernetes API kaudu, mitte etcd-s või Consulis.
- Teenustele antakse aadresse sisevõrgus (Kubernetes ClusterIP aadressid) asemel 127.0.0.0/8.
- Omab täiendavat komponenti (Citadel), et lisada TLS vastastikune autentimine kliendi ja serverite vahel.
- Toetab uusi funktsioone, nagu ahelakatkestus (circuit breaking), jaotatud jälgimine, kanarikujunduse juurutamine jne.
Vaadakem lühidalt üle mõned erinevused.
Envoy Proxy
Envoy Proxy on kirjutanud ettevõte Lyft [Uberi konkurent taksiturul - tõlkija märkus]. See on suuresti sarnane teistele proksidele (nt HAProxy, Nginx, Traefik...), kuid Lyft kirjutas selle, kuna neil olid vajalikud funktsioonid, mida teistes proksides ei olnud, ja tundus mõistlikum teha uus, kui olemasolevat laiendada.
Envoy't saab kasutada iseseisvalt. Kui mul on konkreetne teenus, mis peab ühenduma teiste teenustega, võin selle seadistada Envoy'ga ühendust võtma ning seejärel dünaamiliselt konfigureerida ja ümber konfigureerida Envoy'd, et hõlbustada teiste teenuste asukoha haldamist, saades samal ajal palju suurepäraseid lisafunktsioone, näiteks paremat jälgimist. Kohandatud kliendiraamatukogu või kutsumise jälgimise koodi integreerimise asemel suuname liikluse Envoy'sse, mis kogub meie jaoks mõõdikuid.
Kuid Envoy on samuti võimeline toimima andmeplaanina (data plane) teenuse mesh'i jaoks. See tähendab, et nüüd konfigureeritakse Envoy antud teenuse mesh'i jaoks kontrollplaanina (control plane).
Kontrollplaan
Kontrollplaanis toetub Istio Kubernetes API-le. See ei erine kuigi palju confd'i kasutamisest, mis toetub etcd või Consulile, et vaadata andmehõive võtmete kogumit. Istio vaatab Kubernetes API kaudu Kubernetes'i ressursside kogumit.
Samas: mulle isiklikult tundus see kirjeldus kasulik, mis ütleb:
Kubernetes API server on "loll server", mis pakub salvestamist, versioonihaldust, kontrollimist, uuendamist ja API ressursside semantikat.
Istio on loodud töötama koos Kubernetesega; ja kui soovite seda kasutada väljaspool Kuberneteset, peate käivitama Kubernetes API serveri eksemplari (ja toetava teenuse etcd).
Teenuste aadressid
Istio tugineb Kubernetes'i määratud ClusterIP aadressidele, seega saavad Istio teenused sisemise aadressi (mitte vahemikus 127.0.0.0/8).
Aadressile ClusterIP konkreetse teenuse jaoks Kubernetes klastris ilma Istio't, liigub kube-proxy ja suunatakse selle proksi tagaplaanile. Kui teid huvitavad tehnilised üksikasjad, siis kube-proxy seab iptables reeglid (või IPVS koormuse tasakaalustajad, olenevalt sellest, kuidas see seadistati), et muuta ühenduste sihtaadresse, mis liiguvad aadressil ClusterIP.
Pärast Istio paigaldamist Kubernetes klastrisse ei muutu midagi, kuni see ei ole selgelt lubatud konkreetse tarbija või isegi kogu nimiruumis, käivitades konteineri sidecar kohandatud podidesse. See konteiner käivitab Envoy eksemplari ja seadistab hulgast iptables reeglitest, et kõrvaldada liiklus, mis suundub teiste teenuste poole, ning suunata see liiklus Envoy-le.
Kubernetes DNS-iga integreerimisel tähendab see, et meie kood saab ühendust teenuse nime kaudu, ja kõik "toimib lihtsalt". Teisisõnu, meie kood genereerib päringud, näiteks http://api/v1/users/4242, siis api lahendab päringu 10.97.105.48, iptables reeglid kõrvaldavad ühendused, mis on saadetud 10.97.105.48-le ja suunavad need kohaliku Envoy-proksi poole, ning see kohalik proksi suunab päringu tegeliku API taustsüsteemi poole. Uff!
Lisa nüansid
Istio tagab ka lõpp-punktide krüpteerimise ja autentimise mTLS (kaks suunda TLS) kaudu. Selle eest vastutab komponent nimega Citadel.
Seal on ka komponent Mixer, mida Envoy võib küsida, et peamise domeeni kohta loendis. pärib, et teha selle päringu kohta erilisi otsuseid, sõltuvalt erinevatest teguritest, nagu päisesed andmed, taustsüsteemi koormus jne… (ärge muretsege: on palju vahendeid, et Mixer jääks töökorras, ja isegi kui see kokku kukub, töötab Envoy siiski normaalselt proksina).
Ja, ja mainisime ka jälgitavust: Envoy kogub tohutult palju meetrikaid, pakkudes samas jaotatud jälgimist. Mikroteenuste arhitektuuris, kui üks API-päring peab läbima mikroteenused A, B, C ja D, lisab jaotatud jälgimine päringule ainulaadse identifikaatori ja hoiab selle identifikaatori kõigis alamküsitlustes nende mikroteenuste kaudu, võimaldades salvestada kõik seotud kutsed, nende latentsuse jne.
Arendada või osta
Istio maine on keerulise süsteemina. Vastupidi, selle marsruudivõrgu loomiseks, mida ma postituse alguses kirjeldasin, on olemasolevate tööriistade abil suhteliselt lihtne. Niisiis, kas oleks mõtet selle asemel luua oma teenusevahe?
Kui meie vajadused on tagasihoidlikud (ei ole vaja jälgitavust, ahelat katkestajat ja muid peensuseid), siis tuleb mõtteid oma tööriista arendamisest. Kuid kui kasutame Kubernetes, ei pruugi see isegi vajalik olla, kuna Kubernetes juba pakub põhilisi teenuste avastamise ja koormuse tasakaalustamise tööriistu.
Kuid kui meie nõuded on keerukamad, siis „teenusmasina” ostmine tundub palju parem valik. (See ei ole alati just „ostmine”, kuna Istio on avatud lähtekoodiga, kuid vajame siiski inseneritehnikas investeerimist, et arendada mõista, kuidas see töötab, paigaldada ja seda hallata).
Mida valida: Istio, Linkerd või Consul Connect?
Kunagi oleme rääkinud ainult Istio'ist, kuid see ei ole ainus teenusmasin. Populaarne alternatiiv on , ja on veel .
Mida valida?
Ausalt öeldes, ma ei tea. Praegu ei pea ma end piisavalt pädevaks, et sellele küsimusele vastata. On mitu võrdlust nende tööriistade vahel ja isegi .
Üks paljutõotavaid lähenemisviise on kasutada tööriista, mis sarnaneb . See, et rakendab abstraktsioonikihti, et lihtsustada ja ühtlustada teenuse mesh'ide poolt pakutavaid API-sid. Selle asemel, et õppida erinevate (ja minu arvates suhteliselt keeruliste) teenuse mesh'ide konkreetseid API-sid, saame kasutada SuperGloo lihtsustatud konstruktsioone — ja hõlpsasti vahetada ühest teise, nagu meil oleks vahepealne konfiguratsioonifail, mis kirjeldab HTTP-liideseid ja taustsüsteeme ning suudab genereerida tõelise konfiguratsiooni Nginx'ile, HAProxy'le, Traefik'ule, Apache'ile…
Mängisin veidi Istio ja SuperGlooga ning järgmises artiklis tahan näidata, kuidas lisada Istio või Linkerd olemasolevasse klastrisse SuperGloo abil ning kui hästi viimane oma ülesande täidab, st lubab vahetada ühe teenuse mesh'i teise vastu ilma konfiguratsioonide uuesti kirjutamiseta.
Allikas: habr.com
