I think its fair to say that "microservices" has established itself as the leading way to architect a modern distributed cloud-native application. I've discussed many of the advantages of this approach over "monolithic" architectures in my Pluralsight courses such as Microservices Fundamentals
But it's also well known that microservices bring a lot of challenges with them. How do you perform service discovery? How do you enable developers to easily work with the services locally? How do you implement upgrades while minimizing downtime? How do you effectively monitor everything in a centralized location?
Fortunately, there are multiple tools and frameworks designed to help overcome these challenges. Kubernetes is an excellent orchestration platform that helps us immensely with challenges like deployments, observability, and service discovery. Frameworks like ASP.NET Core comes with a whole host of practical features ready to use out of the box like configuration, logging, and health endpoints. Cloud providers like Azure provide a wide variety of PaaS services that can easily be plugged into a microservices application.
So, in theory it ought to be really easy to develop, test, maintain and deploy microservice applications? Well, not so fast. Much progress has been made, but there is a way to go. And projects like Dapr seek to improve things...
What is Dapr?
At first glance Dapr might seem fairly unimpressive. It offers a collection of "building blocks" that solve several challenges relating to building microservices. These building blocks include service to service invocation, pub sub messaging, state management, observability, and secret management.
But don't we already have solutions to all of these? Anyone who's built a microservices application has already had to deal with all those problems, and the tools and frameworks we've already mentioned go a long way to easing the pain.
However, I do think Dapr offers something unique. To illustrate, I'm just going to pick one of the building blocks - service to service invocation, to highlight how Dapr can provide added value on top of what you are already using.
An Example: Service to Service Invocation
When one microservice needs to call another, several things need to happen.
First, we need service discovery - to find the address of the service we're communicating with. Of course, Kubernetes makes this pretty painless with inbuilt DNS. But it's not uncommon for developers to run microservices locally on their development machines. In which case each microservice is at localhost on a specific port number, which requires you to have some alternative mechanism in place to point to the correct service when running locally. With Dapr, you can address the target service by name regardless of whether you're running in "self-hosted" mode (directly on your machine) or on Kubernetes.
Second, when communicating between microservices it's important to retry if there are transient network issues. Of course this is possible to implement yourself with libraries like Polly, but that requires everyone to remember to use it and only recently I found a bug in a microservice caused by forgetting to implement retries. With Dapr, this is just a built-in capability.
Third, it's very important that communication between microservices is secured. Communications should be encrypted using mTLS, and authentication should be used to validate that the caller is authorized. A widely recognized best practice is to use mutual TLS, but this can be a pain to configure correctly, and often gets in the way when you are running locally in development. With Dapr, all service to service communications are automatically encrypted for you with mTLS, and certificates are automatically cycled. This takes a huge headache away.
Fourth, it's very valuable if you have distributed tracing and metrics gathering to give you a way to understand the communications between your microservices. Azure offers this with Application Insights, but again you don't necessarily benefit from that if you are running locally, and I've had problems in the past getting it correctly configured on all services. With Dapr, observability is another built-in part of the runtime. It uses open standards such as OpenTelemetry and W3C tracing making it easy to integrate with existing tools.
Fifth, another aspect of security is governing which microservices are allowed to call each other. For example microservice A might be allowed to talk to microservice B but not vice versa. It can be a pain to roll your own framework for configuring something like this, and if you're not a security expert its easy to get it wrong. Service meshes can offer this kind of behaviour for a Kubernetes cluster. Dapr also can provide the same access restrictions by means of access control lists, which are easy to configure, and even work when your running in "self-hosted" mode rather than Kubernetes.
Finally, we're seeing the rise of gRPC as an alternative to HTTP based APIs for microservices, due to its higher performance, and more formalized contracts. Migrating from HTTP to gRPC in a microservices environment could be tricky, as you'd need to upgrade clients and servers at the same time, or provide a period where both protocols were exposed. Dapr again can help us with this - allowing gRPC or HTTP to be used for service to service invocation, and even allowing a HTTP caller to consume a gRPC service.
So as you can see, there's quite a lot to the "simple" task of service invocation, and Dapr gives you a very comprehensive solution out of the box. It's not perfect - I've ran into some issues where VPN settings on a corporate network interfere with Dapr's service to service invocation in self-hosted mode. But it has the potential to greatly simplify this aspect of microservice development.
Dive deeper into Dapr
Of course, we've only scratched the surface of what Dapr offers by focusing on a single "building block". We could do the same for the other building blocks. I'm very interested to keep following Dapr and seeing how it evolves. It is already a very rich and capable platform, and it's very easy to adopt incrementally if you don't want to embrace everything at once. I recommend checking out the free Dapr for .NET Developers book which is a great introduction if you're a .NET developer.