Kontejnery, mikroslužby a servisní sítě

Na internetu hromada články о servisní síť (servisní síť) a tady je další. Hurá! Ale proč? Poté chci vyjádřit svůj názor, že by bylo lepší, kdyby se servisní sítě objevily před 10 lety, před příchodem kontejnerových platforem, jako jsou Docker a Kubernetes. Neříkám, že můj úhel pohledu je lepší nebo horší než ostatní, ale vzhledem k tomu, že obslužné sítě jsou poměrně složitá zvířata, více úhlů pohledu jim pomůže lépe je pochopit.

Budu mluvit o platformě dotCloud, která byla postavena na více než stovce mikroslužeb a podporovala tisíce kontejnerizovaných aplikací. Vysvětlím problémy, kterým jsme čelili při vývoji a spouštění, a jak mohou (nebo nemohly) pomoci servisní sítě.

Historie dotCloud

Psal jsem o historii dotCloud a volbě architektury pro tuto platformu, ale nemluvil jsem moc o síťové vrstvě. Pokud se nechcete ponořit do čtení poslední článek o dotCloud, zde je podstata v kostce: je to platforma PaaS jako služba, která zákazníkům umožňuje provozovat širokou škálu aplikací (Java, PHP, Python...), s podporou široké škály dat služby (MongoDB, MySQL, Redis...) a pracovní postup jako Heroku: Nahrajete svůj kód na platformu, ona vytvoří obrázky kontejnerů a nasadí je.

Řeknu vám, jak byl provoz nasměrován na platformu dotCloud. Ne proto, že by to bylo obzvlášť cool (i když systém na svou dobu fungoval dobře!), ale především proto, že s moderními nástroji může takový návrh snadno implementovat v krátké době skromný tým, pokud potřebuje způsob, jak směrovat provoz mezi skupinami. mikroslužeb nebo hromady aplikací. Tímto způsobem můžete porovnat možnosti: co se stane, když vše vyvinete sami nebo použijete existující síť služeb. Standardní volbou je vyrobit si ho sami nebo koupit.

Směrování provozu pro hostované aplikace

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

HTTP koncové body dynamicky přidán do konfigurace clusteru nástroje pro vyrovnávání zatížení Hipache. To je podobné tomu, co dnes dělají zdroje Ingress v Kubernetes a load balanceru jako Traefik.

Klienti se připojují ke koncovým bodům HTTP prostřednictvím příslušných domén za předpokladu, že název domény odkazuje na nástroje pro vyrovnávání zatížení dotCloud. Nic zvláštního.

TCP koncové body spojené s číslem portu, které je pak předáno všem kontejnerům v tomto zásobníku prostřednictvím proměnných prostředí.

Klienti se mohou připojit ke 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 překládá na serverový cluster „nats“ (nesouvisí s NATS), který bude směrovat příchozí TCP spojení do správného kontejneru (nebo v případě služeb s vyvážením zatížení do správných kontejnerů).

Pokud znáte Kubernetes, pravděpodobně vám to připomene Služby Port uzlu.

Na platformě dotCloud nebyly žádné ekvivalentní služby ClusterIP: Pro zjednodušení byly služby přístupné stejným způsobem jak zevnitř, tak zvenčí platformy.

Vše bylo organizováno docela jednoduše: počáteční implementace směrovacích sítí HTTP a TCP obsahovaly pravděpodobně jen několik set řádků Pythonu. Jednoduché (řekl bych naivní) algoritmy, které byly zdokonalovány, jak platforma rostla a objevovaly se další požadavky.

Nebylo nutné rozsáhlé refaktorování stávajícího kódu. Zejména, 12faktorové aplikace může přímo používat adresu získanou prostřednictvím proměnných prostředí.

Jak se to liší od moderní sítě služeb?

Omezený viditelnost. Pro směrovací síť TCP jsme neměli vůbec žádné metriky. Pokud jde o směrování HTTP, novější verze zavedly podrobné metriky HTTP s chybovými kódy a dobou odezvy, ale moderní sítě služeb jdou ještě dále a poskytují integraci se systémy sběru metrik, jako je například Prometheus.

Viditelnost je důležitá nejen z provozního hlediska (pro pomoc při odstraňování problémů), ale také při vydávání nových funkcí. Jde o bezpečí modrozelené nasazení и kanárské nasazení.

