Konténerek, mikroszolgáltatások és szolgáltatás-meshek

Az interneten rengeteg cikkünkben ó szolgáltatás-meshek (service mesh), és itt van még egy. Hurrá! De miért? Mert szeretném kifejteni a véleményem, hogy jó lett volna, ha a szolgáltatás-meshek 10 évvel ezelőtt jelentek volna meg, még a konténerplatformok, mint a Docker és a Kubernetes megjelenése előtt. Nem állítom, hogy az én nézőpontom jobb vagy rosszabb, mint a többieké, de mivel a szolgáltatás-meshek meglehetősen bonyolult lények, a különböző nézőpontok segítenek jobban megérteni őket.

Beszélek a dotCloud platformról, amely több mint száz mikroszolgáltatáson alapult, és ezer alkalmazást támogattunk konténerekben. Elmagyarázom azokat a problémákat, amelyekkel a fejlesztés és a bevezetés során szembesültünk, és hogy hogyan segíthettek volna (vagy nem segíthettek volna) a szolgáltatás-meshek.

A dotCloud története

Már írtam a dotCloud történetéről és az architektúra választásáról a platform számára, de keveset meséltem a hálózati szintről. Ha nem akarsz mélyebben belemerülni cikkemből a dotCloud-ba, itt a lényeg: ez egy platform-szolgáltatás (PaaS), amely lehetővé teszi a felhasználók számára, hogy széles spektrumú alkalmazásokat futtassanak (Java, PHP, Python…), széleskörű adatforrások támogatásával (MongoDB, MySQL, Redis…) és a Heroku-hoz hasonló munkafolyamatokkal: feltöltöd a kódodat a platformra, és ő létrehozza a konténerképeket, majd telepíti azokat.

Mesélek arról, hogy hogyan irányítottuk a forgalmat a dotCloud platformra. Nem mert különösebben nagyszerű volt (bár a maga idejében a rendszer jól működött!), hanem elsősorban azért, mert a modern eszközökkel egy kicsi csapat könnyen megvalósíthatja ezt a dizájnt rövid idő alatt, ha szükségük van egy módszerre a forgalom irányítására számos mikroszolgáltatás vagy alkalmazás között. Így összehasonlíthatjuk a lehetőségeket: mi történik, ha mindent magunk fejlesztünk vagy használunk egy meglévő szolgáltatás-mest. A standard választás: csinálni magunk vagy megvenni.

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

A dotCloud alkalmazások HTTP és TCP végpontokat tudnak biztosítani.

HTTP végpontok dinamikusan kerülnek hozzáadásra a terheléselosztó klaszter konfigurációjához Hipache. Ez hasonló ahhoz, amit ma a források Ingress a Kubernetesben és terheléselosztók, mint a Traefik.

A kliensek a megfelelő tartományokon keresztül csatlakoznak a HTTP végpontokhoz, feltéve, hogy a domain név a dotCloud terheléselosztóira mutat. Semmi különös.

TCP végpontok kapcsolódik a port számhoz, amely ezután minden konténerhez átadásra kerül a stack-en keresztül környezeti változókként.

Az ügyfelek TCP végpontokhoz csatlakozhatnak a megfelelő host név használatával (például gateway-X.dotcloud.com) és port számmal.

Ez a host név a "nats" szerver klaszterre feloldásra kerül (nem kapcsolódik a NATS), amelyek az érkező TCP kapcsolatok irányításáért felelősek a megfelelő konténerhez (vagy, terheléselosztó szolgáltatások esetén, a megfelelő konténerekhez).

Ha ismeri a Kubernetes-t, valószínűleg emlékeztetni fogja a szolgáltatások. NodePort.

A dotCloud platformon nem volt megfelelője a szolgáltatásoknak. ClusterIP: az egyszerűség kedvéért a szolgáltatásokhoz való hozzáférés belülről és kívülről egyaránt azonos módon történt a platformon.

Minden elég egyszerűen volt megszervezve: a HTTP és TCP irányító hálózatok kezdeti megvalósításai valószínűleg csak néhány száz sor Python kódot tartalmaztak. Egyszerű (mondhatnám naiv) algoritmusok, melyeket a platform növekedésével és a további követelmények megjelenésével tökéletesítettek.

