Kontejnery, microservices a service mesh

Na internetu spousta článků o systémových meshů (service mesh), a je tu další. Hurá! Ale proč? Chci předložit svůj názor, že by bylo lepší, kdyby se služební meshe objevily před 10 lety, před vznikem kontejnerových platforem, jako jsou Docker a Kubernetes. Netvrdím, že můj názor je lepší nebo horší než ostatní, ale protože jsou služební meshe poměrně složité systémy, různé pohledy pomohou lépe je pochopit.

Povím vám o platformě dotCloud, která byla postavena na více než stovce mikroslužeb a podporovala tisíce aplikací v kontejnerech. Vysvětlím problémy, se kterými jsme se při její vývoji a nasazení setkali, a jak by služební meshe mohly pomoci (nebo nepomoci).

Historie dotCloud

O historii dotCloud a volbě architektury pro tuto platformu jsem již psal, ale málo jsem hovořil o síťové vrstvě. Pokud se nechcete zabývat čtením předchozího článku o dotCloud, stručně řečeno: je to platforma jako služba PaaS, která umožňuje klientům spouštět široké spektrum aplikací (Java, PHP, Python…) s podporou širokého spektra datových služeb (MongoDB, MySQL, Redis…) a workflow podobným Heroku: nahráváte svůj kód na platformu, ta vytváří obrazy kontejnerů a nasazuje je.

Povím, jak byl směřován provoz na platformu dotCloud. Ne proto, že by to bylo zvlášť úžasné (i když pro svou dobu systém fungoval docela dobře!), ale především proto, že pomocí moderních nástrojů lze podobný design snadno realizovat za krátkou dobu malým týmem, pokud potřebují způsob, jak směrovat provoz mezi spoustou mikroslužeb nebo spoustou aplikací. Takže je možné porovnat varianty: co se stane, pokud vše vyvineme sami nebo použijeme existující služební mesh. Standardní volba: vyvinout sami nebo koupit.

Směrování provozu pro hosted aplikace

Aplikace na dotCloud mohou poskytovat HTTP a TCP koncové body.

HTTP koncové body jsou dynamicky přidávány do konfigurace clusteru vyrovnávačů zatížení Hipache. Je to podobné tomu, co dnes dělají zdroje Ingress v Kubernetes a vyrovnávač zatížení jako github.com/containous/traefik.

Klienti se připojují k HTTP koncovým bodům prostřednictvím odpovídajících domén, pokud doménové jméno směřuje na vyrovnávače zatížení dotCloud. Nic zvláštního.

TCP koncové body jsou spojeny s číslem portu, které se pak předává všem kontejnerům v tomto stacku prostřednictvím proměnných prostředí.

Zákazníci se mohou připojit k koncovým bodům TCP pomocí příslušného názvu hostitele (něco jako gateway-X.dotcloud.com) a čísla portu.

Tento název hostitele se řeší na cluster serverů "nats" (to nemá nic společného s NATS), které budou směrovat příchozí TCP připojení do správného kontejneru (nebo, v případě služeb s vyvažováním zátěže, do správných kontejnerů).

Pokud jste obeznámeni s Kubernetes, pravděpodobně vám to připomene služby NodePort.

Na platformě dotCloud neexistoval ekvivalent služeb ClusterIP: pro jednoduchost probíhal přístup k službám stejně jak zevnitř, tak zvenčí platformy.

Vše bylo uspořádáno dost jednoduše: počáteční implementace směrovacích sítí HTTP a TCP, pravděpodobně jen několik set řádků Pythonu. Jednoduché (řekl bych, naivní) algoritmy, které byly vyvíjeny s růstem platformy a objevováním dalších požadavků.

Obsáhlé refaktoring stávajícího kódu nebyl potřebný. Zvláště 12-faktorové aplikace mohou přímo používat adresu získanou prostřednictvím proměnných prostředí.

Jak se to liší od moderní servisní mřížky?

Omezená viditelnost. Neměli jsme vůbec žádné metriky pro směrovací mřížku TCP. Pokud jde o směrování HTTP, v pozdějších verzích se objevily podrobné HTTP metriky s chybovými kódy a dobou odezvy, ale moderní servisní mřížky jdou ještě dále, poskytují integraci s metrickými sběrnými systémy, jako je například Prometheus.

Viditelnost je důležitá nejen z operativního hlediska (aby pomáhala při odstraňování problémů), ale také při uvedení nových funkcí. Mluvíme o bezpečném modrém-zeleném nasazení a nasazení kanárků.