Efektivita směrování je také omezená. Ve směrovací síti dotCloud musel veškerý provoz procházet shlukem vyhrazených směrovacích uzlů. To znamenalo potenciální překročení více hranic AZ (zóny dostupnosti) a výrazné zvýšení latence. Pamatuji si kód pro odstraňování problémů, který prováděl více než sto SQL dotazů na stránku a pro každý dotaz otevíral nové připojení k SQL serveru. Při lokálním běhu se stránka načte okamžitě, ale v dotCloudu trvá načtení pár sekund, protože každé TCP spojení (a následný SQL dotaz) trvá desítky milisekund. V tomto konkrétním případě problém vyřešila trvalá připojení.

S takovými problémy se lépe vypořádají moderní servisní sítě. V první řadě kontrolují směrování spojů ve zdroji. Logický tok je stejný: клиент → меш → сервис, ale nyní síť funguje lokálně a ne na vzdálených uzlech, takže připojení клиент → меш je lokální a velmi rychlý (mikrosekundy místo milisekund).

Moderní sítě služeb také implementují chytřejší algoritmy vyvažování zátěže. Sledováním stavu backendů mohou posílat více provozu na rychlejší backendy, což vede ke zlepšení celkového výkonu.

zabezpečení taky lepší. Směrovací mesh dotCloud běžel celý na EC2 Classic a nešifroval provoz (na základě předpokladu, že pokud se někomu podařilo nasadit sniffer na síťový provoz EC2, už jste měli velké potíže). Moderní servisní sítě transparentně chrání veškerý náš provoz, například vzájemnou autentizací TLS a následným šifrováním.

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

Dobře, diskutovali jsme o provozu mezi aplikacemi, ale co samotná platforma dotCloud?

Samotná platforma se skládala ze zhruba stovky mikroslužeb zodpovědných za různé funkce. Někteří přijímali požadavky od ostatních a někteří byli pracovníky na pozadí, kteří se připojovali k jiným službám, ale sami připojení nepřijímali. V každém případě musí každá služba znát koncové body adres, ke kterým se potřebuje připojit.

Mnoho služeb na vysoké úrovni může používat výše popsanou směrovací síť. Ve skutečnosti bylo mnoho z více než stovky mikroslužeb dotCloud nasazeno jako běžné aplikace na samotné platformě dotCloud. Ale malý počet nízkoúrovňových služeb (zejména těch, které implementují tuto směrovací síť) potřeboval něco jednoduššího, s menším počtem závislostí (protože se nemohly spoléhat samy na sebe – problém starého dobrého slepice a vejce).

Tyto nízkoúrovňové kritické služby byly nasazeny spuštěním kontejnerů přímo na několika klíčových uzlech. V tomto případě nebyly použity standardní služby platformy: linker, plánovač a běžec. Pokud se chcete srovnat s moderními kontejnerovými platformami, je to jako provozovat řídicí letadlo docker run přímo na uzlech, namísto delegování úkolu na Kubernetes. Koncepčně je to dost podobné statické moduly (pody), kterou používá kubeadm nebo bootkube při spouštění samostatného clusteru.

Tyto služby byly odhaleny jednoduchým a hrubým způsobem: soubor YAML uváděl jejich jména a adresy; a každý klient si musel vzít kopii tohoto souboru YAML pro nasazení.

Na jednu stranu je extrémně spolehlivý, protože nevyžaduje podporu externího úložiště klíč/hodnota, jako je Zookeeper (nezapomeňte, že etcd nebo Consul v té době neexistovaly). Na druhou stranu to ztížilo přesun služeb. Při každém přesunu by všichni klienti obdrželi aktualizovaný soubor YAML (a případně se restartovali). Ne moc pohodlné!

Následně jsme začali implementovat nové schéma, kdy se každý klient připojoval k lokálnímu proxy serveru. Místo adresy a portu potřebuje znát pouze číslo portu služby a připojit se přes localhost. Místní proxy zpracovává toto připojení a předává jej skutečnému serveru. Nyní, když přesouváte backend na jiný počítač nebo škálujete, místo aktualizace všech klientů stačí aktualizovat všechny tyto místní proxy; a restart již není nutný.

