Friday, October 9, 2015

How to deploy a Hello World node.js app from your laptop to IBM BlueMix


Introduction

I recently had the opportunity to begin learning IBM BlueMix.

To get started, I wanted to deploy a trivial Hello World program written in javascript/node.js.  And I wanted to do as many tasks as possible from the command line instead of the BlueMix web interface, because the web interface is useless for scripting and automation.

It wasn't easy.  I couldn't find complete and simple docs that worked.  Many docs I found were out-of-date, or focused on selling services.  It took me two days, working sporadically, to figure this out.  Thankfully, I found answers from bloggers (links included below).

Caveats
The steps below worked on my Linux laptop (Ubuntu 12.04).  Mac should be similar.

I obfuscated my real email address to myname@example.com for privacy in the listings below.

Prereqs
Required:  Get yourself an account at IBM Bluemix.  https://console.ng.bluemix.net/

Required:  Install the Cloud Foundy command line interface tool, cf, on your laptop.  Fetch it from https://github.com/cloudfoundry/cli/releases  (as of this writing, I installed CF version v6.12.4, Linux 32-bit binary.)  Un-tar it and add it to your path.   IBM Doc:  https://www.ng.bluemix.net/docs/starters/install_cli.html 

Recommended:  Install node.js on your laptop and add it to your path.   https://nodejs.org/en/  Reason:  It can be used to test the hello world locally on your laptop.

Part 1.  Prepare node.js app on your laptop

First create a node.js app and package.json file in the same folder on your laptop...

Create a new folder on your laptop for the app.

Create a file in that folder named hellohttp.js.  I found a trivial HTTP server app written by Tim Caswell.  Browse here and search for 'Hello HTTP':  http://howtonode.org/hello-node     Paste the contents into the file and save it.

Important: To support port mapping within BlueMix, edit the app to use environment variable VCAP_APP_PORT as shown below.  This code will listen on port 8000 on your laptop (where the env var is NOT defined), or on the BlueMix-defined port when deployed to BlueMix (where the env var IS defined)

    // Source:  Hello HTTP by Tim Caswell http://howtonode.org/hello-node

    // Load the http module to create an http server.
    var http = require('http');

    // Configure our HTTP server to respond with Hello World to all requests.
    var server = http.createServer(function (request, response) {
      response.writeHead(200, {"Content-Type": "text/plain"});
      response.end("Hello World\n");
    });

    // Listen on port VCAP_APP_PORT (if defined) or 8000 (default).
    var port = process.env.VCAP_APP_PORT || 8000;
    server.listen(port);

    // Put a friendly message on the terminal
    console.log("Server running at http://127.0.0.1:" + port + "/");


Next create a file named package.json in the same folder as the hello http app.  Copy/paste the following content into the file.  Edit your personal info.

Note: The most important statement in this file is the scripts.start definition.  BlueMix issues this command to start your app.

I found this solution in a blog post by Brian Innes.  Brian documented several ways to start apps in BlueMix.  https://www.ibm.com/developerworks/community/blogs/enablingwithbluemix/entry/confused_about_how_to_specify_a_start_command_for_node_js_application_on_ibm_bluemix?lang=en
Of course, as soon as I discovered Brian's solution, I also found the package.json technique in the official docs:  https://www.ng.bluemix.net/docs/#starters/nodejs/index.html#nodejs   Ugh.

    {
      "name": "hellohttp",
      "version": "0.0.1",
      "description": "hellohttp",
      "author": "myname@example.com",
      "contributors": [
            {    "name": "myname",
                "email": "myname@example.com" }
        ],
      "scripts": {
        "start": "node hellohttp.js"
      }
    }

Local test

    If you installed node.js on your laptop, test the hellohttp.js app by running it locally.
   
        Start
            node hellohttp.js
       
        See response
            Server running at http://127.0.0.1:8000/

        Verify
            netstat -na | grep LIST | grep 8000
            tcp   0   0 0.0.0.0:8000   0.0.0.0:*   LISTEN

        Verify again
            Browse to http://localhost:8000, see response 'Hello World'.

