A Node.js Developer's Guide to Bluemix
-
Upload
ibm-websphere-software -
Category
Technology
-
view
1.398 -
download
2
Transcript of A Node.js Developer's Guide to Bluemix
NodeConf EU Workshop
James M Snell <[email protected]> <[email protected]>
A Node.js Developer's Guide to Bluemix
Getting Started
3
James M Snell
@jasnell on Github and Twitter
IBM Technical Lead for Node.js
TSC Member
4
http://bluemix.net/
Sign up for Free Trial Account:
http://ibm.co/1M05AMX
(go ahead, it only takes a couple minutes)
5
Node.js v0.12.7 or higher
Bluemix supports Node.js v0.12.7 by default(If you want to use Node v4.0.0 locally, go for it.)
6
$ npm install –g bluemix-workshop$ bluemix-workshop
(This is a nodeschool style workshopper that runs with a minimal UI.)
7
What is Bluemix?The Five Minute or Less Introduction
9
Bluemix is IBM's Platform-as-a-Service Offering.
It's built on top of Cloud Foundry.
It also uses Docker and OpenStack (but we're not covering those today)
10
With Bluemix, you write applications and deploy ("push") them to the server.
Bluemix manages the details– Provisioning VMs – Setting up the Containers– Routing,– Load-Balancing,– Scaling,– Configuring Services, etc
11
12
13
Bluemix can run in a Shared or Dedicated Environment
14
Services Services Services Services
15
"Buildpack" – a collection of scripts that prepare code for execution in Bluemix.
…tells Bluemix how to set up the VM, Container and Runtime for your application to run.
For Node.js applications deployed to Bluemix, the default Buildpack is "sdk-for-nodejs"
Install the CLI
17
You will interact with Bluemix using both the browser-based UI and the Cloud Foundry cf command line client.
Visit:
https://github.com/cloudfoundry/cli/releases
Once installed, cf will be added to your PATH. You may need to restart your terminal session to pick up the change.
$ cf -version
Setting the API Endpoint
19
Once the cf command line tool is installed, you have to tell it about the Bluemix endpoint.
First, what region are you in?
US South (`us-south`):
https://api.ng.bluemix.netEurope United Kingdom (`eu-gb`):
https://api.eu-gb.bluemix.net✔
20
Once the cf command line tool is installed, you have to tell it about the Bluemix endpoint.
Second, set the API endpoint and Login
$ cf api https://api.eu-gb.bluemix.net$ cf login
Enter your Bluemix User ID and Password to authenticate
A Simple App
22
$ mkdir helloworld && cd helloworld && npm init
…name: (helloworld)version: (1.0.0)description:entry point: (index.js)test command:git repository:keywords:author:license: (ISC)…Is this ok? (yes)
Remember what you choose here
23
$ vi index.js var http = require('http');
var server = http.createServer(function(req,res) { res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('Hello World');});
server.listen(8888, function() { console.log('The server is running');});
24
$ vi package.json { "name": "helloworld", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "start": "node index" }, "author": "", "license": "ISC"}
Add this part!
25
$ npm start
> [email protected] start /Users/james/tmp/helloworld> node index
The server is running
Adding Bluemix Support
27
$ vi index.js var http = require('http');var server = http.createServer(function(req,res) { res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('Hello World');});server.listen( process.env.VCAP_APP_PORT || 8888, function() { console.log('The server is running'); });
28
$ vi manifest.yml --- applications: - name: {yourappname} mem: 128M instances: 1 path: . host: {yourappname}
Pick something unique for the application name
http://{yourappname}.mybluemix.net
29
$ vi .cfignore node_modules
$ ls –a
.cfignoreindex.jspackage.jsonmanifest.yml
This tells cf not to upload your local node_modules, Bluemix will install them for you.
30
$ cf push
31
http://{yourappname}.mybluemix.net
32
http://snellworkshop.mybluemix.net
Provisioning and Binding Services
34
Services are additional managed capabilities that can be added to an application.
$ cf marketplace
$ cf marketplace –s rediscloud
$ cf create-service rediscloud 30mb myrediscloud
Creates an instance of the rediscloud service within your account.
35
Services are additional managed capabilities that can be added to an application.
$ cf bind-service {yourappname} rediscloud
$ npm install --save redis
Attach the myrediscloud service instance to your application
Add the redis client module to your application.
36
$ vi index.js var http = require('http');var redis = require('redis');var vcap_services = process.env.VCAP_SERVICES;var rediscloud_service = JSON.parse(vcap_services)["rediscloud"][0];var credentials = rediscloud_service.credentials;
var client = redis.createClient( credentials.port, credentials.hostname, {no_ready_check: true});client.auth(credentials.password);client.on('connect', function() { console.log('Connected to Redis');});
var server = http.createServer(function(req,res) { client.get('last-visit', function(err, reply) { res.writeHead(200, {'Content-Type': 'text/plain'}); client.set('last-visit', new Date().toISOString()); res.write('Last Visit: ' + reply + '\n'); res.end('Hello World'); });});server.listen(process.env.VCAP_APP_PORT || 8888, function() { console.log('The server is running');});
37
$ vi index.js var http = require('http');var redis = require('redis');var vcap_services = process.env.VCAP_SERVICES;var rediscloud_service = JSON.parse(vcap_services)["rediscloud"][0];var credentials = rediscloud_service.credentials;
var client = redis.createClient( credentials.port, credentials.hostname, {no_ready_check: true});client.auth(credentials.password);client.on('connect', function() { console.log('Connected to Redis');});
var server = http.createServer(function(req,res) { client.get('last-visit', function(err, reply) { res.writeHead(200, {'Content-Type': 'text/plain'}); client.set('last-visit', new Date().toISOString()); res.write('Last Visit: ' + reply + '\n'); res.end('Hello World'); });});server.listen(process.env.VCAP_APP_PORT || 8888, function() { console.log('The server is running');});
38
$ vi index.js var http = require('http');var redis = require('redis');var vcap_services = process.env.VCAP_SERVICES;var rediscloud_service = JSON.parse(vcap_services)["rediscloud"][0];var credentials = rediscloud_service.credentials;
var client = redis.createClient( credentials.port, credentials.hostname, {no_ready_check: true});client.auth(credentials.password);client.on('connect', function() { console.log('Connected to Redis');});
var server = http.createServer(function(req,res) { client.get('last-visit', function(err, reply) { res.writeHead(200, {'Content-Type': 'text/plain'}); client.set('last-visit', new Date().toISOString()); res.write('Last Visit: ' + reply + '\n'); res.end('Hello World'); });});server.listen(process.env.VCAP_APP_PORT || 8888, function() { console.log('The server is running');});
39
$ vi index.js var http = require('http');var redis = require('redis');var vcap_services = process.env.VCAP_SERVICES;var rediscloud_service = JSON.parse(vcap_services)["rediscloud"][0];var credentials = rediscloud_service.credentials;
var client = redis.createClient( credentials.port, credentials.hostname, {no_ready_check: true});client.auth(credentials.password);client.on('connect', function() { console.log('Connected to Redis');});
var server = http.createServer(function(req,res) { client.get('last-visit', function(err, reply) { res.writeHead(200, {'Content-Type': 'text/plain'}); client.set('last-visit', new Date().toISOString()); res.write('Last Visit: ' + reply + '\n'); res.end('Hello World'); });});server.listen(process.env.VCAP_APP_PORT || 8888, function() { console.log('The server is running');});
40
$ vi index.js var http = require('http');var redis = require('redis');var vcap_services = process.env.VCAP_SERVICES;var rediscloud_service = JSON.parse(vcap_services)["rediscloud"][0];var credentials = rediscloud_service.credentials;
var client = redis.createClient( credentials.port, credentials.hostname, {no_ready_check: true});client.auth(credentials.password);client.on('connect', function() { console.log('Connected to Redis');});
var server = http.createServer(function(req,res) { client.get('last-visit', function(err, reply) { res.writeHead(200, {'Content-Type': 'text/plain'}); client.set('last-visit', new Date().toISOString()); res.write('Last Visit: ' + reply + '\n'); res.end('Hello World'); });});server.listen(process.env.VCAP_APP_PORT || 8888, function() { console.log('The server is running');});
41
$ cf push
The Bluemix Environment
43
Bluemix uses environment variables to configure your application
VCAP_APP_PORT - The TCP Port
VCAP_APP_HOST - The Hostname
VCAP_SERVICES - *JSON* File with Service Details
VCAP_APPLICATION - *JSON* file with Application details
44
Bluemix uses environment variables to configure your application
VCAP_SERVICES:
{ "rediscloud": { "credentials": { ... }, "label": "rediscloud", "name": "myrediscloud", "plan": "30mb", ... }}
45
Bluemix uses environment variables to configure your application
VCAP_APPLICATION:
{ "application_name": "snellworkshop", "application_urls": [ "snellworkshop.mybluemix.net" ], ...}
46
Bluemix uses environment variables to configure your application
$ cf set-env {myappname} MYENVVAR value
$ cf env {myappname}
$ cf unset-env {myappname} MYENVVAR
Enabling Application Management
48
The Application Management Tools are additional utilities for debugging and managing applications
$ cf set-env {yourappname} BLUEMIX_APP_MGMT_ENABLE proxy+devconsole+shell+inspector+trace
$ cf restage {yourappname}
Enables: • a terminal shell for command line
access to your application's container• a node-inspector instance• debug tracing using log4js, bunyan, etc
49
http://{yourappname}.mybluemix.net/bluemix-debug/manage/
50
http://{yourappname}.mybluemix.net/bluemix-debug/manage/
51
http://{yourappname}.mybluemix.net/bluemix-debug/manage/
52
You can enable tracing using log4js or bunyan
$ npm install --save [email protected]
$ vi index.js
...var log4js = require('log4js');log4js.loadAppender('console');var logger = log4js.getLogger('app');logger.setLevel('ERROR');...logger.info('running...');...
53
Set the trace level from within the Bluemix Dashboard…
54
Set the trace level from within the Bluemix Dashboard…
55
Use cf logs to view the trace output
$ cf logs {yourappname}
$ cf logs --recent {yourappname}
Tails the logs to the console
Prints the most recent logs
Using an alternative buildpack(or, how to use newer versions of Node.js)
57
The default Node.js Buildpack uses Node.js v0.12.7, which is good.
But I want to use the new stuff.
The IBM Node.js Buildpack is based on the open source Cloud Foundry Node.js Buildpack. Nearly all Cloud Foundry Buildpacks can work on Bluemix out of the box.
58
The Heroku Node.js Buildpack:
https://github.com/heroku/heroku-buildpack-nodejs.git
Includes support for the latest Node.js/io.js Binaries
59
You specify the alternate buildpack in the manifest.yml
$ vi manifest.yml
--- applications: - name: {yourappname} mem: 128M instances: 1 path: . host: {yourappname} buildpack: https://github.com/heroku/heroku-buildpack-nodejs.git command: node app
60
And tell package.json which version of the Node runtime to use
$ vi package.json
{ "name": "helloworld", "version": "1.0.0", "main": "./app.js", "scripts": { "start": "node app" }, ..., "engines": { "iojs" : "*" }}
61
$ cf push
User-Provided Services
63
Bluemix supports User-Provided Services.
User Provided Services are essentially service configurations you provide. They are kept separate from your application so that they can be shared and managed just like the services provided by Bluemix itself.
User Provided Services provide an excellent way of providing runtime configuration setting to your applications.
64
For instance, suppose we need to configure a secret for our applications:
$ cf cups session-secret -p secret
secret> this is the secretCreating user provided service session-secret in org jasnell / space dev as jasnell...
$ cf bind-service {yourappname} session-secret
$ cf restage
65
User-Provide Service properties are included in the VCAP_SERVICES environment variable, just like any other service.
Using a Custom Domain Name
67
Bluemix supports Custom Domain Names
By default, Bluemix will create a URL for your application automatically.
This usually follows the pattern:
http://{yourappname}.mybluemix.net
But what if you want to use your own domain name?
68
A few command line calls is all you need.
$ cf create-domain myorg example.org
$ cf map-route {yourappname} example.org --n foo
Then create a CNAME DNS record for your sub-domain:
foo.example.org CNAME {yourappname.mybluemix.net}
Once the DNS records propagate, your application will be available at:
http://foo.example.org
69
You can upload your SSL/TLS certificates via the dashboard:
No-downtime deployment
71
Updating an application on Bluemix will cause the application to restart, forcing a small downtime period.
You can avoid it.
$ cf rename {yourappname} {youappname}-old
$ cf push
$ cf delete {yourappname}-old
Resources:
• Bluemix Documentation - https://www.ng.bluemix.net/docs
• developerWorks -http://www.ibm.com/developerworks/cloud/bluemix/
Q&A
Thank you
James M [email protected]@gmail.comtwitter/github @jasnell