(Bylo také plánováno zapouzdření provozu v připojeních TLS a umístění dalšího proxy serveru na přijímací stranu, stejně jako ověření certifikátů TLS bez účasti přijímající služby, která je nakonfigurována tak, aby přijímala připojení pouze na localhost. Více o tom později).

Toto je velmi podobné SmartStack od Airbnb, ale podstatný rozdíl je v tom, že SmartStack je implementován a nasazen do produkce, zatímco interní směrovací systém dotCloud byl odložen, když se dotCloud stal Dockerem.

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

  • Spusťte proxy na každém uzlu.
  • Klienti se připojují k proxy.
  • Řídicí rovina aktualizuje konfiguraci proxy, když se backendy změní.
  • ... Zisk!

Moderní implementace servisní sítě

Pokud bychom dnes potřebovali implementovat podobnou mřížku, mohli bychom použít podobné principy. Například nakonfigurujte interní zónu DNS mapováním názvů služeb na adresy v prostoru 127.0.0.0/8. Poté spusťte HAProxy na každém uzlu v clusteru a přijměte připojení na každé adrese služby (v této podsíti 127.0.0.0/8) a přesměrování/vyrovnání zátěže na příslušné backendy. Konfigurace HAProxy lze ovládat confd, což vám umožní ukládat informace o backendu v etcd nebo Consul a v případě potřeby automaticky odeslat aktualizovanou konfiguraci do HAProxy.

Přesně takhle funguje Istio! Ale s určitými rozdíly:

  • Použití Envoy Proxy místo HAProxy.
  • Ukládá konfiguraci backendu přes Kubernetes API místo etcd nebo Consul.
  • Službám jsou přiděleny adresy na vnitřní podsíti (adresy Kubernetes ClusterIP) namísto 127.0.0.0/8.
  • Má další komponentu (Citadel) pro přidání vzájemné autentizace TLS mezi klientem a servery.
  • Podporuje nové funkce, jako je přerušení obvodu, distribuované trasování, nasazení kanárků atd.

Pojďme se v rychlosti podívat na některé rozdíly.

Envoy Proxy

Envoy Proxy napsal Lyft [konkurent Uberu na trhu taxi - cca. pruh]. V mnoha ohledech je podobný jiným proxy (např. HAProxy, Nginx, Traefik...), ale Lyft napsal jejich, protože potřeboval funkce, které ostatní proxy postrádaly, a zdálo se chytřejší vytvořit nový, než rozšiřovat stávající.

Envoy lze použít samostatně. Pokud mám konkrétní službu, která se potřebuje připojit k jiným službám, mohu ji nakonfigurovat tak, aby se připojila k Envoy, a poté dynamicky nakonfigurovat a překonfigurovat Envoy s umístěním jiných služeb a zároveň získat spoustu skvělých doplňkových funkcí, jako je viditelnost. Namísto vlastní klientské knihovny nebo vkládání trasování hovorů do kódu odesíláme provoz do Envoy a ten pro nás shromažďuje metriky.

Ale Envoy je také schopen pracovat jako datová rovina (datová rovina) pro síť služeb. To znamená, že Envoy je nyní nakonfigurován pro tuto síť služeb řídicí rovina (kontrolní rovina).

Řídící rovina

V řídicí rovině se Istio spoléhá na Kubernetes API. To se příliš neliší od použití confd, který při zobrazení sady klíčů v datovém úložišti spoléhá na etcd nebo Consul. Istio používá rozhraní Kubernetes API k zobrazení sady zdrojů Kubernetes.

Mezi tím a potom: Osobně jsem to považoval za užitečné Popis Kubernetes APIkterý zní:

Kubernetes API Server je „hloupý server“, který nabízí úložiště, verzování, ověřování, aktualizaci a sémantiku pro prostředky API.

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

Servisní adresy

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

Provoz na adresu ClusterIP pro konkrétní službu v clusteru Kubernetes bez Istio je zachycován kube-proxy a odeslán do backendu tohoto proxy. Pokud vás zajímají technické detaily, kube-proxy nastaví pravidla iptables (nebo IPVS load balancery, podle toho, jak je nakonfigurováno), aby přepsala cílové IP adresy připojení směřujících do ClusterIP adresy.