Efektivita směrování byla také omezená. V síti směrování dotCloud musel veškerý provoz procházet klastrem dedikovaných uzlů pro směrování. To znamenalo potenciální překročení několika hranic AZ (oblastí dostupnosti) a výrazné zvýšení latence. Pamatuji si, jak jsem odstraňoval problémy s kódem, který prováděl více než stovku SQL dotazů na stránku a pro každý dotaz otevíral nové připojení k SQL serveru. Při lokálním spuštění se stránka načítá okamžitě, ale na dotCloud načítání trvá několik sekund, protože každému TCP připojení (a následnému SQL dotazu) je třeba desítek milisekund. V tomto konkrétním případě problém vyřešila trvalá připojení.

Moderní servisní meshé lépe zvládají takové problémy. Především kontrolují, že připojení jsou směrována zdroje. Logický tok zůstává stejný: klient → mesh → služba, ale nyní mesh funguje lokálně, nikoli na vzdálených uzlech, takže připojení klient → mesh je lokální a velmi rychlé (mikrosekuny místo milisekund).

Moderní servisní meshé také implementují inteligentnější algoritmy pro vyrovnávání zátěže. Kontrolováním provozuschopnosti backendů mohou směrovat více provozu na rychlejší backendy, což zvyšuje celkový výkon.

Bezpečnost také lépe. Síť směrování dotCloud fungovala zcela na EC2 Classic a nešifrovala provoz (na základě předpokladu, že pokud se někomu podařilo nasadit sniffer na síťový provoz EC2, už máte velké problémy). Moderní servisní meshé transparentně chrání veškerý náš provoz, například vzájemnou TLS autentizací a následným šifrováním.

Směrování provozu pro platformní služby

Dobře, prodiskutovali jsme provoz mezi aplikacemi, ale co samotná platforma dotCloud?

Samotná platforma se skládala z přibližně stovky mikroslužeb zodpovědných za různé funkce. Některé přijímaly požadavky od jiných, a některé byly pozadové pracovníky, které se připojovaly k jiným službám, ale samy nepřijímaly připojení. Každá služba musí v každém případě znát cílové adresy, ke kterým se musí připojit.

Mnoho vysoce kvalitních služeb může využívat síť směrování popsanou výše. Ve skutečnosti bylo mnoho z více než sta mikroslužeb dotCloud nasazeno jako běžné aplikace na samotné platformě dotCloud. Ale malé množství nízkoúrovňových služeb (zejména těch, které implementují tuto síť směrování) potřebovalo něco jednoduššího, s menšími závislostmi (protože nemohly záviset samy na sobě - starý dobrý problém slepice a vejce).

Tyto nízkoúrovňové, důležité služby byly nasazeny spuštěním kontejnerů přímo na několika klíčových uzlech. Přitom nebyly zapojeny standardní služby platformy: kompozitor, plánovač a runner. Pokud chcete porovnat se současnými kontejnerovými platformami, je to podobné spuštění řídicího stanoviska s docker run přímo na uzlech, místo abychom delegovali úkol Kubernetes. To je docela podobné myšlence statických modulů (podů), které využívá kubeadm nebo bootkube při spuštění autonomního clusteru.

Tyto služby byly exponovány jednoduchým a hrubým způsobem: v souboru YAML byla uvedena jejich jména a adresy; a každý klient si musel vzít kopii tohoto YAML souboru pro nasazení.

Na jedné straně je to extrémně spolehlivé, protože to nevyžaduje podporu externího úložiště klíčů/hodnot, jako je Zookeeper (nezapomínejte, že v té době ještě neexistovalo etcd nebo Consul). Na druhé straně to ztěžovalo přesun služeb. Při každém přesunu museli všichni klienti získat aktualizovaný YAML soubor (a potenciálně se znovu načíst). Ne příliš pohodlné!

V průběhu času jsme začali zavádět nový systém, kde se každý klient připojoval k místnímu proxy serveru. Místo adresy a portu mu stačí znát pouze číslo portu služby a připojit se přes localhost. Místní proxy server zpracovává toto připojení a směruje ho na skutečný server. Nyní při přesunu backendu na jiný stroj nebo při škálování je potřeba aktualizovat pouze všechny tyto místní proxy; a znovu načítání již není potřeba.

(Také bylo plánováno enkapsulovat provoz v TLS spojení a nasadit další proxy server na přijímající straně, a také kontrolovat TLS certifikáty bez účasti přijímací služby, která je nastavena pro příjem spojení pouze na localhost. O tom později).

To velmi připomíná SmartStack od Airbnb, ale zásadní rozdíl je v tom, že SmartStack byl zaveden a nasazen v produkci, zatímco vnitřní systém směrování dotCloud byl uložen do šuplíku, když se dotCloud přeměnil na Docker.

Osobně považuji SmartStack za jednoho z předchůdců systémů jako Istio, Linkerd a Consul Connect, protože všechny následují stejný vzor:

  • Spuštění proxy na každém uzlu.
  • Klienti se připojují k proxy.
  • Řídicí rovina aktualizuje konfiguraci proxy serveru při změně backendů.
  • … Zisk!

Moderní implementace service mesh

Pokud dnes potřebujeme implementovat podobnou síť, můžeme použít podobné principy. Například nastavit vnitřní DNS zónu, přiřazující názvy služeb k adresám ve prostoru 127.0.0.0/8. Poté spustit HAProxy na každém uzlu clusteru, přijímat spojení na každou adresu služby (v této podsíti 127.0.0.0/8) a přesměrovávat/rozkládat zátěž na příslušné backendy. Konfigurace HAProxy může být spravována confd, což umožňuje uchovávat informace o backendu v etcd nebo Consul a automaticky pushovat aktualizovanou konfiguraci na HAProxy, když je to nutné.

Takto přibližně funguje Istio! Ale s některými rozdíly:

  • Používá Envoy Proxy místo HAProxy.
  • Udržuje konfiguraci backendu prostřednictvím Kubernetes API namísto etcd nebo Consul.
  • Službám jsou přidělovány adresy ve vnitřní podsíti (adresy Kubernetes ClusterIP) namísto 127.0.0.0/8.
  • Má další komponent (Citadel) pro přidání vzájemné autentizace TLS mezi klientem a servery.
  • Podporuje nové funkce, jako je přerušení okruhu (circuit breaking), distribuované sledování, nasazení kanárků a další.

Pojďme stručně přehlednout některé rozdíly.

Envoy Proxy

Envoy Proxy napsala společnost Lyft [konkurent Uber na trhu taxislužeb – pozn. př.]. V mnohém je podobná jiným proxy (například HAProxy, Nginx, Traefik…), ale Lyft vytvořila svoji, protože potřebovala funkce, které v jiných proxy chyběly, a bylo rozumnější vytvořit nový, než rozšiřovat stávající.

Envoy lze používat samostatně. Pokud mám konkrétní službu, která se má připojit k jiným službám, mohu ji nastavit na připojení k Envoy, a poté dynamicky konfigurovat a přeformulovávat Envoy s umístěním dalších služeb, přičemž získám mnoho skvělých dalších funkcí, jako například přehlednost. Místo vlastní klientské knihovny nebo implementace sledování volání směrujeme provoz do Envoy, který pro nás shromažďuje metriky.

Ale Envoy může také fungovat jako datová rovina (data plane) pro servisní mesh. To znamená, že nyní pro tento servisní mesh je Envoy konfigurován řídicí rovinou (control plane).

Řídicí rovina

V řídicí rovině Istio spoléhá na API Kubernetes. To se příliš neliší od použití confd, které se spoléhá na etcd nebo Consul pro prohlížení souboru klíčů v datovém úložišti. Istio přes API Kubernetes prohlíží sadu zdrojů Kubernetes.

Mezitím: mně osobně přišlo užitečné toto popis API Kubernetes, které říká:

Server API Kubernetes je "hloupý server", který nabízí úložiště, správu verzí, kontrolu, aktualizaci a sémantiku API zdrojů.

Istio je navržen pro práci s Kubernetes; a pokud jej chcete používat mimo Kubernetes, musíte spustit instanci serveru API Kubernetes (a pomocné služby etcd).

Adresy služeb

Istio spoléhá na adresy ClusterIP, které přiděluje Kubernetes, takže služby Istio dostávají interní adresu (ne v rozsahu 127.0.0.0/8).

Provoz na adresu ClusterIP pro konkrétní službu v klastru Kubernetes bez Istio je zachycován kube-proxy a odesílán na backend této proxy. Pokud vás zajímají technické podrobnosti, kube-proxy nastavuje pravidla iptables (nebo IPVS vyvažovače zátěže, v závislosti na tom, jak je nakonfigurován), aby přepsal cílové IP adresy spojení, která jdou na adresu ClusterIP.

