Konténerek, mikroszolgáltatások és szervizhálók

Az interneten halom cikkek о szervizháló (service mesh), és itt van még egy. Hurrá! De miért? Aztán szeretném kifejezni a véleményemet, hogy jobb lett volna, ha a szervizhálók 10 évvel ezelőtt, még a konténerplatformok, például a Docker és a Kubernetes megjelenése előtt jelennek meg. Nem azt mondom, hogy az én nézőpontom jobb vagy rosszabb, mint másoké, de mivel a szervizhálók meglehetősen összetett állatok, több nézőpont segít jobban megérteni őket.

Szólok a dotCloud platformról, amely több mint száz mikroszolgáltatásra épült, és több ezer konténeres alkalmazást támogatott. Elmagyarázom, milyen kihívásokkal kellett szembenéznünk a fejlesztés és az indítás során, és hogyan segíthetnek (vagy nem tudtak) a szervizhálók.

A dotCloud története

Írtam már a dotCloud történetéről és a platform architektúrájáról, de a hálózati rétegről nem sokat beszéltem. Ha nem akarsz belemerülni az olvasásba utolsó cikk a dotCloudról dióhéjban a lényeg: ez egy PaaS platform-as-a-service, amely lehetővé teszi az ügyfelek számára az alkalmazások széles skálájának futtatását (Java, PHP, Python...), sokféle adat támogatásával szolgáltatások (MongoDB, MySQL, Redis...) és egy munkafolyamat, mint a Heroku: Feltöltöd a kódot a platformra, az összeállítja a konténerképeket és telepíti azokat.

Elmondom, hogyan irányították a forgalmat a dotCloud platformra. Nem azért, mert különösebben menő volt (bár a rendszer a maga idejében jól működött!), hanem elsősorban azért, mert modern eszközökkel egy ilyen kialakítást könnyen, rövid időn belül megvalósíthat egy szerény csapat, ha egy csomó között kell a forgalmat irányítani. mikroszolgáltatások vagy egy csomó alkalmazás. Így összehasonlíthatja a lehetőségeket: mi történik, ha mindent saját maga fejleszt, vagy egy meglévő szolgáltatáshálót használ. A szokásos választás az, hogy saját kezűleg készíti el vagy vásárolja meg.

Forgalomirányítás a tárolt alkalmazásokhoz

A dotCloudon lévő alkalmazások HTTP- és TCP-végpontokat tárhatnak fel.

HTTP végpontok dinamikusan hozzáadva a terheléselosztó fürt konfigurációjához Hipache. Ez hasonló ahhoz, amit az erőforrások ma csinálnak Bemenetel a Kubernetesben és egy terheléselosztóban, mint pl Traefik.

Az ügyfelek a megfelelő tartományokon keresztül csatlakoznak a HTTP-végpontokhoz, feltéve, hogy a tartománynév a dotCloud terheléselosztókra mutat. Semmi különös.

TCP végpontok portszámmal van társítva, amely ezután környezeti változókon keresztül az adott veremben lévő összes tárolóhoz kerül.

Az ügyfelek a megfelelő gazdagépnév (például gateway-X.dotcloud.com) és portszám használatával csatlakozhatnak a TCP-végpontokhoz.

Ez a gazdagépnév a „nats” kiszolgálófürtöt adja fel (nem kapcsolódik a NATS), amely a bejövő TCP-kapcsolatokat a megfelelő tárolóba (vagy terheléselosztó szolgáltatások esetén a megfelelő tárolókba) irányítja.

Ha ismeri a Kubernetes-et, ez valószínűleg a Szolgáltatásokra fogja emlékeztetni Csomópont port.

A dotCloud platformon nem voltak megfelelő szolgáltatások ClusterIP: Az egyszerűség kedvéért a szolgáltatásokat a platformon belülről és kívülről is ugyanúgy lehetett elérni.

Mindent nagyon egyszerűen szerveztek: a HTTP és a TCP útválasztó hálózatok kezdeti megvalósítása valószínűleg csak néhány száz Python sorból állt. Egyszerű (mondhatnám naiv) algoritmusok, amelyek a platform növekedésével és a további követelmények megjelenésével finomodtak.