Jakmile je Istio nainstalováno v clusteru Kubernetes, nic se nezmění, dokud nebude explicitně povoleno pro daného spotřebitele nebo dokonce celý jmenný prostor zavedením kontejneru. sidecar do vlastních podů. Tento kontejner spustí instanci Envoy a nastaví sadu pravidel iptables pro zachycení provozu směřujícího do jiných služeb a přesměrování tohoto provozu na Envoy.

Při integraci s Kubernetes DNS to znamená, že se náš kód může připojit podle názvu služby a vše „prostě funguje“. Jinými slovy, náš kód vydává dotazy jako http://api/v1/users/4242pak api vyřešit žádost o 10.97.105.48, pravidla iptables zachytí připojení z 10.97.105.48 a předají je místnímu proxy Envoy a tento lokální proxy předá požadavek skutečnému backendovému API. Fuj!

Další ozdoby

Istio také poskytuje end-to-end šifrování a ověřování prostřednictvím mTLS (vzájemné TLS). Komponenta s názvem Citadela.

K dispozici je také komponenta mixér, o které může vyslanec požádat každý žádost o provedení zvláštního rozhodnutí o tomto požadavku v závislosti na různých faktorech, jako jsou hlavičky, zatížení backendu atd... (nebojte se: existuje mnoho způsobů, jak udržet Mixer spuštěný, a i když dojde k jeho zhroucení, Envoy bude nadále fungovat v pořádku jako proxy).

A samozřejmě jsme zmínili viditelnost: Envoy shromažďuje obrovské množství metrik a zároveň poskytuje distribuované sledování. V architektuře mikroslužeb, pokud jeden požadavek API musí projít mikroslužbami A, B, C a D, pak po přihlášení distribuované trasování připojí k požadavku jedinečný identifikátor a uloží tento identifikátor napříč dílčími požadavky na všechny tyto mikroslužby, což umožní všechny související hovory, které mají být zachyceny, zpoždění atd.

Vyvinout nebo koupit

Istio má pověst komplexu. Naproti tomu vytváření routovací sítě, kterou jsem popsal na začátku tohoto příspěvku, je poměrně jednoduché pomocí stávajících nástrojů. Má tedy smysl místo toho vytvořit vlastní síť služeb?

Pokud máme skromné ​​potřeby (nepotřebujeme viditelnost, jistič a další jemnosti), přichází myšlenky na vývoj vlastního nástroje. Pokud ale použijeme Kubernetes, možná to ani nebude potřeba, protože Kubernetes již poskytuje základní nástroje pro zjišťování služeb a vyrovnávání zátěže.

Ale pokud máme pokročilé požadavky, pak se „nákup“ servisní sítě zdá být mnohem lepší volbou. (Toto není vždy „koupit“, protože Istio je open source, ale stále potřebujeme investovat čas inženýrů, abychom to pochopili, nasadili a spravovali.)

Mám si vybrat Istio, Linkerd nebo Consul Connect?

Zatím jsme mluvili pouze o Istio, ale to není jediná síť služeb. Populární alternativa - Linkerd, a je toho víc Consul Connect.

Co si vybrat?

Upřímně, nevím. V tuto chvíli se nepovažuji za dostatečně kompetentní, abych na tuto otázku odpověděl. Je tu pár zajímavý články s porovnáním těchto nástrojů a dokonce benchmarky.

Jedním slibným přístupem je použití nástroje jako SuperGloo. Implementuje abstrakční vrstvu pro zjednodušení a sjednocení rozhraní API vystavených servisními sítěmi. Místo toho, abychom se učili konkrétní (a podle mého názoru poměrně složitá) API různých servisních sítí, můžeme použít jednodušší konstrukce SuperGloo – a snadno přepínat z jednoho na druhý, jako bychom měli přechodný konfigurační formát popisující HTTP rozhraní a backendy schopné generování aktuální konfigurace pro Nginx, HAProxy, Traefik, Apache...

Trochu jsem fušoval s Istio a SuperGloo a v dalším článku chci ukázat, jak přidat Istio nebo Linkerd do existujícího clusteru pomocí SuperGloo a jak ten druhý udělá práci, to znamená, že vám umožní přejít z jedna síť služeb do druhé bez přepsání konfigurací.

Zdroj: www.habr.com

Přidat komentář