Po instalaci Istio v klastru Kubernetes se nic nemění, dokud nebude výslovně povoleno pro daného zákazníka nebo dokonce pro celé jmenné prostory, prostřednictvím zavedení kontejneru sidecar do vlastních podů. Tento kontejner spustí instanci Envoy a nastaví řadu pravidel iptables, aby zachytil provoz jdoucí k jiným službám a přesměroval tento provoz na Envoy.

Při integraci s Kubernetes DNS to znamená, že náš kód se může připojit podle názvu služby a všechno "jednoduše funguje". Jinými slovy, náš kód posílá dotazy typu http://api/v1/users/4242, pak api vyřeší dotaz na 10.97.105.48, pravidla iptables zachycují spojení s 10.97.105.48 a přesměrovávají je na místní proxy Envoy, která tento místní proxy přesměruje dotaz na skutečný backend API. Uf!

Další vychytávky

Istio také zajišťuje end-to-end šifrování a autentizaci pomocí mTLS (vzájemné TLS). O tuto funkcionalitu se stará komponenta nazvaná Citadel.

Existuje také komponenta Mixer, kterou může Envoy požádat o každou žádost, aby přijal speciální rozhodnutí o této žádosti na základě různých faktorů, jako jsou hlavičky, zatížení backendu atd. (nemějte obavy: existuje mnoho prostředků, jak zajistit funkčnost Mixeru, a i když se dostane do problémů, Envoy bude nadále normálně fungovat jako proxy).

A samozřejmě jsme zmínili sledovatelnost: Envoy shromažďuje obrovské množství metrik a zajišťuje distribuované trasování. V architektuře mikroslužeb, pokud jeden API dotaz musí projít mikroslužbami A, B, C a D, pak při vstupu do systému distribuované trasování přidá k dotazu jedinečný identifikátor a uchová tento identifikátor přes poddotazy do všech těchto mikroslužeb, což umožní zaznamenávat všechna související volání, jejich zpoždění atd.

Vyvinout nebo koupit

Istio má pověst složitého systému. Naopak, stavění směrovací sítě, kterou jsem popsal na začátku tohoto příspěvku, je relativně jednoduché pomocí stávajících nástrojů. Má tedy smysl místo toho vytvářet vlastní service mesh?

Pokud máme skromné potřeby (nepotřebujeme sledovatelnost, přerušovač řetězce a další jemnosti), přicházejí myšlenky na vývoj vlastního nástroje. Ale pokud používáme Kubernetes, možná nebude ani nutný, protože Kubernetes už poskytuje základní nástroje pro objevování služeb a vyvažování zátěže.

Ale pokud máme pokročilé požadavky, pak se "nákup" service mesh jeví jako mnohem lepší varianta. (To není vždy úplně "nákup", protože Istio je dodáváno s otevřeným zdrojovým kódem, ale i tak musíme investovat inženýrský čas na pochopení jeho fungování, nasazení a správu).

Co si vybrat: Istio, Linkerd nebo Consul Connect?

Zatím jsme mluvili pouze o Istio, ale to není jediný service mesh. Oblíbenou alternativou je Linkerd, a jsou také další Consul Connect.

Co vybrat?

Upřímně, nevím. V tuto chvíli se nepovažuji za dostatečně kompetentního, abych na tuto otázku odpověděl. Existuje několik zajímavých článků srovnání těchto nástrojů a dokonce benchmarky.

Jedním z nadějných přístupů je použít nástroj jako SuperGloo. Ten implementuje vrstvu abstrakce pro zjednodušení a unifikaci API, které poskytují service meshe. Místo toho, abychom se museli učit specifická (a podle mého názoru relativně složitá) API různých service meshů, můžeme použít jednodušší konstrukce SuperGloo - a snadno přepínat z jednoho na druhý, jako bychom měli prostřední formát konfigurace popisující HTTP rozhraní a backendy, schopný generovat skutečnou konfiguraci pro Nginx, HAProxy, Traefik, Apache…

Chvíli jsem si hrál s Istio a SuperGloo, a v dalším článku chci ukázat, jak přidat Istio nebo Linkerd do existujícího clustera pomocí SuperGloo a jak si poslední nástroj poradí se svou prací, tedy umožní přepínání z jednoho service mesh na druhý bez přepisování konfigurací.

Zdroj: habr.com

Koupit spolehlivý hosting pro webové stránky s ochranou proti DDoS, VPS VDS servery 🔥 Koupit spolehlivý hosting pro webové stránky s ochranou proti DDoS, VPS VDS servery | ProHoster