DEV Community

Abhishek Gupta for Microsoft Azure

Posted on

How to connect your Dapr microservices using NATS

Dapr version 0.2.0 comes with a bunch of new components added to the runtime. One such component includes pubsub capability with NATS which is a Go based open source messaging system for cloud native applications, IoT messaging, and microservices architectures. This blog will provide a step-by-step walk through of how to use it.

the code is available on GitHub as always

We will deploy Dapr on Kubernetes (minikube) and use the NATS server at demo.nats.io for demonstration purposes.

Hello Dapr!

Dapr stands for Distributed Application Runtime. It is an open source, portable runtime to help developers build resilient, microservice stateless and stateful applications by codifying the best practices for building such applications into independent components.

If you're new to Dapr, I would recommend starting off with the overview and concepts. Try the getting-started guide and then move on to samples and how-to guides. As you advance further, you can dig into the Dapr runtime API reference and individual components

Setup

Start by installing the Dapr CLI (you will need Docker to be installed) using the documentation - https://github.com/dapr/docs/blob/master/getting-started/environment-setup.md

If you're on a Mac, simply:

curl -fsSL https://raw.githubusercontent.com/dapr/cli/master/install/install.sh | /bin/bash
Enter fullscreen mode Exit fullscreen mode

Install Dapr to Kubernetes (we'll use minikube to keep things simple). See the docs to install minikube if needed.

Once minikube is setup, make sure you start it

minikube start
Enter fullscreen mode Exit fullscreen mode

Now all you need is a single command to install Dapr on Kubernetes!

dapr init --kubernetes
Enter fullscreen mode Exit fullscreen mode

You should see this message

Success! Dapr has been installed. To verify, run 'kubectl get pods -w' in your terminal
Enter fullscreen mode Exit fullscreen mode

If you want to use Helm for installing Dapr, check https://github.com/dapr/docs/blob/master/getting-started/environment-setup.md#using-helm-advanced

To confirm, use the below command and proceed when Dapr pods are in Running state. The related Pods are Dapr operator, Dapr sidecar injector and Dapr placement

kubectl get pods -w
Enter fullscreen mode Exit fullscreen mode

You are ready to go!

Try Dapr with NATS pubsub

Start by cloning the repo and change to the correct directory

git clone https://github.com/abhirockzz/dapr-nats-pubsub
cd dapr-nats-pubsub
Enter fullscreen mode Exit fullscreen mode

Deploy the NATS pubsub component

A Component is a Dapr CRD (Custom Resource Definition). Here is the configuration - note that we are using the demo NATS server at demo.nats.io:4222 as specified by natsURL

apiVersion: dapr.io/v1alpha1
kind: Component 
metadata:
  name: messagebus-nats
spec:
  type: pubsub.nats
  metadata:
  - name: natsURL
    value: nats://demo.nats.io:4222
Enter fullscreen mode Exit fullscreen mode

To create:

kubectl apply -f deploy/nats-pubsub.yaml
//component.dapr.io/messagebus-nats created
Enter fullscreen mode Exit fullscreen mode

Confirm:

kubectl get component.dapr.io    

NAME              AGE
messagebus-nats   12s
Enter fullscreen mode Exit fullscreen mode

Deploy subscriber application

This is a simple application that subscribes to a subject called testsubject.

http.HandleFunc("/dapr/subscribe", func(w http.ResponseWriter, r *http.Request) {
    response := `["` + natsSubject + `"]`
    fmt.Println("subscribed to NATS subject", natsSubject)
    w.Write([]byte(response))
})
Enter fullscreen mode Exit fullscreen mode

The app itself is defined as a Kubernetes Deployment resource. It uses annotations to ensure that the Dapr sidecar container is "injected" inside the Pod along with the application container

dapr.io/enabled: "true"
dapr.io/id: "natsapp"
dapr.io/port: "8080"
dapr.io/log-level: "debug"
Enter fullscreen mode Exit fullscreen mode

To create the app:

kubectl apply -f deploy/app.yaml
Enter fullscreen mode Exit fullscreen mode

The Deployment uses a pre-built Docker image (abhirockzz/dapr-nats-pubsub), but you can build your own using the Dockerfile provided in the nats-app folder

Check the new Pod and wait for it to transition to Running state

kubectl get pods -l=app=natsapp -w
Enter fullscreen mode Exit fullscreen mode

At this point, you can check the logs for the app as well as the Dapr sidecar container

//for the app
kubectl logs <POD_NAME> -c natsapp

//logs for the Dapr sidecar
kubectl logs <POD_NAME> -c daprd
Enter fullscreen mode Exit fullscreen mode

For the app, you should just see the following logs which indicate that the application has subscribed to the NATS subject and is listening for further messages

starting HTTP server....
subscribed to NATS subject testsubject
Enter fullscreen mode Exit fullscreen mode

For the Dapr sidecar, you should see something on these lines - notice that the NATS pusbsub component is set up properly and Dapr has been able to connect to NATS and subscribe to NATS server specified in the component.

time="2019-11-19T10:00:18Z" level=info msg="starting Dapr Runtime -- version 0.2.0 -- commit c75b111"
time="2019-11-19T10:00:18Z" level=info msg="log level set to: debug"
time="2019-11-19T10:00:18Z" level=info msg="kubernetes mode configured"
time="2019-11-19T10:00:18Z" level=info msg="dapr id: natsapp"
time="2019-11-19T10:00:19Z" level=info msg="loaded component messagebus-nats (pubsub.nats)"
time="2019-11-19T10:00:19Z" level=info msg="application protocol: http. waiting on port 8080"
time="2019-11-19T10:00:19Z" level=info msg="application discovered on port 8080"
time="2019-11-19T10:00:20Z" level=debug msg="connected to nats at nats://demo.nats.io:4222"
time="2019-11-19T10:00:20Z" level=debug msg="nats: subscribed to subject testsubject with queue group natsapp"
time="2019-11-19T10:00:20Z" level=warning msg="failed to init actors: actors: state store must be present to initialize the actor runtime"
time="2019-11-19T10:00:20Z" level=info msg="http server is running on port 3500"
time="2019-11-19T10:00:20Z" level=info msg="gRPC server is running on port 50001"
time="2019-11-19T10:00:20Z" level=info msg="dapr initialized. Status: Running. Init Elapsed 1211.203177ms"
Enter fullscreen mode Exit fullscreen mode

Start tailing the application logs, as you will need to check the end to end functionality

kubectl logs -f <POD_NAME> -c natsapp
Enter fullscreen mode Exit fullscreen mode

Deploy the client application

The client application is a React front end app which has been picked up from the Dapr samples repo and has been modified ever so slightly for the purposes of this scenario

Switch to a new terminal to deploy the client app. This too is a Kubernetes Deployment. It additionally includes a LoadBalancer so that we can access the app in our browser

kubectl apply -f deploy/react-app.yaml
Enter fullscreen mode Exit fullscreen mode

Wait for the application to be deployed

kubectl get pods -l=app=react-form -w
Enter fullscreen mode Exit fullscreen mode

Once it's deployed, you are ready to check the end to end flow of events.

Produce/publish messages using the front end app

Since we're using minikube, we can open React app in a browser with:

minikube service react-form
Enter fullscreen mode Exit fullscreen mode

You should see the following screen:

testsubject is the NATS subject we want to send messages to (ignore the other ones in the dropdown). Simply enter the message and press the Submit button. This will use the publisher part of the NATS pubsub component and send a message to the NATS server at demo.nats.io:4222

Check the other terminal where the subscriber application logs are being tailed - you should see the logs along with the message you sent e.g.

Recieved Message from NATS - {"id":"48825607-1f10-4789-8d99-84b927c1900e","source":"react-form","type":"com.dapr.event.sent","specversion":"0.3","datacontenttype":"application/json","data":{"messageType":"testsubject","message":"looking dapr"}}
Enter fullscreen mode Exit fullscreen mode

The message is encapsulated within the Cloud Events payload. You can send a few more messages and double-check the results.

Horizontal scaling...

So far we just had one subscriber app instance. The NATS pubsub component in Dapr works as a queue subscriber, meaning that you can spawn more instances and the events from the NATS server will be distributed amongs them. This is results in a horizontally scalable system

To scale up our Deployment:

kubectl scale deployment/natsapp --replicas=2
Enter fullscreen mode Exit fullscreen mode

Wait for the new application Pod to start

kubectl get pods -l=app=natsapp -w
Enter fullscreen mode Exit fullscreen mode

Once it's ready, start tailing the logs, just like you did for the first instance

kubectl logs -f <NAME_OF_NEW_POD> -c natsapp
Enter fullscreen mode Exit fullscreen mode

Send messages using the front end app and confirm that they will be distributed among both the instances. You can scale out the app even further and confirm that the behavior remains the same.

What about a different application?

Imagine you had a totally different application that also wanted to process messages from the same subject but process them differently compared to the existing app. Well, you can create a new Dapr powered app in the same way as the existing one, include your processing logic and deploy it to Kubernetes. It will also receive the same set of messages which the earlier app did.

Summary

In this blog post, you saw how to use NATS as a pubsub layer for communication amongst your Dapr apps. Your app was not even aware of NATS - all it did was to interact with the Dapr runtime (just a sidecar) using the Dapr HTTP API!

It is also possible to do it using gRPC or language specific SDKs

As the time of writing, Dapr is in alpha state (v0.2.0) and gladly accepting community contributions 😃 Vist https://github.com/dapr/dapr to dive in!

If you found this article helpful, please like and follow 🙌 Happy to get feedback via Twitter or just drop a comment.

Top comments (2)

Collapse
 
ldeny profile image
ldeny

Thanks Abhishek, very interesting. For the component, is it possible to use a NATS server requiring authentication?

Collapse
 
abhirockzz profile image
Abhishek Gupta

It's not yet possible. Feel free to raise an issue here github.com/dapr/components-contrib and would be awesome if you can send a pull request :-)