In my previous Microservices PoC post, I attempted to use a calculator to conceptualize microservices. The premise was to look at the calculator as a monolithic application and then break it down into discrete services. The focus was on the Add, Subtract, Multiply, and Divide functions and deploying them in separate docker containers thus creating 4 “microservices.” This post will take you to the next evolution of where we move towards making these services available outside of my local machine.
Requirements:
- Docker installed
While not required, I did switch over to using Raspberry Pi’s for my Docker environment.
As always, let’s create a directory to maintain the files required for this exercise
pi@docker1:~ $ pwd /home/pi pi@docker1:~ $ mkdir -p nodecalc
Next, we will need to create dockerfiles for each of the calculation functions. The significant change in this implementation will be the use of node.js instead of python:
Dockerfile
FROM armhf/ubuntu RUN apt-get update && \ apt-get -qy install wget unzip WORKDIR /root/ RUN wget \ https://nodejs.org/dist/v4.2.4/node-v4.2.4-linux-armv7l.tar.gz RUN tar -xvf node-v4.2.4-linux-armv7l.tar.gz -C /usr/local \ --strip-components=1 RUN npm install -g express ENV NODE_PATH=/usr/local/lib/node_modules/ ADD add2.js . CMD [ "node", "add2.js"]
Save this as “Dockerfile”.
Before going any further let’s see what’s going on in this Dockerfile.
Line 1: Use the Ubuntu image for Raspberry Pi architecture
Line2: Update Ubuntu
Line3: Install wget and unzip
Line6: Set the work directory to root
Line7&8: Download Node.js and untar the the file to the /usr/local directory in the image
Line9: Use node package manager to install the Node.js web application framework Express
Line10: Set the Node_Path environment variable
Line11: Add the file add2.js to the docker image
Line12: Execute the node add2.js command in the container
Now that you know what is happening, create three more dockerfiles. I have used:
- Dockerfile_m
FROM armhf/ubuntu RUN apt-get update && \ apt-get -qy install wget unzip WORKDIR /root/ RUN wget \ https://nodejs.org/dist/v4.2.4/node-v4.2.4-linux-armv7l.tar.gz RUN tar -xvf node-v4.2.4-linux-armv7l.tar.gz -C /usr/local \ --strip-components=1 RUN npm install -g express ENV NODE_PATH=/usr/local/lib/node_modules/ ADD multiply2.js . CMD [ "node", "multiply2.js"]
- Dockerfile_s
FROM armhf/ubuntu RUN apt-get update && \ apt-get -qy install wget unzip WORKDIR /root/ RUN wget \ https://nodejs.org/dist/v4.2.4/node-v4.2.4-linux-armv7l.tar.gz RUN tar -xvf node-v4.2.4-linux-armv7l.tar.gz -C /usr/local \ --strip-components=1 RUN npm install -g express ENV NODE_PATH=/usr/local/lib/node_modules/ ADD subtract2.js . CMD [ "node", "subtract2.js"]
- Dockerfile_d
FROM armhf/ubuntu RUN apt-get update && \ apt-get -qy install wget unzip WORKDIR /root/ RUN wget \ https://nodejs.org/dist/v4.2.4/node-v4.2.4-linux-armv7l.tar.gz RUN tar -xvf node-v4.2.4-linux-armv7l.tar.gz -C /usr/local \ --strip-components=1 RUN npm install -g express ENV NODE_PATH=/usr/local/lib/node_modules/ ADD divide2.js . CMD [ "node", "divide2.js"]
The next step is to use your favorite editor to code our calculator functions in node and invoke a webservice for each of the following:
- add2.js
const express = require('express') const app = express() app.get('/add/', function (req, res) { var id = req.query.id; var array = id.split(' '); var num1 = array[0]; var num2 = array[1]; var total = (+num1) + (+num2); res.send('The answer is: '+total) }) app.listen(3000, function () { console.log('Addition service listening on port 3000!') })
- multiply2.js
const express = require('express') const app = express() app.get('/multiply/', function (req, res) { var id = req.query.id; var array = id.split(' '); var num1 = array[0]; var num2 = array[1]; var total = (+num1) * (+num2); res.send('The answer is: '+total) }) app.listen(3002, function () { console.log('Multiplication service listening on port 3002!') })
- subtract2.js
const express = require('express') const app = express() app.get('/subtract/', function (req, res) { var id = req.query.id; var array = id.split(' '); var num1 = array[0]; var num2 = array[1]; var total = (+num1) - (+num2); res.send('The answer is: '+total) }) app.listen(3001, function () { console.log('Subtraction service listening on port 3001!') })
- divide2.js
const express = require('express') const app = express() app.get('/divide/', function (req, res) { var id = req.query.id; var array = id.split(' '); var num1 = array[0]; var num2 = array[1]; var total = (+num1) / (+num2); res.send('The answer is: '+total) }) app.listen(3003, function () { console.log('Division service listening on port 3003!') })
At a high level each one of the node.js applications will listen on a port and expect an http request. If you wanted to add two number, you will go to your web browser and enter:
http://localhost:3000/add/?id=1 15
Once these files have been created, your directory should look something like this:
pi@docker1:~/nodecalc $ ls add2.js Dockerfile Dockerfile_m multiply2.js divide2.js Dockerfile_d Dockerfile_s subtract2.js
With all this in place, it’s time to build the images. While still in the directory, issue the following commands at the prompt:
docker build -t <username>/<repository> .
My build commands look like this:
docker build -t dbaontap/node-add-app .
docker build -f Dockerfile_s -t dbaontap/node-subtract-app .
docker build -f Dockerfile_m -t dbaontap/node-multiply-app .
docker build -f Dockerfile_d -t dbaontap/node-divide-app .
The first time you run these, Docker will check for the existence of the necessary files on your local machine. If it doesn’t find them, it will download them from the appropriate repository, and execute the commands outlined in the Dockerfile. You will notice that I did not include -f Dockerfile in the “add” example. That is because the default file name is Dockerfile. The other Dockerfiles that are used to build the multiply, subtract, and divide containers need to have the Dockerfile_? explicitly defined. We use the -f flag for that.
docker images at the command prompt should result in the something similar to what we see below:
pi@docker1:~/nodecalc $ docker images REPOSITORY TAG IMAGE ID CREATED SIZE dbaontap/node-divide-app latest 86949bb44c72 4 days ago 200MB dbaontap/node-multiply-app latest 31412c54bac3 4 days ago 200MB dbaontap/node-subtract-app latest fee9704ce45d 4 days ago 200MB dbaontap/node-add-app latest 52f7b73e0b53 4 days ago 200MB armhf/ubuntu latest fa40ea71de37 9 months ago 106MB
Once the images are done, you can deploy each image into a container. Since these have a webservice running in them, we need to define a port for each one to listen on as part of the docker run command:
If you recall, in the node.js code, each calculation service is set to listen internally on a port. We will map the same external port to this internal port using the -p flag.
docker run -p 3000:3000 -d dbaontap/node-add-app
docker run -p 3001:3001 -d dbaontap/node-subtract-app
docker run -p 3002:3002 -d dbaontap/node-multiply-app
docker run -p 3003:3003 -d dbaontap/node-divide-app
At this point you will have docker containers listening ports 3000, 3001, 3002, 3003 each with a specific purpose. The video below will demonstrate how to access your add, subtract, multiply, divide services from a web browser.
For the records, the docker containers are running on the Raspberry Pi’s shown in the photo at the beginning of this post, and I was accessing the services from my MacBook Pro. Where do we go from here? The next step is try and deploy something like this to the Oracle Container Cloud Service. As you can see, while overly simplified, containers can offer some interesting way to deliver services.
As always, the code for this can be found on my github site.
***UPDATE: Check out my post on using docker-compose to simplify the deployment process.
1 Comment