Nem volt szükség a meglévő kód kiterjedt átalakításra. Különösen, 12 faktoros alkalmazások közvetlenül használhatja a környezeti változókon keresztül kapott címet.

Miben különbözik ez a modern szervizhálótól?

Korlátozott láthatóság. Egyáltalán nem volt metrikánk a TCP útválasztási hálóhoz. Ami a HTTP-útválasztást illeti, a későbbi verziók részletes HTTP-metrikákat vezettek be hibakódokkal és válaszidőkkel, de a modern szolgáltatáshálók még tovább mennek, integrációt biztosítva például a metrikagyűjtő rendszerekkel, mint például a Prometheus.

A láthatóság nemcsak működési szempontból fontos (a problémák hibaelhárítása érdekében), hanem új funkciók kiadásakor is. A biztonságról van szó kék-zöld bevetés и kanári bevetés.

Útválasztási hatékonyság is korlátozott. A dotCloud útválasztási hálóban az összes forgalomnak dedikált útválasztási csomópontok csoportján kellett keresztülhaladnia. Ez potenciálisan több AZ (Elérhetőségi zóna) határátlépést jelentett, és jelentősen megnövelte a késleltetést. Emlékszem a hibaelhárítási kódra, amely oldalanként több mint száz SQL-lekérdezést hajtott végre, és minden lekérdezéshez új kapcsolatot nyitott az SQL-kiszolgálóval. Helyi futtatáskor az oldal azonnal betöltődik, de a dotCloudban néhány másodpercig tart, mert minden TCP-kapcsolat (és az azt követő SQL-lekérdezés) több tíz ezredmásodpercet vesz igénybe. Ebben a konkrét esetben a tartós kapcsolatok megoldották a problémát.

A modern szervizhálók jobban kezelik az ilyen problémákat. Először is ellenőrzik, hogy a kapcsolatok meg vannak-e irányítva forrásban. A logikai folyamat ugyanaz: клиент → меш → сервис, de most a háló helyileg működik és nem távoli csomópontokon, így a kapcsolat клиент → меш lokális és nagyon gyors (mikroszekundum ezredmásodperc helyett).

A modern szolgáltatáshálók intelligensebb terheléselosztási algoritmusokat is megvalósítanak. A háttérrendszerek állapotának figyelésével nagyobb forgalmat küldhetnek a gyorsabb háttérrendszerekre, ami javítja az általános teljesítményt.

biztonság jobban is. A dotCloud routing mesh teljes egészében az EC2 Classicon futott, és nem titkosította a forgalmat (abban a feltételezésben, hogy ha valakinek sikerült sniffert rakni az EC2 hálózati forgalmára, akkor már nagy bajban voltál). A modern szolgáltatáshálók átláthatóan védik az összes forgalmunkat, például kölcsönös TLS-hitelesítéssel és ezt követő titkosítással.

Forgalom irányítása platformszolgáltatásokhoz

Oké, megbeszéltük az alkalmazások közötti forgalmat, de mi a helyzet magával a dotCloud platformmal?

Maga a platform mintegy száz mikroszolgáltatásból állt, amelyek különféle funkciókért feleltek. Néhányan mások kérését fogadták el, mások pedig háttérmunkások voltak, akik más szolgáltatásokhoz kapcsolódtak, de maguk nem fogadták el a csatlakozásokat. Mindenesetre minden szolgáltatásnak ismernie kell azon címek végpontjait, amelyekhez csatlakoznia kell.

Sok magas szintű szolgáltatás használhatja a fent leírt útválasztási hálót. Valójában a dotCloud több mint száz mikroszolgáltatása közül sokat hagyományos alkalmazásként telepítettek magán a dotCloud platformon. De néhány alacsony szintű szolgáltatásnak (különösen azoknak, amelyek ezt az útválasztási hálót alkalmazzák) valami egyszerűbbre volt szükségük, kevesebb függőséggel (mivel nem számíthattak magukra a működésükben – a jó öreg csirke és tojás probléma).

