An introduction to Dapr (Distributed Application Runtime)
Last year, Microsoft announced a new approach to develop modern applications based on Dapr. To put it simply: Dapr is an open source, portable, event-driven runtime that makes it easy for developers to build resilient, microservice stateless and stateful applications that run on the cloud and edge and embraces the diversity of languages and developer frameworks.
Dapr is completely platform and language independent; it means that it can run on any platform, any Kubernetes deployment, in the cloud or on-premise, and even on IoT (Internet of Things) devices too.
Initially, one contemplates Dapr as just another service mesh. Dapr operates as a sidecar, but provides a totally different functionality than a service mesh. Dapr is focused on providing building blocks that make it easier for developers to build microservices, unlike a service mesh, which is focused on networking concerns.
In this blog, we will take a look at how Dapr works and some key Dapr concepts.
How Dapr works
Communication between multiple microservices commands the use of gRPC (general-purpose Remote Procedure Calls), API (Application Programming Interface), pub/sub (publish-subscribe pattern), etc. Moreover, developers have to do Service Discovery as well as State Management. These two instances involve several parameters. Depending on whether it’s a stateless or stateful app, developers have to work with different SDKs (Software Development Kit) and programming models.
Dapr uses a sidecar pattern which is similar to side-car implementation in service mesh architecture, where a local proxy is used to route requests. Side-cars in Dapr are used to enable integration of microservice building blocks at runtime versus at compile time. This brings-in the advantage of having Dapr integrated with existing and legacy code operated through a standard HTTP (Hyper Text Transfer protocol)/gRPC interface, which enables enterprise developers to experience the benefits of microservices development without having to re-write their applications.
Some prominent Dapr concepts are given below. The purpose of these concepts is to provide a general and basic understanding of Dapr.
Any framework, any language, anywhere
As Dapr is totally platform independent, it means you can run applications locally, on any Kubernetes cluster and other managed environments integrated with Dapr. This enables developers to build microservice applications that run on the cloud and edge without changing code. Dapr collates best practices for building microservice applications into open, independent, building blocks to build portable applications with the language and framework of your choice.
In Dapr, a secret is any piece of private data that you want to protect against unsolicited users. Dapr provides a secret building block API and integrates it with secret stores such as Azure Key Vault and Kubernetes to store the secrets.
Robust Microservice Building Blocks for Cloud and Edge
A building block is like an HTTP or gRPC API that can be called from user code and uses one or more Dapr components.
Image source: https://github.com/dapr/docs/tree/master/concepts
Dapr consists of a set of building blocks, with extensibility to add new building blocks.
Each of these building blocks is independent, and you can use one, some or all of them in your application. In the initial release of Dapr, the following building blocks are provided:
Service Invocation - Service invocation enables applications to communicate with each other through well-known endpoints in the form of HTTP or gRPC messages.
State Management - Dapr provides a key or value-based state API with pluggable state stores for persistence. With state management for storing key or value pairs, long running, highly available, stateful services can be simply written alongside stateless services in your application. The state store is pluggable and can include Azure CosmosDB, AWS DynamoDB or Redis.
Publish and Subscribe Messaging - Dapr supports the pub/sub pattern between applications. Pub/Sub is a loosely coupled messaging pattern where senders or publishers, publishes messages to a topic, to which the subscribers subscribe.
Resource Bindings - Dapr permits you to invoke the external service through the Dapr binding API, and it allows your application to be triggered by events sent by the connected service. A binding provides a bi-directional connection to an external cloud/on-premise service or system.
Actors - An actor is an isolated, independent unit of compute and state with single-threaded execution. Dapr provides numerous capabilities in its actor runtime including concurrency, state, life-cycle management for actor activation/deactivation and timers and reminders to wake-up actors.
Distributed Tracing - Distributed tracing collects and aggregates trace events, metrics and performance numbers between Dapr instances. It allows you to trace the entire call chain across multiple services, or see call metrics on a user service.
Secrets - Service code can call the secrets API to retrieve secrets out of the Dapr supported secret store. Dapr offers a simple secret API and integrates with secret stores such as Azure Key Vault and Kubernetes secret stores.
Dapr reveals its APIs as a sidecar architecture, either as a container or as a process without requiring the application code to have any Dapr runtime code. This makes integration with Dapr easy from other runtimes and provides separation of the application logic for better supportability.
In standalone mode, Dapr runs as a separate process from which your service code can call via HTTP or gRPC.
In container hosting environments such as Kubernetes, Dapr runs as a side-car container with the application container in the same pod.
Dapr can run on multiple hosting platforms. The supported hosting platforms are:
- Self-hosted - Dapr runs on a single machine either as a process or in a container.
- Kubernetes - Dapr runs on any Kubernetes cluster either from a cloud provider or on-premise.
Running Dapr on a local developer machine in self-hosted mode
Dapr can be configured to run on your local developer machine in self-hosted mode. Each running service has a Dapr runtime process or sidecar which is configured to use state stores, pub/sub, binding components and other building blocks. You can use Dapr CLI to run a Dapr enabled application on your local machine.
Running Dapr in Kubernetes mode
Dapr can be configured to run on any Kubernetes cluster. Deploying and running a Dapr enabled application into your kubernetes cluster is a simple as adding a few annotations to the deployment schemes. To give your service an id and port known to Dapr, turn on tracing information and launch the Dapr sidecar container, you annotate your Kubernetes deployment like this.
annotations: dapr.io/enabled: "true" dapr.io/id: "nodeapp" dapr.io/port: "3000" dapr.io/config: "tracing"
Developer language SDKs and frameworks
Dapr can be integrated with any developer framework. For example, in the Dapr .NET SDK you can find ASP.NET Core integration, which brings stateful routing controllers that respond to pub/sub events from other services. And, in the Dapr Java SDK you can find Spring Boot integration.
Dapr uses a modular design where functionality is delivered as a component. Each component has an interface definition. All of the components are pluggable so that you can swap out one component with the same interface for another. You can get a list of current components available in the current hosting environment using the
dapr components CLI command.
Dapr allows custom middleware to be plugged into the request processing pipeline. Middleware can perform additional actions on a request, like authentication, encryption and message transformation before the request is routed to the user code, or before the request is returned to the client. The middleware components are used with the Service Invocation building block.
Dapr offers best practices for common capabilities when building microservice applications that developers can use in a standard way and deploy to any environment. Dapr brings around some of the demonstrated techniques and best practices to microservice development. In fact, Dapr does what ODBC (Open Database Connectivity) and JDBC (Java Database Connectivity) did to data driven client/server applications for consuming common services required by modern, cloud native applications. TypeScript, C#, Scala, Ruby and Rust are also slated for SDK development in the near future.