How to connect your Dapr microservices using NATS
Tags: opensource, showdev, tutorial, kubernetes
Published: 2019-11-19 12:30:45

[Dapr version 0.2.0](https://github.com/dapr/dapr/blob/master/docs/release_notes/v0.2.0.md) comes with a bunch of [new components added to the runtime](https://github.com/dapr/dapr/blob/master/docs/release_notes/v0.2.0.md#dapr-runtime). One such component includes pubsub capability with [NATS](https://nats.io/) which is a [Go based](https://golang.org/) 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](https://github.com/abhirockzz/dapr-nats-pubsub) as always

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

![](https://thepracticaldev.s3.amazonaws.com/i/mml7r8815pr7u7bpi4y7.jpg)

## Hello Dapr!

[**Dapr**](http://dapr.io/) 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](https://github.com/dapr/docs/blob/master/overview.md) and [concepts](https://github.com/dapr/docs/tree/master/concepts). Try the [getting-started guide](https://github.com/dapr/docs/tree/master/getting-started) and then move on to [samples](https://github.com/dapr/samples/blob/master/README.md) and [how-to guides](https://github.com/dapr/docs/tree/master/howto). As you advance further, you can dig into the [Dapr runtime API reference](https://github.com/dapr/docs/tree/master/reference/api) and [individual components](https://github.com/dapr/components-contrib)

## Setup

Start by installing the [Dapr CLI](https://github.com/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
```

Install `Dapr` to `Kubernetes` (we'll use `minikube` to keep things simple). See [the docs to install minikube](https://kubernetes.io/docs/setup/learning-environment/minikube/) if needed.

Once `minikube` is setup, make sure you start it

```
minikube start
```

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

```
dapr init --kubernetes
```

You should see this message

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

> 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
```

You are ready to go!

![](https://media.giphy.com/media/gGldiUgAUOJ04g1Ves/giphy-downsized.gif)

## 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
```

### 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
```

To create:

```
kubectl apply -f deploy/nats-pubsub.yaml
//component.dapr.io/messagebus-nats created
```

Confirm:

```
kubectl get component.dapr.io    

NAME              AGE
messagebus-nats   12s
```

### 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))
})
```

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"
```

To create the app:

```
kubectl apply -f deploy/app.yaml
```

> 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
```

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
```

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
```

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"
```

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

```
kubectl logs -f <POD_NAME> -c natsapp
```

### Deploy the client application

The client application is a React front end app which has been picked up from the [Dapr samples repo](https://github.com/dapr/samples) 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
```

Wait for the application to be deployed

```
kubectl get pods -l=app=react-form -w
```

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
```

You should see the following screen:

![](https://thepracticaldev.s3.amazonaws.com/i/8u794hr4mjzxc86ouvfh.png)

`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"}}
```

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
```

Wait for the new application `Pod` to start

```
kubectl get pods -l=app=natsapp -w
```

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
```

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!

![](https://media.giphy.com/media/ASd0Ukj0y3qMM/giphy.gif)

If you found this article helpful, please like and follow 🙌 Happy to get feedback via [Twitter](https://twitter.com/abhi_tweeter) or just drop a comment.