Ezeket az alacsony szintű, kritikus fontosságú szolgáltatásokat úgy telepítették, hogy konténereket futtattak közvetlenül néhány kulcsfontosságú csomóponton. Ebben az esetben nem használtak szabványos platformszolgáltatásokat: linker, ütemező és futtató. Ha a modern konténerplatformokhoz akarod hasonlítani, az olyan, mintha egy vezérlősíkot futtatnál vele docker run közvetlenül a csomópontokon, ahelyett, hogy a feladatot a Kubernetesre delegálnák. Koncepciójában eléggé hasonló statikus modulok (podok), amelyet használ kubeadm vagy bootkube önálló fürt indításakor.

Ezeket a szolgáltatásokat egyszerű és nyers módon tették közzé: egy YAML-fájl felsorolta a nevüket és címüket; és minden ügyfélnek másolatot kellett készítenie ebből a YAML-fájlból a telepítéshez.

Egyrészt rendkívül megbízható, mert nem igényel külső kulcs/értéktár támogatását, mint például a Zookeeper (ne feledjük, etcd vagy Consul akkor még nem létezett). Másrészt megnehezítette a szolgáltatások áthelyezését. Minden alkalommal, amikor egy lépést végrehajtanak, minden kliens frissített YAML-fájlt kap (és esetleg újraindul). Nem túl kényelmes!

Ezt követően elkezdtünk egy új sémát implementálni, ahol minden kliens egy helyi proxyszerverhez csatlakozott. Cím és port helyett csak a szolgáltatás portszámát kell tudnia, és ezen keresztül csatlakozni localhost. A helyi proxy kezeli ezt a kapcsolatot, és továbbítja a tényleges szervernek. Most, amikor a háttérrendszert egy másik gépre helyezi át vagy méretezi, az összes kliens frissítése helyett csak ezeket a helyi proxykokat kell frissítenie; és már nincs szükség újraindításra.

(Tervezték továbbá a forgalom TLS kapcsolatokba való beágyazását és egy másik proxy szerver elhelyezését a fogadó oldalra, valamint a TLS tanúsítványok ellenőrzését a fogadó szolgáltatás részvétele nélkül, amely úgy van beállítva, hogy csak localhost. Erről később).

Ez nagyon hasonlít a SmartStack az Airbnb-től, de a jelentős különbség az, hogy a SmartStack implementálásra és üzembe helyezésre került, míg a dotCloud belső útválasztási rendszerét leállították, amikor a dotCloud Docker lett.

Én személy szerint a SmartStack-et az olyan rendszerek egyik elődjének tartom, mint az Istio, a Linkerd és a Consul Connect, mert mindegyik ugyanazt a mintát követi:

  • Futtasson proxyt minden csomóponton.
  • Az ügyfelek csatlakoznak a proxyhoz.
  • A vezérlősík frissíti a proxykonfigurációt, amikor a háttérprogramok megváltoznak.
  • ... Profit!

A szervizháló modern megvalósítása

Ha ma hasonló rácsot kellene megvalósítanunk, hasonló elveket használhatnánk. Például konfiguráljon egy belső DNS-zónát úgy, hogy a szolgáltatásneveket a térben lévő címekhez rendeli hozzá 127.0.0.0/8. Ezután futtassa a HAProxy-t a fürt minden csomópontján, elfogadva a kapcsolatokat minden szolgáltatáscímen (abban az alhálózatban 127.0.0.0/8) és a terhelés átirányítása/kiegyenlítése a megfelelő háttérprogramokhoz. A HAProxy konfiguráció vezérelhető confd, amely lehetővé teszi a háttérinformációk tárolását az etcd-ben vagy a Consulban, és szükség esetén automatikusan leküldi a frissített konfigurációt a HAProxy-ra.

Nagyjából így működik az Istio! De néhány eltéréssel:

  • Felhasználások Envoy Proxy HAProxy helyett.
  • A háttérkonfigurációt a Kubernetes API-n keresztül tárolja az etcd vagy a Consul helyett.
  • A szolgáltatások a belső alhálózaton vannak kiosztva (Kubernetes ClusterIP-címek) a 127.0.0.0/8 helyett.
  • Kiegészítő komponenssel (Citadella) rendelkezik a kliens és a szerverek közötti kölcsönös TLS-hitelesítés hozzáadásához.
  • Támogatja az új funkciókat, például az áramkör megszakítását, az elosztott nyomkövetést, a kanári telepítést stb.

