Technical Articles
How To Deploy a Public MQTT Server in Cloud Foundry using a Docker Image
0. Pre-requirements
- Node.JS installed locally
- Docker installed locally
- Javascript / Node.JS
- Cloud Foundry & Docker minimal knowledge
1. Introduction about MQTT and SAP Cloud Platform
When you are working on an IoT scenario most of the time you have to use an MQTT server.
When the solution needs to be hosted in cloud then your options are limited because most of them are paid services or public servers that anybody can use an publish data.
Within the SAP Cloud Platform you can find RabbitMQ in the Service Marketplace.
It’s a great service but it may be binded to your Cloud Foundry apps and it can’t be exposed as a public service on the internet.
There is an workaround for this limitation of the environment : In Cloud Foundry anyone can deploy Docker Images with a simple bash command.
Working with Node.JS I know that everything may be found on www.npmjs.com. There you can find a standalone MQTT server named mosca
.
More details about this subject can be found in this article
To be able to use a MQTT Server for non-critical data you can apply the following scenario
- create a custom Docker image based on a Linux OS that runs
mosca
- test it with a MQTT client that support WSS (Web Sockets Secure) – see
publisher.js
file below - check the messages with the same client – see
subscriber.js
file below
I used in this example MQTT.js
package for Node.JS.
2. How to create and build a new Docker Image
2.1 Create a file named Dockerfile
and copy/paste/adapt the code below
You can pull the existing Docker Image from here
Dockerfile
content for copy/paste :
FROM ubuntu:18.04
MAINTAINER Radu Simen <radu103@hotmail.com>
RUN ln -fs /usr/share/zoneinfo/Europe/Bucharest /etc/localtime
RUN apt-get update
RUN apt-get install -y nodejs npm
RUN apt-get install -y make gcc g++ python git gyp build-essential
RUN npm install -g npm@latest
RUN node -v
RUN npm -v
RUN npm install -g node-gyp@latest
RUN chmod -R 777 /root
RUN chmod -R 777 /usr/local/lib
RUN npm install -g mosca bunyan
EXPOSE 80
ENTRYPOINT ["mosca", "--http-port", "80", "--http-bundle", "-v"]
2.2 Build and publish the image to the docker hub webpage
Open a new terminal window and navigate to the folder where you saved the Dockerfile
and run :
docker login
docker build ./ -t radu103/mosca:latest -t radu103/mosca:1.0.0`
docker push radu103/mosca:1.0.0
docker push radu103/mosca:latest
2.3 Check the image and run a Docker Container
docker run radu103/mosca:latest
docker ps
You can use also Kitematic
UI to see containers and images.
3. Deploy the Docker Image on SAP Cloud Platform
cf login
cf push <APP_NAME> -m 256M --docker-image radu103/mosca:latest
4. Test the SAP Cloud Platform new deployed app
Run in terminal to see <APP_NAME> logs
cf logs <APP_NAME> --recent
Open a browser and check https://<APP_URL>/mqtt.js
(because mosca is started with –http-bundle flag)
5. Publish and Consume Messages Example with a Node.JS app
5.1 Create a new folder with the folowing files
- File
package.json
{
"name": "stm-mqtt-broker",
"version": "1.0.0",
"description": "",
"main": "publisher.js",
"engines": {
"node": "^8.1.3",
"npm": "^6.1.0"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"mqtt": "^2.18.3"
}
}
2. File publisher.js
var mqtt = require('mqtt');
var mqttHost = 'wss://<APP_NAME>.cfapps.eu10.hana.ondemand.com:443';
var topicName = 'myTopic';
var client = mqtt.connect(mqttHost);
client.on('connect', function () {
setInterval(function() {
var date = new Date();
var message = 'Hello mqtt ' + date.getTime();
client.publish(topicName, message);
date = new Date();
console.log(date.getTime() + ' - Message Sent : ' + message);
}, 5000);
});
client.on('error', function(err) {
console.log(err);
});
3. File subscriber.js
var mqtt = require('mqtt');
var mqttHost = 'wss://<APP_NAME>.cfapps.eu10.hana.ondemand.com:443';
var topicName = 'myTopic';
var client = mqtt.connect(mqttHost);
client.on('connect', function () {
client.subscribe(topicName);
});
client.on('message', function (topic, message) {
context = topic + " : " + message.toString();
var date = new Date();
console.log(date.getTime() + " - " + context);
});
5.2 Run Publisher app and Subscriber app in terminal
npm install
node publisher.js
node subscriber.js
the example was tested and used last summer by a colleague, so it should work
I can confirm that I tested it and it worked.
Hi Radu. Thanks for openning my eyes to so many new possibilities with this post 🙂 I've been playing with this for last two days forgetting about other stuff I need to do...
One quite remark: in
package.json
you do not needmosca
dependency - this makesnpm i
faster and cleaner.Well done!
You're right so I removed it
Hi Radu,
Great blog, Ive looking for this functionality for a while.
Thanks
Kevin