Vytvářejte aplikace nezávislé na platformě s DAPR (Distributed Application Runtime)

Vytváření distribuovaných cloud-native aplikací postavených na mikroslužbách není snadné. Infrastrukturní platforma jako je Kubernetes (orchestrátor kontejnerů) je velmi dobrým způsobem, jak takové řešení provozovat a nasazovat. Nicméně pro vývojáře nenabízí mnoho prostředků k tomu, aby jim zjednodušila používání klíčových patternů distribuovaného světa. Nenabízí nějaké univerzální API, které by pro vás řešilo binding externích služeb, řešilo sdílení state pro stavové služby, nativní řešení pro publish/subscribe pattern ani programátorské koncepty typu actor model a další vlastnosti. Je to logické - Kubernetes není aplikační platforma, ale orchestrátor kontejnerů.

Potřeba pro DAPR a prorůstání kódu s technickou implementací

Vezměme si na začátek jednoduchý příklad - mám sadu instancí mikroslužby, které potřebují sdílet nějaký stav, například session state, obsah nákupního košíků a tak podobně. Jak to vyřešíte? Na první dobrou možná řeknete - tak to je jasné, dáme tam Redis. Ten má svůj vlastní binární protokol, takže si do kódu přikompilujete SDK a dáte si na Redis dependency. Také si rozmyslíte, jak si předávat connection stringy. Ale co když potřebujete i jiné možnosti? Třeba pro vás bude vhodnější v cloudu použít CosmosDB, protože umí být celoplanetární a držet vám state mezi kontinenty a přitom číst i psát lokálně. Ale co v jiném cloudu, kde zvolíte DynamoDB nebo Spanner? Nebo nějaký state repozitář typu Consul či etcd? Nebo Memcached, Zookeeper, Couchbase či MongoDB? Každé takové rozhodnutí znamená nové SDK, změnu kódu, jiný způsob ověřování. A teď si představte, že máte aplikace v různých programovacích jazycích a v každém je samozřejmě jiná implementace SDK, tedy jsou v nich pokaždé jiné bugy nebo vlastnosti. Implementační rozhodnutí prorůstá do aplikace a to u distribuovaných řešení není dobré.

A teď si vezměte fakt, že typicky používáte i další patterny. Publish/Subscribe (protokol bude AMQP 0.9, AMQP 1.0, MQTT, REST nebo Kafka … a implementace bude NAST, Rabbit, Azure Service Bus, Kafka)? Co Actor Model, který má typicky různé implementace pro různé jazyky? A jak na binding externích systémů, co když potřebuji někam chrlit výstup a nechci řešit rozdíly mezi Azure Blob Storage vs. AWS S3 vs. GPC Storage Bucket? Nebo chci binding směrem k sobě, ale nechci v kódu ani SDK řešit rozdíl mezi Azure Event Hub, Kafka, AWS SQS nebo generické MQTT.

DAPR tohle řeší. Je to vrstva abstrakce, která směrem k vašemu kódu nabízí jednoduchý REST nebo gRPC interface, takže vlastně ani nepotřebujete nějaké SDK (ale můžete ho mít a vypadá nádherně jednoduše). Vývojář využívá služby DAPR - pub/sub, state store, binding, actor model, leaders election, service discovery apod. a neřeší jak je to implementováno. Aplikační a infrastrukturní operátor využije v DAPR “driver” pro konkrétní cloud nebo on-premises implementaci. Konečně oddělíte kód od infrastrukturních rozhodnutí. DAPR je univerzální open source abstrakce, kterou si přinesete do libovolného Kubernetes, virtuálních mašin, jakéhokoli cloudu. Způsob jak to řeší je elegantní a má velmi malý overhead, ale hlavně - DAPR je sada jednoduchých API pro snadnější tvorbu cloud-native distribuovaných aplikací kdekoli. Ideální doplněk infrastrukturní platformy jako je Kubernetes.

Výhody a nevýhody PaaS řešení a serverless

Platform as a Service je typicky řešení, které nabízí i užitečné služby pro váš aplikační kód, ne jen jeho nasazení a provoz. Asi nejlepším příkladem jsou serverless platformy jako jsou Azure Functions. Potřebujete aby se váš kód probudil, když se objeví nová zpráva ve frontě? Serverless to řeší. Potřebujete ve svém kódu připravit připojení na frontu, její polling, předávání connection stringů a tak podobně? To za vás řeší platforma. Pokud má být výsledkem vaší funkce vytvoření souboru ve storage nebo vygenerování zprávy do fronty, opět nepotřebujete v aplikaci zajistit klíče pro napojení, SDK pro správné naformátování zprávy a použití vhodného protokolu. Serverless, jako jsou Azure Functions, tohle vyřeší pro vás na úrovni platformy.