Nézzünk gyorsan néhány különbséget.

Envoy Proxy

Az Envoy Proxyt a Lyft [az Uber versenytársa a taxipiacon - kb. sáv]. Sok tekintetben hasonlít a többi proxyhoz (pl. HAProxy, Nginx, Traefik...), de a Lyft megírta a sajátjukat, mert olyan funkciókra volt szükségük, amelyek más proxykben nem voltak, és okosabbnak tűnt újat készíteni, mint kiterjeszteni a meglévőt. egy.

Az Envoy önmagában is használható. Ha van egy adott szolgáltatásom, amelyhez más szolgáltatásokhoz kell kapcsolódnom, akkor beállíthatom, hogy csatlakozzon az Envoyhoz, majd dinamikusan konfigurálhatom és újrakonfigurálhatom az Envoyt a többi szolgáltatás helyével, miközben számos nagyszerű kiegészítő funkciót kapok, például a láthatóságot. Egyéni klienskönyvtár vagy hívásnyomok kódba szúrása helyett az Envoy-nak küldjük a forgalmat, és az összegyűjti a mérőszámokat.

De Envoy is képes dolgozni adatsík (adatsík) a szervizhálóhoz. Ez azt jelenti, hogy az Envoy most be van állítva ehhez a szolgáltatáshálóhoz irányító sík (vezérlősík).

Vezérlési sík

A vezérlősík esetében az Istio a Kubernetes API-ra támaszkodik. Ez nem sokban különbözik a confd használatától, amely az etcd-re vagy a Consulra támaszkodik az adattárban lévő kulcskészlet megtekintéséhez. Az Istio a Kubernetes API-t használja a Kubernetes-erőforrások készletének megtekintéséhez.

Eközben és akkor: Személy szerint ezt hasznosnak találtam Kubernetes API leírásaamely így szól:

A Kubernetes API Server egy „hülye szerver”, amely tárolást, verziókezelést, érvényesítést, frissítést és szemantikát kínál az API-erőforrásokhoz.

Az Istio a Kubernetes-szel való együttműködésre készült; és ha a Kubernetesen kívül szeretné használni, akkor futtatnia kell a Kubernetes API-kiszolgáló egy példányát (és az etcd helper szolgáltatást).

Szolgáltatási címek

Az Istio a Kubernetes által kiosztott ClusterIP-címekre támaszkodik, így az Istio szolgáltatások belső címet kapnak (nem a tartományban 127.0.0.0/8).

Az Istio nélküli Kubernetes-fürtben egy adott szolgáltatás ClusterIP-címére irányuló forgalmat a kube-proxy elfogja, és elküldi a proxy háttérrendszerére. Ha érdeklik a technikai részletek, a kube-proxy beállítja az iptables szabályokat (vagy IPVS terheléselosztókat, a konfigurálástól függően), hogy átírja a ClusterIP-címre tartó kapcsolatok cél IP-címeit.

Miután az Istio telepítve van egy Kubernetes-fürtre, semmi sem változik, amíg egy tároló bevezetésével kifejezetten nem engedélyezik egy adott fogyasztó számára, vagy akár a teljes névtérre. sidecar egyedi hüvelyekbe. Ez a konténer felpörgeti az Envoy egy példányát, és beállít egy iptables-szabálykészletet, hogy elfogja a más szolgáltatások felé irányuló forgalmat, és átirányítsa azt a Envoy-hoz.

A Kubernetes DNS-sel integrálva ez azt jelenti, hogy a kódunk szolgáltatásnév alapján csatlakozhat, és minden „csak működik”. Más szóval, a kódunk olyan lekérdezéseket ad ki, mint pl http://api/v1/users/4242azután api kérését megoldani 10.97.105.48, az iptables szabályok a 10.97.105.48-tól kezdődően elfogják a kapcsolatokat, és továbbítják azokat a helyi Envoy proxynak, és ez a helyi proxy továbbítja a kérést a tényleges háttér API-nak. Fú!