A meglévő kód jelentős refaktorizálása nem volt szükséges. Különösen, a 12-factor alkalmazások közvetlenül használhatják a környezeti változók által kapott címet.

Miben különbözik ez a modern szolgáltatás-mesh-től?

Korlátozott átláthatóság. Egyáltalán nem voltak metrikáink a TCP irányító hálózatról. Az HTTP irányítással kapcsolatban a későbbi verziókban részletes HTTP metrikák jelentek meg hibakódokkal és válaszidőkkel, de a modern szolgáltatás-mesh-ek még tovább mennek, integrálva a metrikagyűjtő rendszerekkel, mint például a Prometheus.

Az átláthatóság nemcsak operatív szempontból fontos (segíteni a problémák megoldásában), hanem új funkciók bevezetésénél is. A biztonságos kék-zöld telepítésekről és kanári telepítésekről.

Irányítási hatékonyság szintén korlátozott. A dotCloud routing hálózatában a forgalomnak át kellett haladnia egy dedikált route csomópontok klaszterén. Ez potenciálisan több AZ (elérhetőségi zónák) határvonalának átlépését és jelentős késlekedést jelentett. Emlékszem, amikor hibákat keresgéltem egy olyan kódban, amely több mint száz SQL-lekérdezést végzett az oldalon, és minden egyes lekérdezéshez új kapcsolatot nyitott az SQL-szerverrel. Helyi futtatáskor az oldal azonnal betöltődik, de a dotCloud-ban a betöltés több másodpercet vesz igénybe, mert minden TCP-kapcsolathoz (és a következő SQL-lekérdezéshez) több tucat milliszekundum szükséges. Ebben a konkrét esetben a problémát a tartós kapcsolatok oldották meg.

A modern szolgáltatás-mesh rendszerek jobban kezelik az ilyen problémákat. Elsősorban ellenőrzik, hogy a kapcsolatok routingolva vannak a forrásban. A logikai áramlás ugyanaz: ügyfél → mesh → szolgáltatás, de most a mesh helyben működik, nem távoli csomópontokon, így a kapcsolat ügyfél → mesh helyi és nagyon gyors (mikroszekundumok a milliszekundumok helyett).

A modern szolgáltatás-mesh rendszerek intelligensebb terheléselosztási algoritmusokat is alkalmaznak. A backendek működésének ellenőrzésével több forgalmat tudnak eljuttatni a gyorsabb backendekre, ami a teljesítmény növekedéséhez vezet.

Biztonság sokkal jobb is. A dotCloud routing hálózata teljes egészében az EC2 Classic-on futott, és nem titkosította a forgalmat (azt feltételezve, hogy ha valakinek sikerült sniffert telepítenie az EC2 hálózati forgalmára, már nagy problémák vannak). A modern szolgáltatás-mesh rendszerek átláthatóan védik az összes forgalmunkat, például kölcsönös TLS-azonosítással és azt követő titkosítással.

A platform szolgáltatásainak forgalomirányítása

Rendben, beszéltünk az alkalmazások közötti forgalomról, de mi a helyzet a dotCloud platformjával?

A platform maga körülbelül száz mikroszolgáltatásból állt, amelyek különböző funkciókért voltak felelősek. Egyesek kéréseket fogadtak másoktól, míg néhány háttérmunkás volt, amely más szolgáltatásokhoz csatlakozott, de saját maguk nem fogadtak kapcsolatokat. Mindenesetre minden szolgáltatásnak tudnia kellett azokat a végpontokat, amelyekhez csatlakozni kellett.

Sok magas szintű szolgáltatás használhatja a fent leírt útválasztási hálózatot. Valójában a dotCloud több mint száz mikroszolgáltatása hagyományos alkalmazásként volt telepítve a dotCloud platformján. Azonban néhány alacsony szintű szolgáltatás (különösen azok, amelyek ezt az útválasztási hálózatot megvalósítják) valami egyszerűbbre vágyott, kevesebb függőséggel (mivel nem támaszkodhattak magukra – régi, jó tojás- és csirke probléma).

