A step-by-step guide to implementing two microservices using Docker containers and WAS Liberty.

Microservices is an architectural style in which large complex software applications are broken down into a collection of independent, loosely coupled services. Starting points to learn about microservices include an excellent blog post by Martin Fowler and the IBM Redbooks publication. Also, review the 12-factor app for microservices article by Kate.

Docker containers wrap up a piece of software in a complete filesystem that contains everything it needs to run: code, runtime, system tools, system libraries – ensuring that it will run consistently across all environments – on-premises/public cloud/private cloud/VMWare etc.

Building two microservices using Docker containers

In this article, we will put Docker and microservices together using an example microservices application composed of two services, Inventory and Billing. Each service will run in its own Docker container, and will communicate using lightweight REST APIs.

Microservices are small and focused, meaning that each service is responsible for one task. Technology choices can vary from service to service, but should be made based on what it is the service has to do, for example choosing between a Relational or NoSQL datastore based on the type of data the service interacts with. The software stack for the services in our example include the following components:

  • Inventory microservice
    • runtime: Node.js
    • database: node-json-db and node.js REST client
  • Billing microservice
    • runtime: WAS Liberty
    • database: Apache Derby


1

Kitematic – a GUI for Docker

Before we start, you need to get an account on Docker Hub.

Also, download and install Kitematic, an easy and useful GUI-based tool for running Docker containers.

After installing Kitematic, start the application, which starts a Linux VM that is needed to run Docker containers:


2

On the home page, search for the Ubuntu image and click Create to create a container for the image:


3

Now, we’ll build two Docker images, one for the Inventory microservice and another for the Billing microservice. You can use Dockerfile to automatically build Docker images (see Running Liberty profile in a Docker container for a detailed example of building a Docker image for running WAS Liberty).

Creating the Billing microservice

To build the Docker image for the Billing microservice, create a Dockerfile and add the following lines:

FROM ubuntu

ADD wlp-extended-8.5.5.6.jar /root/
ADD wlp-runtime-8.5.5.6.jar /root/
ADD BillingMicroservice.war /root/
ADD db-derby-10.11.1.1-bin.tar.gz /root/

RUN apt-get update
RUN apt-get install -y default-jre
RUN java -jar /root/wlp-runtime-8.5.5.6.jar --acceptLicense /root/
RUN java -jar /root/wlp-extended-8.5.5.6.jar --acceptLicense /root/
EXPOSE 9080

Download the Liberty runtime and Liberty Extended Programming Models from the Liberty Repository. Download Apache Derby from this link

Download the attached the WAR for the Billing microservice from here BillingMicroservice.war

Place the Dockerfile and the other four files in the same directory somewhere in your local file system. You should now see the following 5 files on your filesystem:

  • BillingMicroservice.war
  • db-derby-10.11.1.1-bin.tar.gz
  • Dockerfile
  • wlp-extended-8.5.5.6.jar
  • wlp-runtime-8.5.5.6.jar

Next, from the Kitematic console, click DOCKER CLI to bring up the command line interface for working with Docker images:


5

In the shell, type the command docker images and you should see the following output:

REPOSITORY        TAG               IMAGE ID          CREATED           VIRTUAL SIZE
ubuntu            latest            d2a0ecffe6fa      2 weeks ago       188.4 MB

Next, navigate to the directory where you placed the Dockerfile and the other software downloads and issue the command:

docker build -t anandnatraj/wlp .

Note that the -t flag allows us to tag our successfully built image with a name. In my case, the anandnatraj also corresponds to the name of my private registry on Docker Hub, making it easy when to push my image to Docker Hub. This step will usually take a few minutes. At the end, you should see a message:

Successfully built ab6b3dd7be8f

Let’s now explicitly publish our container’s exposed ports to specified ports on the host machine by issuing the following command:

docker run -p 1930:9080 anandnatraj/wlp