Part 2.  Upload node.js app to BlueMix

From the same folder, issue these Cloud Foundry cf commands...

Set the API

    cf api https://api.ng.bluemix.net

    Get response

        Setting api endpoint to https://api.ng.bluemix.net...
        OK
        API endpoint:   https://api.ng.bluemix.net (API version: 2.27.0)  
        Not logged in. Use 'cf login' to log in.

Log in

    cf login -u myname@example.com -o myname@example.com -s dev
        where -o is org, -u is username (both are the same when you first start using BlueMix), and -s is space dev.
   
    and enter your password when prompted

        Password> ********

    Get response

        Authenticating...
        OK
   
        Targeted org myname@example.comn
   
        Targeted space dev
                      
        API endpoint:   https://api.ng.bluemix.net (API version: 2.27.0)  
        User:           myname@example.com  
        Org:            myname@example.com  
        Space:          dev

Deploy the app.  The command 'cf push' will upload all files in your folder to BlueMix (recursively).

    cf push hellohttp

    Wait a few minutes to receive this entire response...

    Creating app hellohttp in org myname@example.com / space dev as myname@example.com...
    OK
   
    Creating route hellohttp.mybluemix.net...
    OK
   
    Binding hellohttp.mybluemix.net to hellohttp...
    OK
   
    Uploading hellohttp...
    Uploading app files from: /home/myname/sandbox/nodejs/hellohttp
    Uploading 1.1K, 2 files
    Done uploading              
    OK
   
    Starting app hellohttp in org myname@example.com / space dev as myname@example.com...
    -----> Downloaded app package (4.0K)
   
    -----> IBM SDK for Node.js Buildpack v2.5-20150902-1526
           Based on Cloud Foundry Node.js Buildpack v1.5.0
    -----> Creating runtime environment
           NPM_CONFIG_LOGLEVEL=error
           NPM_CONFIG_PRODUCTION=true
           NODE_MODULES_CACHE=true
    -----> Installing binaries
           engines.node (package.json):  unspecified
           engines.npm (package.json):   unspecified (use default)
           Resolving node version (latest stable) via 'node-version-resolver'
           Installing IBM SDK for Node.js (0.12.7) from cache
           Using default npm version: 2.11.3
    -----> Restoring cache
           Loading 1 from cacheDirectories (default):
           - node_modules (not cached - skipping)
    -----> Checking and configuring service extensions before installing dependencies
    -----> Building dependencies
           Pruning any extraneous modules
           Installing node modules (package.json)
    -----> Checking and configuring service extensions after installing dependencies
    -----> Installing App Management
    -----> Caching build
           Clearing previous node cache
           Saving 1 cacheDirectories (default):
           - node_modules (nothing to cache)
    -----> Build succeeded!
           └── (empty)
   
    -----> Uploading droplet (14M)
   
    0 of 1 instances running, 1 starting
    1 of 1 instances running
   
    App started
   
    OK
   
    App hellohttp was started using this command `./vendor/initial_startup.rb`
   
    Showing health and status for app hellohttp in org myname@example.com / space dev as myname@example.com...
    OK

    requested state: started
    instances: 1/1
    usage: 1G x 1 instances
    urls: hellohttp.mybluemix.net
    last uploaded: Wed Oct 7 15:11:49 UTC 2015
    stack: cflinuxfs2
    buildpack: SDK for Node.js(TM) (ibm-node.js-0.12.7)
   
         state     since                    cpu    memory        disk          details  
    #0   running   2015-10-07 11:12:56 AM   0.0%   55.2M of 1G   48.2M of 1G
   
Verify

    Determine the URL for your app.  Browse to the BlueMix web interface, look for your new app, and see the URL (in blue):



    Browse to the URL and see 'Hello World'.  For example, mine was:

        http://hellohttp.mybluemix.net/




Done

It worked.  Claim success.