Ezeket az alacsony szintű, fontos szolgáltatásokat úgy telepítették, hogy közvetlenül több kulcsfontosságú csomóponton indítottak konténereket. Ekkor nem használták a platform standard szolgáltatásait: összesítőt, ütemezőt és futtatót. Ha a modern konténerplatformokkal szeretné összehasonlítani, ez olyan, mintha a vezérlő síkot közvetlenül a docker run csomópontokon indítanánk, ahelyett, hogy a Kubernetes-re bíznánk a feladatot. Ez meglehetősen hasonlít a statikus modulok (podok), amelyeket a kubeadm vagy bootkube használ, amikor egy önálló klasztert indít.

Ezeket a szolgáltatásokat egyszerű és durva módon tették elérhetővé: a YAML fájlban felsorolták a nevüket és címeiket; minden kliensnek le kellett másolnia ezt a YAML fájlt a telepítéshez.

Egyrészt ez rendkívül megbízható, mert nem igényel külső kulcs-érték tárolószolgáltatás támogatását, mint például a Zookeeper (ne feledje, akkoriban még nem létezett az etcd vagy a Consul). Másrészt ez megnehezítette a szolgáltatások áthelyezését. Minden alkalommal, amikor áthelyezték őket, minden kliensnek frissített YAML fájlt kellett kapnia (és potenciálisan újra kellett indítani). Nem túl kényelmes!

Később elkezdtük bevezetni egy új sémát, ahol minden kliens egy helyi proxy szerverhez csatlakozott. Ahelyett, hogy a címét és portját kellene ismernie, elegendő csupán a szolgáltatás portszámát tudnia, és a localhost-ra csatlakoznia. A helyi proxy szerver kezeli ezt a kapcsolatot és irányítja azt a tényleges szerverre. Most, amikor a backendet egy másik gépre helyezzük át vagy méretezzük, nem kell minden klienst frissíteni, elég csak az összes helyi proxy-t frissíteni; és az újraindítás már nem szükséges.

(A TLS-kapcsolatokban tervezett forgalom encapsulálása és egy új proxy-szerver telepítése a fogadó oldalon, valamint a TLS-tanúsítványok ellenőrzése a kapcsolatok fogadására beállított fogadó szolgáltatás közreműködése nélkül, ami csak localhost. Erről később).

Ez nagyon hasonló SmartStack az Airbnb-től, de a lényeges különbség az, hogy a SmartStack megvalósítva és bevezetve van a produkciós környezetbe, míg a dotCloud belső irányítási rendszere a fiókba került, amikor a dotCloud Dockerre váltott.

Személy szerint úgy vélem, hogy a SmartStack az Istio, Linkerd és Consul Connect rendszerek egyfajta előfutára, mert mindegyik ugyanazon mintát követi:

  • Proxy indítása minden egyes csomóponton.
  • Az ügyfelek a proxyhoz csatlakoznak.
  • A vezérlési sík frissíti a proxy konfigurációját a háttérszolgáltatások megváltozása esetén.
  • … Profitt!

A modern szolgáltatás-hálók megvalósítása

Ha ma hasonló hálót kellene megvalósítanunk, hasonló elveket követhetnénk. Például belső DNS-zónát beállítva, amely összepárosítja a szolgáltatásneveket a 127.0.0.0/8. címekkel a 127.0.0.0/8) alhálózatban, és elágazás/balanszírozás végzése a megfelelő háttérszolgáltatásokra. Az HAProxy konfigurációját kezelhetnénk confd, lehetővé téve a háttérinformációk tárolását az etcd-ben vagy Consulban, és automatikusan frissített konfigurációk tologatását az HAProxy-ra, amikor szükséges.

Körülbelül így működik az Istio! De van néhány eltérés:

  • Használja Envoy Proxy az HAProxy helyett.
  • A háttérkonfigurációt a Kubernetes API-n keresztül tárolja az etcd vagy Consul helyett.
  • A szolgáltatások címeket kapnak a belső alhálózatban (Kubernetes ClusterIP-címek) a 127.0.0.0/8 helyett.
  • Van egy további összetevője (Citadel), amely lehetővé teszi a TLS-mutatóval való kölcsönös hitelesítést az ügyfelek és a szerverek között.
  • Támogat új funkciókat, mint például a körök megszakítása, elosztott nyomozás, kanári telepítés, stb.

Nézzük röviden a néhány különbséget.

Envoy Proxy

Az Envoy Proxy-t a Lyft írta [a Lyft az Uber versenytársa a taxispiacon - a fordító megjegyzése]. Nagyban hasonlít más proxykra (például az HAProxy, Nginx, Traefik…), de a Lyft sajátot írt, mert olyan funkciókra volt szükségük, amelyek hiányoztak más proxykból, és értelmesebbnek tűnt újat csinálni, mint a meglévőt bővíteni.

Az Envoy használható önállóan. Ha van egy konkrét szolgáltatásom, amely más szolgáltatásokhoz kell csatlakoznia, be tudom állítani, hogy csatlakozzon az Envoyhoz, és ezután dinamikusan be tudom állítani és átkonfigurálni az Envoy-t más szolgáltatások elhelyezkedésével, közben rengeteg kiváló funkciót kapva, például a megfigyelhetőséget. Ahelyett, hogy egyedi ügyfél könyvtárat használnék, vagy a kódban nyomkövetést integrálnék, a forgalmat az Envoyra irányítom, amely összegyűjti számunkra a metrikákat.

De az Envoy képes működni mint adatlap (data plane) a szolgáltatás-hálón. Ez azt jelenti, hogy most a szolgáltatás-hálón az Envoy-t a irányító lap (control plane) konfigurálja.

Irányító lap

Az irányító lapon 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, hogy lekérdezze a kulcsok halmazát az adat tárolóban. Az Istio a Kubernetes API-n keresztül a Kubernetes erőforrások halmazát böngészi.

Közben: számomra hasznosnak tűnt ez a Kubernetes API leírás, amely így szól:

A Kubernetes API szerver „butaszerver”, amely tárolást, verziókezelést, érvényesítést, frissítést és az API erőforrások szeminantikáját kínál.

Az Istio a Kubernetes-szel való együttműködésre lett kifejlesztve; és ha azon kívül szeretné használni, akkor egy Kubernetes API szerver példányt (és az etcd segédszolgáltatást) kell futtatnia.

Szolgáltatások címei

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).

A ClusterIP címre irányuló forgalom a Kubernetes klaszterben Istio nélkül a kube-proxy által át van irányítva, és a proxy hátoldalára kerül. Ha érdekli a technikai részletek, a kube-proxy iptables szabályokat (vagy IPVS terheléselosztókat, attól függően, hogyan van beállítva) állít fel a célcímmel érkező kapcsolatok IP-címeinek átkonfigurálásához, és a ClusterIP címre irányuló forgalom kerül.

Miután az Istio telepítve van a Kubernetes klaszterben, semmi sem változik, amíg az kifejezetten be nem van kapcsolva az adott felhasználó számára, vagy akár az egész névtér számára, a sidecar konténer bevezetésével az egyedi podokba. Ez a konténer elindít egy példányt az Envoyból, és létrehoz egy sor iptables szabályt a más szolgáltatásokra irányuló forgalom elfogásához, és ennek a forgalomnak az Envoyra irányításához.

A Kubernetes DNS integrációval ez azt jelenti, hogy a kódunk képes a szolgáltatás neve alapján csatlakozni, és minden "egyszerűen működik". Más szavakkal, a kódunk olyan lekérdezéseket generál, mint http://api/v1/users/4242, majd api megoldja a lekérdezést a következőhöz 10.97.105.48, az iptables szabályok elfogják a kapcsolatokat a 10.97.105.48 címről, és átirányítják azokat a helyi Envoy proxyra, amely ezt a helyi proxy továbbítja a tényleges API háttérszolgáltatásnak. Huh!

További finomságok

Az Istio emellett végpontok közötti titkosítást és hitelesítést is biztosít mTLS (kölcsönös TLS) révén. Ezt a funkciót egy úgynevezett összetevő biztosít Citadel.

Van egy további összetevő is Mixer, amelyet az Envoy kérhet a minden lekérdezéshez, hogy speciális döntést hozzon e lekérdezésről különböző tényezők, például a fejlécek, a háttérszolgáltatás terhelése stb. alapján... (ne aggódj: sok eszköz áll rendelkezésre a Mixer működésének biztosítására, és még ha le is áll, az Envoy továbbra is rendesen működik proxy-ként).

És természetesen említettük a megfigyelhetőséget: az Envoy hatalmas mennyiségű metrikát gyűjt, miközben elosztott nyomkövetést biztosít. A mikroszolgáltatások architektúrájában, ha egy API lekérdezésnek végig kell mennie az A, B, C és D mikroszolgáltatásokon, akkor a rendszerbe való belépéskor az elosztott nyomkövetés egy egyedi azonosítót ad a kéréshez, és ezt az azonosítót megőrzi az összes ilyen mikroszolgáltatáshoz intézett al-kérdésen keresztül, lehetővé téve az összes kapcsolódó hívás, azok késleltetései stb. rögzítését.

Fejleszteni vagy vásárolni

Az Istiónak hírneve van, mint bonyolult rendszernek. Ezzel szemben a routing hálózat építése, amit a poszt elején leírtam, viszonylag egyszerű a meglévő eszközök segítségével. Szóval van-e értelme saját szolgáltatás-meshing létrehozásának?

Ha szerény igényeink vannak (nincs szükség megfigyelhetőségre, láncutasító és egyéb finomságokra), felmerül a gondolat, hogy saját eszközt fejlesszünk. De ha Kubernetes-t használunk, talán még arra sincs szükség, mert a Kubernetes már biztosít alapvető eszközöket a szolgáltatások felfedezésére és a terheléselosztásra.

De ha fejlettebb követelményekkel rendelkezünk, akkor a szolgáltatás-mesh "vásárlása" sokkal jobb megoldásnak tűnik. (Ez nem mindig pontosan "vásárlás", mivel az Istio nyílt forráskódú, de így is időt kell fektetnünk abba, hogy megértsük a működését, telepítsük és kezeljük azt).

Mit választani: Istio, Linkerd vagy Consul Connect?

Eddig csak az Istioról beszéltünk, de nem ő az egyetlen service mesh. Népszerű alternatíva - Linkerd, és még van Consul Connect.

Mit válasszunk?

Őszintén szólva, nem tudom. Jelenleg nem tartom magam elég kompetensnek ahhoz, hogy válaszoljak erre a kérdésre. Van néhány érdekes cikkünkben összehasonlítás ezekről az eszközökről, és még benchmarkok.

Az egyik ígéretes megközelítés az, hogy olyan eszközt használunk, mint a SuperGloo. Ez egy absztrakciós réteget valósít meg az API-k egyszerűsítésére és egységesítésére, amelyeket a service mesh-ek kínálnak. Ahelyett, hogy a különböző (és véleményem szerint viszonylag bonyolult) service mesh API-kat tanulmányoznánk, egyszerűbb SuperGloo konstrukciókat használhatunk - és könnyedén válthatunk az egyikből a másikba, mintha lenne egy köztes konfigurációs formátumunk, amely leírja a HTTP interfészeket és a háttérszolgáltatásokat, és képes generálni a tényleges konfigurációt az Nginx, HAProxy, Traefik, Apache… számára.

Kicsit játszadoztam az Istióval és a SuperGloo-val, a következő cikkemben pedig meg akarom mutatni, hogyan lehet hozzáadni az Istiót vagy a Linkerd-t egy meglévő klaszterhez a SuperGloo segítségével, és hogy mennyire teljesíti a feladatát, azaz lehetővé teszi a váltást az egyik service meshről a másikra a konfigurációk felülírása nélkül.

Forrás: habr.com

Megbízható hosting vásárlása weboldalak számára, DDoS védelemmel, VPS VDS szerverek. 🔥 Megbízható webtárhely vásárlása DDoS védelemmel, VPS VDS szerverek | ProHoster