What we’re going to do next is a bit of a workaround. Since the current version of Kitematic does not import local Docker images, we have to publish our image to Docker Hub and import it back to the local machine using Kitematic. Also, since the Docker image now contains licensed code, you cannot publish it to the public registry on Docker Hub. So create a private registry on Docker Hub and push your Docker image to it by issuing the following command (in this case, the name of the private registry is anandnatraj):

docker push anandnatraj/wlp

This step takes several minutes, so #coffeetime.

Log into Docker Hub and ensure your image has been published successfully.


6

Next, go back to the Docker CLI shell and remove the existing local Docker image because we will download it from Docker Hub in the next step:

docker rmi anandnatraj/wlp

Now, launch the Kitematic console. Ensure you are signed into it using your Docker Hub account. Click My Repos on the top-left-hand corner and you should see the image you just pushed to Docker Hub. If you don’t see it, try signing out and signing back into Kitematic.

Click Create to download the image to your local machine and create a Docker container:


7

Once the download is complete, click EXEC to launch a shell to work with the Docker container:


8

Navigate to the /root directory and ensure you can see the files you added to the Docker image:


9

Now, the Billing microservice Docker container is almost ready. Next we have to start the Derby database and install the BillingMicroservice app on the WAS Liberty server.

So, navigate to /root/db-derby-10.11.1.1-bin/bin and type the following command to start the Derby database and to start the database:

./startNetworkServer

You’ll see the following message when it’s started:

Sun Jul 26 22:16:51 UTC 2015 : Apache Derby Network Server - 10.11.1.1 - (1616546) started and ready to accept connections on port 1527

If needed, you can launch another shell for the Docker container by selecting the wlp image and selecting EXEC on the Kitematic console.

Let’s now create a Liberty server by issuing the following command:

./server create mylibertyserver

Don’t start the server yet.

Install the BillingMicroservice app by copying it into the Liberty server’s dropins directory:

cp /root/BillingMicroservice.war /root/wlp/usr/servers/mylibertyserver/dropins/.

Before you start the server, navigate to /root/wlp/usr/servers/mylibertyserver and open the server.xml file. Replace all its contents and with the following lines:

<?xml version="1.0" encoding="UTF-8"?>
<server description="new server">
    <!-- Enable features -->
    <featureManager>
           <feature>jaxrs-1.1</feature>
           <feature>jsp-2.2</feature>
           <feature>localConnector-1.0</feature>
    <feature>jsp-2.2</feature>
    </featureManager>

    <!-- To access this server from a remote client add a host attribute to the following element, e.g. host="*" -->
    <httpEndpoint id="defaultHttpEndpoint"
                  host="*"
                  httpPort="9080"
                  httpsPort="9443" />
    <webApplication id="BillingMicroservice" location="BillingMicroservice.war" name="BillingMicroservice"/>
</server>

Start the Liberty server:

./server start mylibertyserver

Now, ‘Docker-izing’ the BillingMicroservice is complete. The service itself is very simple. It performs the following functions:

  1. Inserts Billing Information to the Apache Derby database.
  2. Returns a status (always “verified” to keep things simple).
  3. Exposed as a JAX-RS service. See How to create a simple JAX-RS servlet.

I pasted the skeleton code below for your reference. Note, you can use sample code from Apache to customize the java code below to access a derby database sample code in the Apache Derby documentation:

package net.wasdev.jaxrs;

import java.util.HashMap;
import java.util.Map;

import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@Path("Billing/microservice")
public class Billingmicroservice {

	private static String status = "verified";

	@POST
	@Produces(MediaType.APPLICATION_JSON)

	public Map<String, String> getSystemProperties(Map<String, String> input) {

		System.out.println("Insert records to Apache Derby database");
		/*
		 * Apache Derby database record insert
		 */
		Map<String, String> result = new HashMap<>();
		result.put("result", status);
		return result;

	}

}

Creating the Inventory microservice

In the next step, let’s build another Docker image with the Inventory microservice running on Node.js. On your host machine, create a new Dockerfile for the Inventory microservice image with the following lines:

FROM ubuntu
ADD InventoryMicroservice.js /root/
ADD createDB.js

As before, ensure the Dockerfile and the other dependencies are in the same directory in your host machine. Download createDB.js and InventoryMicroservice.js from here: Inventory Microservice Downloads

The following screenshot shows the Dockerfile and other dependencies in the same directory on the filesystem of your host machine:

  • createDB.js
  • Dockerfile
  • InventoryMicroservice.js

Launch a command shell from your host machine and navigate to the directory where you placed for the Dockerfile for the node image. Then build and push the image by issuing the following commands (note that a free account on Docker Hub allows you to only keep one image, so you may need to delete the previous image before pushing this new one):

docker build -t anandnatraj/node .

docker push anandnatraj/node

After pushing the image to Docker Hub, you can remove the local image, since we will be getting it back from Docker Hub (remember the work around we used above to get around the restriction of Kitematic not being able to pull images from a local registry).


11

docker rmi anandnatraj/node

These steps, will take several minutes, so #coffeetimeagain.

Again, log in to your Docker account to ensure the image made it through successfully:


12

Now, launch the Kitematic console. Ensure you are signed into it using the Docker Hub account. Click My Repos on the top-left-hand corner and you should see the image you just pushed to Docker Hub. If you don’t see it, try signing out and signing back into Kitematic. Click Create to download the image to your local machine and create a Docker container:


13

Once the download is complete, click EXEC to launch a shell to work with the Docker container.


14

Navigate to the /root directory and ensure you can see the file you added to the Docker image. Issue the following commands to install the Node REST Client and Node JSON DB modules:

apt-get update

apt-get install nodejs [ Hit Y to continue if prompted] 

apt-get install npm [ Hit Y to continue if prompted]

npm install node-rest-client

npm install node-json-db –save

The Inventory microservice has now been successfully “Docker-ized” as well. One small step is to update the end-point of the Billing microservice.

Open the Inventory microservice:

vi InventoryMicroservice.js

Replace the line:

client.registerMethod("getBillingInfo", "http://localhost:32768/BillingMicroservice/rest/Billing/microservice", "POST");

With the following line:

client.registerMethod("getBillingInfo", "http://192.168.99.100:32768/BillingMicroservice/rest/Billing/microservice", "POST");

You can get the exposed HTTP port of BillingMicroservice from the Kitematic console:


15

Create the required database for the Inventory service and then run the Inventory microservice:

nodejs createDB.js

nodejs InventoryMicroservice.js

You should see the following output:


16

The Inventory microservice is very simple. It performs two simple functions:

  1. Updates the Inventory information to a local node JSON DB.
  2. Invokes BillingMicroservice running inside another Docker container using the lightweight REST API.

I pasted the code for the Inventory microservice here for your reference. The code for InventoryMicroservice is adapted from the sample code for node-rest-client and the code for createDB.js is adapted from sample code for node-json-db on www.npmjs.com.

var Client = require('node-rest-client').Client;
var client = new Client();

var myargs = {
  data: { Name: "Anand",
          Address:"Austin",
          Age:"Nice-try !",
          SSN:"123",
        },
  headers:{"Content-Type": "application/json"}
};

var myJSONDB = require('node-json-db');
var mydb = new myJSONDB("InventoryDataBase", true, false);
mydb.push("/Inventory",myargs);

client.registerMethod("getBillingInfo", "http://localhost:32768/BillingMicroservice/rest/Billing/microservice", "POST");

client.methods.getBillingInfo(args, function(data,response){
  console.log(data);
});

Also, login to the shell for the Liberty container and navigate to /root/wlp/usr/servers/mylibertyserver/logs. Cat the console.log file and you should see the following output indicating the BillingMicroservice was successfully invoked:


17

Conclusion

Docker and microservices form a very powerful combination. In this article, we examined a very simple example of running a microservices app in Docker containers. This simple microservices app consists of two microservices, Inventory and Billing, communicating via lightweight REST APIs.

Join The Discussion

Your email address will not be published. Required fields are marked *