További sallangok

Az Istio végpontok közötti titkosítást és hitelesítést is biztosít az mTLS-en (kölcsönös TLS) keresztül. Az úgynevezett komponens Fellegvár.

Alkatrész is van hozzá Keverő, amelyet a Küldött kérhet mindegyikből kérés, hogy hozzon különleges döntést a kéréssel kapcsolatban, különféle tényezőktől függően, mint például a fejlécek, a háttérterhelés stb... (ne aggódjon: sokféleképpen lehet a Mixert futni, és még ha összeomlik is, az Envoy továbbra is működik megfelelő meghatalmazottként) .

És természetesen megemlítettük a láthatóságot: az Envoy hatalmas mennyiségű mérőszámot gyűjt össze, miközben elosztott nyomkövetést biztosít. Egy mikroszolgáltatási architektúrában, ha egyetlen API-kérelemnek át kell haladnia az A, B, C és D mikroszolgáltatásokon, akkor bejelentkezéskor az elosztott nyomkövetés egyedi azonosítót ad a kéréshez, és ezt az azonosítót alkérelmeken keresztül tárolja az összes ilyen mikroszolgáltatásban, lehetővé téve minden kapcsolódó hívást rögzíteni kell, késések stb.

Fejleszteni vagy vásárolni

Istio összetettről híres. Ezzel szemben a bejegyzés elején leírt útválasztó háló felépítése viszonylag egyszerű a meglévő eszközök használatával. Tehát van értelme saját szolgáltatáshálót létrehozni helyette?

Ha szerény igényeink vannak (nincs szükségünk láthatóságra, megszakítóra és egyéb finomságokra), akkor felmerül a saját eszköz fejlesztése. De ha Kubernetes-et használunk, akkor lehet, hogy nem is lesz rá szükség, mert a Kubernetes már alapvető eszközöket biztosít a szolgáltatáskereséshez és a terheléselosztáshoz.

De ha speciális követelményeink vannak, akkor a szervizháló „vásárlása” sokkal jobb megoldásnak tűnik. (Ez nem mindig "vásárlás", mert az Istio nyílt forráskódú, de még mindig mérnöki időt kell szánnunk annak megértésére, telepítésére és kezelésére.)

Az Istio-t, a Linkerdet vagy a Consul Connect-et válasszam?

Eddig csak az Istio-ról beszéltünk, de nem ez az egyetlen szervizháló. Népszerű alternatíva - Linkerd, és van még több is Consul Connect.

Mit válasszak?

Őszintén szólva, nem tudom. Jelenleg nem tartom magam elég kompetensnek, hogy válaszoljak erre a kérdésre. Van néhány érdekes cikkek ezen eszközök összehasonlításával és még benchmarkok.

Az egyik ígéretes megközelítés egy olyan eszköz használata, mint SuperGloo. Egy absztrakciós réteget valósít meg a szolgáltatáshálók által kitett API-k egyszerűsítésére és egységesítésére. A különböző szolgáltatáshálók sajátos (és véleményem szerint viszonylag bonyolult) API-jainak megtanulása helyett használhatjuk a SuperGloo egyszerűbb konstrukcióit – és könnyedén válthatunk egyikről a másikra, mintha lenne egy köztes konfigurációs formátumunk, amely leírja a HTTP-interfészek és háttérprogramok működését. a tényleges konfiguráció létrehozása az Nginx, HAProxy, Traefik, Apache...

Kicsit foglalkoztam az Istióval és a SuperGloo-val, a következő cikkben pedig azt szeretném bemutatni, hogyan lehet SuperGloo-val hozzáadni Istiót vagy Linkerdot egy meglévő fürthöz, és az utóbbi hogyan végzi el a feladatát, vagyis lehetővé teszi-e, hogy átváltsunk egyik szolgáltatásháló a másikhoz a konfigurációk felülírása nélkül.

Forrás: will.com

Hozzászólás