Přes nesporné výhody se ale můžete dostat do situace, kdy narazíte na limity:

  • Řešení se špatně přenáší z jednoho cloudu do druhého a to pro vaší exit strategii znamená problém
  • Platformy od hráčů mimo cloud (jako je Red hat či Pivotal) zase nejsou do cloudu dobře integrované a skončíte s hromadou virtuálních mašin, o které se musíte starat (tedy pokud nemáte Azure Red Hat OpenShift, který je plně spravovaný)
  • Aplikaci provozujete v on-premises a dostat skutečný cloud pod svojí střechu není jednoduché (tedy pokud nemáte Azure Stack Hub)
  • Aplikace není jen pro vás - nabízíte ji jako software zákazníkům a nechcete omezovat jejich možnost volby prostředí
  • Váš kód možná musí fungovat i v edge, tedy například na Raspberry někde v továrně bez připojení na cokoli venku a to není snadné (tedy pokud nemáte Azure IoT Edge nebo Azure Stack Edge)

Azure se snaží na většinu těchto otázek nabízet nějakou zajímavou variantu, ale i tak možná potřebujete naprostou univerzálnost, multi-cloudovost i multi-onpremisovost (to poslední slovo jsem si samosebou vymyslel).

Jak to DAPR vlastně dělá

DAPR nasadíte přímo vedle své aplikace a ve světě Kubernetes je to side-car uvnitř stejného Podu. Díky tomu může vaše aplikace využívat jeho služby na loopbacku 127.0.0.1 a protože to je jen lokální scope, nemusí vás trápit nějaké ověřování nebo service discovery - tento provoz váš Pod neopustí. Nicméně kontejner to být nemusí, klidně to může být proces v nějaké jiné izolaci v IoT zařízení, virtuální mašina a tak podobně. DAPR je aktuálně binárka napsaná v Go, velmi efektivní a rychlá. Má 58 MB a k uspěšnému životu jí stačí 4 MB paměti. Díky tomu ji můžete s naprostým klidem nasadit vedle každé instance mikroslužby.

DAPR tedy nabízí velmi jednoduché API ve formě REST a gRPC a přes něj používáte všechny jeho funkce - state store, actor model, service discovery, pub/sub, binding a všechny další služby. DAPR následně využije v binárce zabudovaných “driverů” k tomu, aby se napojil na vhodné služby v Azure, AWS, Google nebo v on-premises na implementace typu RabbitMQ, Kafka, Redis, Consul a tak podobně. Není to ale jen překladač na úrovni protokolů, implementují se i přidané vlastnosti. Tak například pro publisher/subscriber model ve skutečnosti nepotřebujete službu typu fronty, DAPR vám ji zajistí i přes REDIS. Přidává k datům eTagy a umožní vám tak určit zda chcete strategii First-write wins nebo Last-write wins a často můžete i určit míru konzistence strong nebo eventual. Actor model je další dobrý příklad, kdy s využitím kombinace service discovery a state store získáte implementaci tohoto modelu třeba nad obyčejným Redisem. Binding například napojíte na venkovní frontu, třeba Event Hub kam proudí data z IoT. DAPR vám bude zprávy vyzvedávat a posílat vám je do kódu tak, že zavolá vaše API. Nemusíte řešit z jakého systému to přišlo ani jaký je tam protokol nebo klíč. Jednoduše ve své aplikaci vystavíte třeba API poslouchající na :5000/bindig-eventhub a DAPR vám do něj bude POSTem servírovat rovnou data. Změníte Event Hub za Kafku? Na kódu se nezmění vůbec nic. Totéž pro ouput binding a vlastně všechny další služby.

Implementace v Kubernetes využívá jeho nativních prostředků. Konfigurace “driverů” (říká se jim DAPR components) žije jako Kubernetes objekt (CRD), takže ji nasazujete třeba Helmem a DAPR díky anotacím, které dáte do vašich Podů, pozná, kde chcete přidat DAPR side-car. Je to podobný mechanismus, jaký můžete znát ze service mesh technologií, které ale samozřejmě plní zcela jinou funkci - ostatně kombinace DAPR a service mesh je možná a tvůrci ji mají odzkoušenou.

DAPR považuji za hodně revoluční řešení a mohl by konečně rozmotat kód od provozních detailů. Příště si to všechno vyzkoušíme a pokud už nevydržíte čekat, moje pokusy jsou na https://github.com/tkubica12/dapr-demo. Ale když vydžíte do příště, budou s českým komentářem a screenshoty. V každém případě se nad DAPR zamyslete a vyzkoušejte to - dost možná je to budoucnost cloud-native světa a další schůdek v nikdy nekončící cestě do cloud-native ráje.



Kubernetes praticky: role Service Mesh Kubernetes Kontejnery
Kubernetes praticky: DAPR jako přenositelná aplikační platforma pro cloud-native aplikace - state store a pub/sub Kubernetes Kontejnery Serverless
Open Application Model: moderní popis aplikace bez naivity Kubernetes
Kubernetes praticky: serverless s KEDA, Osiris a Azure Functions Kubernetes Kontejnery Serverless
Pohled na hybridní svět IT nově i s Azure Arc Kubernetes