The distributed application runtime, Dapr, is a portable, event-driven runtime that can run on the cloud or any edge infrastructure. It puts together the best practices for building microservice applications into components called building blocks.
Each building block is completely independent so you can use one, some, or all of them in your application. Building blocks are extensible, so you can also write your own.
Dapr supports a wide range of programming languages and frameworks such as .NET, Java, Node.js, Go and Python. That means you can write microservice apps using your favorite tools and deploy them literally anywhere.
Basically, building blocks are just HTTP or gRPC APIs that can be called from application code and use one or more Dapr components. They abstract some of the major challenges during development such as service-to-service communication, state managment, pub/sub, observability and more. Building blocks do not depend on underlying technology. This means if you need to implement, for example, pub/sub functionality you can use Apache Kafka, RabbitMQ, Redis Streams, Azure Service Bus or any other supported broker that interface with Dapr.
In this example we will show how to run Dapr on the Kubernetes cluster with two .NET applications. First one will send messages to Apache Kafka while the second one will read those messages and store them in Redis. Communication to Kafka and Redis will be realized using the Dapr Client, which means that we will not have any dependencies on NuGet packages like Confluent.Kafka
or StackExchange.Redis
.
Architecture diagram
Prerequisites
This demo requires you to have the following installed on your machine:
- Kubernetes CLI kubectl
- Kubernetes cluster, such as Minikube or Docker Desktop
Also, clone the repository and cd
into the right directory:
git clone https://github.com/cvitaa11/dapr-demo
cd dapr-demo
Step 1 - Setup Dapr on your Kubernetes cluster
The first thing you need is an RBAC enabled Kubernetes cluster. This could be running on your machine using Minikube/Docker Desktop, or it could be a fully-fledged cluser in Azure using AKS or some other managed Kubernetes instance from different cloud vendor.
Once you have a cluster, follow the steps below to deploy Dapr to it. For more details, look here
$ dapr init -k
⌛ Making the jump to hyperspace...
ℹ️ Note: To install Dapr using Helm, see here: https://docs.dapr.io/getting-started/install-dapr-kubernetes/#install-with-helm-advanced
✅ Deploying the Dapr control plane to your cluster...
✅ Success! Dapr has been installed to namespace dapr-system. To verify, run `dapr status -k' in your terminal. To get started, go here: https://aka.ms/dapr-getting-started
The dapr
CLI will exit as soon as the kubernetes deployments are created. Kubernetes deployments are asyncronous, so you will need to make sure that the dapr deployments are actually completed before continuing.
Step 2 - Setup Apache Kafka
The easiest way to setup Apache Kafka on your Kubernetes cluster is by using Helm package manager. To install Helm on your development machine follow this guide.
We will use Bitnamy Library for Kubernetes to launch Zookeper and Kafka message broker.
helm repo add bitnami https://charts.bitnami.com/bitnami
helm install my-release bitnami/kafka
Step 3 - Setup Redis
Just like Apache Kafka, easy way to spin up Redis on your Kubernetes cluster is by using Helm.
helm repo add bitnami https://charts.bitnami.com/bitnami
helm install redis bitnami/redis
To verify the installation of Kafka and Redis run kubectl get all
and you should see similiar output:
NAME READY STATUS RESTARTS AGE
pod/my-release-kafka-0 1/1 Running 0 18m
pod/my-release-zookeeper-0 1/1 Running 0 18m
pod/redis-master-0 1/1 Running 1 11m
pod/redis-slave-0 1/1 Running 1 11m
pod/redis-slave-1 1/1 Running 1 11m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 15d
service/my-release-kafka ClusterIP 10.110.225.238 <none> 9092/TCP 18m
service/my-release-kafka-headless ClusterIP None <none> 9092/TCP,9093/TCP 18m
service/my-release-zookeeper ClusterIP 10.99.95.252 <none> 2181/TCP,2888/TCP,3888/TCP 18m
service/my-release-zookeeper-headless ClusterIP None <none> 2181/TCP,2888/TCP,3888/TCP 18m
service/redis-headless ClusterIP None <none> 6379/TCP 11m
service/redis-master ClusterIP 10.111.109.148 <none> 6379/TCP 11m
service/redis-slave ClusterIP 10.111.66.85 <none> 6379/TCP 11m
NAME READY AGE
statefulset.apps/my-release-kafka 1/1 18m
statefulset.apps/my-release-zookeeper 1/1 18m
statefulset.apps/redis-master 1/1 11m
statefulset.apps/redis-slave 2/2 11m
Step 4 - Create Dapr components in Kubernetes cluster
To deploy pub/sub and state store components make sure you are positioned in the right directory and then apply Dapr YAML manifests.
cd dapr-components
kubectl apply -f .\kafka.yaml
kubectl apply -f .\redis.yaml
Step 5 - Deploy .NET Core applications
Now when all prerequisites are ready we can deploy our apps. To deploy .NET Core publisher and consumer applications make sure you are positioned in the right directory and then apply Kubernetes manifests.
cd k8s
kubectl apply -f .\publisher.yaml
kubectl apply -f .\consumer.yaml
Each manifest contains Deployment
object for the application and Service
object for accessing the application through a browser.
Navigate to the localhost:8081/swagger
and you will se our publisher app with a POST method on MessageController
. This action sends a message to newMessage topic on Kafka pub/sub component. Communication between application and message broker is not performed directly. Dapr is running as a sidecar container inside publisher pod and handles the entire process of sending a message.
Our consumer application is running on localhost:9091
and is subscribed to newMessage topic on Kafka pub/sub component. When new message arrives it reads the content and trough the Dapr client saves it to Redis state store uneder the key message.
To test the entire process we can run Redis client pod and check if content is stored. First of all we will export password to REDIS_PASSWORD variable:
export REDIS_PASSWORD=$(kubectl get secret --namespace default redis -o jsonpath="{.data.redis-password}" | base64 --decode)
Then run the client with the following command:
kubectl run --namespace default redis-client --rm --tty -i --restart='Never' \
--env REDIS_PASSWORD=$REDIS_PASSWORD \
--image docker.io/bitnami/redis:6.0.12-debian-10-r3 -- bash
and connect using Redis CLI:
redis-cli -h redis-master -a $REDIS_PASSWORD
Now that you are connected to Redis you can use command HGETALL message
that will return content of the message we sent to Kafka. With this we have confirmed that the whole process works.
If you want to find out more about Dapr, the best place to start is the official documentation.
Top comments (0)