Monday, August 31, 2015

NodeJS App running on IBM Container hosted on Bluemix

In this post, I'll develop a simple nodejs app, that does no more than saying 'Hello World' and run this app from a IBM container on Bluemix. The purpose of this blog entry is to use the IBM Container Extension (ice, for short) to build a docker image and run it on Bluemix. I have attempted to make it step by step, do-it-yourself kind of a post with screenshots as applicable. If you have any questions, drop a comment and I'll answer it. Let's get started.

Pre-req:
  1. Valid Bluemix account. In case you don't have it, sign up for a 30 day trial on http://bluemix.net. Create a namespace/private repo by clicking the containers icon on the dashboad, this is a one time activity and your images will be stored in registry.ng.bluemix.net/
  2. Cloud Foundry command line installed. You can download the installer for your OS from https://github.com/cloudfoundry/cli#downloads.
  3. Docker installed on your machine. I'd be using docker toolbox (Docker 1.8.1) but the commands would work fine with boot2docker (Docker 1.7) as well.
  4. IBM Container extension. You'd need to install python and use pip to get the ice CLI. If you are using a Mac OS (like me) install Homebrew that'd take care of installing setuptools and pip. If you are using Windows, follow the instructions on this URL - https://developer.ibm.com/answers/questions/201614/how-to-install-the-ice-cli-to-manage-containers-on.html. Note: I prefer to use ice for all the container extension commands, you can use cf ic as well.
After installing the pre-reqs, check the installations using the docker -v and ice version commands from the terminal or command prompt, you should see something similar to the image below

 Start the docker daemon using docker-machine start default, note that default is the name of my vm, it is the vm that is installed by docker toolbox. From the terminal set the required environment variables for the docker client on the terminal, using docker-machine env default command, alternately you can wrap it inside an eval on terminal if you are using Mac.

After starting the docker daemon and having the docker client ready, issue the ice login command. This will prompt for the username and password, key in your Bluemix credentials and you should see that Login succeeded.

 Now, get the list of images available by issuing ice images command, this will bring up all the available images from the repository.
Spend a moment going over the available list of images.
Pull the ibmnode image, I'll be using this as the based image to create an image with my nodejs app.
Type ice --local pull registry.ng.bluemix.net/ibmnode:latest. Note that --local flag will execute the commands using the docker client targeting the docker daemon. This might take sometime based on your network connection speed, wait till you see the message "status: Downloaded newer image for registry.ng.bluemix.net/ibmnode:latest".

Run the image using either docker run or ice --local run, I'll use docker run and enter the root of the image to check the nodejs version. This image of IBM Container comes pre-installed with nodejs, otherwise, we need to install it using the apt-get commands on the base image. Type docker run -i -t registry.ng.bluemix.net/ibmnode:latest /bin/bash, this will take you the bash shell of the image and type node -v for the version of nodejs, you should see like the one below:

You can exit the bash shell using exit command and for the house keeping, use docker rm to remove any unused containers, get a list of containers using docker ps -a to display all stopped containers.

Lets build our nodejs app, for brevity, I have excluded the package.json file as this is a simple app, copy the following in to a file called hello.js, this is a simple script that starts the http server on port 9080 and print Hello World when invoked.


Create the Dockerfile with the following content, will use the ibmnode as the base image and copy the hello.js file to it, the last line starts the node with hello.js.



Now, lets build an image, open the terminal from the directory where the hello.js and Dockerfile are located and issue the command ice --local build -t {image name} . , the trailing '.' denotes the current directory. This will build a local image and watch for the message 'Successfully built '. Run the image locally with ice --local run -p 9080:9080 -d {image name}. The -p flag binds the port of the host with that of the container and -d runs the container in daemon mode. Get the ip of the docker machine and use the curl command to check the node app, all three are shown in the below image:

After confirming that the image is ready, it can be pushed to the registry on Bluemix. Before pushing the image needs to be tagged, type the command ice --local tag -f registry.ng.bluemix.net/{your namespace}/{image name}. Now push the image using ice --local push registry.ng.bluemix.net/{your name space}/{image name} and wait for the success message. Check that your image is pushed using the ice images command.
Run your image on Bluemix using the run command (no local flag):
ice run -name -p 9080 registry.ng.bluemix.net/{name space}/{image name}. This will print a container id, save it for further use. Optional: check your container running
using the ice ps command.

For any diagnostic purposes, you can use ice inspect that will print a JSON string with all the properties of the container. Support team usually asks for this log stack to troubleshoot.

Now, lets bind our container to a public ip.
Request a public ip using ice ip request, this will print an available floating ip. Bind the ip to the container using ice bind {ip} {container id} . Now, you access your nodejs page using the ip:9080 from the browser. That's it, you just deployed your nodejs app running from a container on Bluemix.

Note: If you plan to release the floating ip, use ice unbind {ip} and ice release {ip} commands.

No comments: