Node.js, MySQL and Redis on Cloud Foundry

The Cloud Foundry marketplace provides services that applications deployed into Cloud Foundry can take advantage of. Service plans are added into a Cloud Foundry marketplace by connecting their associated Service Brokers as I described in a previous post.

Recently, I was making a demo Node.js application which used MySQL for storing data and Redis to enable scaled Express session management across application instances. This article is intended to describe how to bind MySQL and Redis service instances to your application deployed into Cloud Foundry. The service brokers used in the Cloud Foundry environment that I deployed the demo Node.js application into were the open source MySQL and Redis service brokers from Pivotal:

cf-mysql-broker: https://github.com/cloudfoundry/cf-mysql-release
cf-redis-broker: https://github.com/pivotal-cf/cf-redis-release

Node.js and Cloud Foundry

To deploy Node.js application into Cloud Foundry the proper buildpack must be available. You can check if the Node.js buildpack is installed in your Cloud Foundry environment by running the following command:

$ cf buildpacks
...
nodejs_buildpack 3 true false nodejs_buildpack-offline-v1.0.4.zip
...

Don’t fret if the Node.js buildpack is not available in your Cloud Foundry environment. There is another way to use the buildpack when you deploy your Cloud Foundry application. When deploying applications into Cloud Foundry we use the `cf` CLI and the `push` command. So to deploy an application with the Node.js buildpack it would look like this:

$ cf push my_app_01 -b https://github.com/cloudfoundry/nodejs-buildpack.git

Adding MySQL to Node.js in Cloud Foundry

As mentioned at the beginning of this article, we will assume that the open source MySQL and Redis service brokers are available in your Cloud Foundry marketplace. You can check if these services are available in your marketplace from a shell:

$ cf marketplace
...
p-mysql 100mb-dev, 1gb-dev A MySQL service for application development and testing
p-redis shared-vm, dedicated-vm Redis service to provide a key-value store

To create a MySQL service instance we can run the following:

$ cf create-service p-mysql 100mb-dev my_service_01

Once we have a service instance we can bind it to our application:

$ cf bind-service my_app_01 my_service_01

Now that the service instance is bound to our application, we need to use the service in our Node.js application. When a service instance is bound to an application it typically puts information on how to connect with the service inside the application’s environment. You can view an application’s environment from a shell like so:

$ cf env my_app_01

Services by convention will put their environment information into the VCAP_SERVICES variable. An example of VCAP_SERVICES might look like the following:

{
"VCAP_SERVICES": {
"p-mysql": [
{
"credentials": {
"hostname": “[some IP]",
"jdbcUrl": "jdbc:mysql://[some IP]:3306/[gen DB name]?user=[gen username]\u0026password=[gen password]",
"name": “[gen DB name]",
"password": “[gen password]",
"port": 3306,
"uri": "mysql://[gen username]:[gen password]@[some IP]:3306/[gen DB name]?reconnect=true",
"username": “[gen username]"
},
"label": "p-mysql",
"name": “my_service_01",
"plan": "100mb-dev",
"tags": [
"mysql"
]
}]
}
}

For MySQL it will provide a full connection URI that can be used by Node.js mysql module to interact with the service instance. To do this, we can write some JavaScript to pull the environment information from VCAP_SERVICES that we need to execute statements against our MySQL service instance. First, we need to install the Node.js mysql module:

$ npm install mysql —save

Next, we need code for local development with the Node.js mysql module. Just put in username, password and database name that you will create for local development.

var mysql = require('mysql');
var connectionInfo = {
user: ‘myuser',
password: ‘aPassword',
database: ‘mydb'
};

Now we will pluck the environment credentials and connection information for our MySQL service instance for when we deploy into Cloud Foundry. We check to see if the VCAP_SERVICES environment variable is defined and that way we know that the application is deployed into Cloud Foundry.

if (process.env.VCAP_SERVICES) {
var services = JSON.parse(process.env.VCAP_SERVICES);
var mysqlConfig = services["p-mysql"];
if (mysqlConfig) {
var node = mysqlConfig[0];
connectionInfo = {
host: node.credentials.hostname,
port: node.credentials.port,
user: node.credentials.username,
password: node.credentials.password,
database: node.credentials.name
};
}
}

We can then create a generic function to execute SQL commands against the MySQL database we’re connected to.

exports.query = function(query, callback) {
var connection = mysql.createConnection(connectionInfo);
connection.query(query, function(queryError, result) {
callback(queryError, result);
});
connection.end();
};

A query using this function might look like:

db.query(‘select * from tasks order by due_date’, function(err, result) {
...
});

Adding Redis to Node.js in Cloud Foundry

Adding Redis is similar to adding MySQL. To create a Redis service instance we can run the following:

$ cf create-service p-redis shared-vm my_cache_01

Once we have a service instance we can bind it to our application:

$ cf bind-service my_app_01 my_cache_01

The VCAP_SERVICES environment information for Redis looks just a little different but is accessed in the same way.

{
"VCAP_SERVICES": {
"p-redis": [
{
"credentials": {
"host": “[some IP]",
"password": “[gen password]",
"port": 55645
},
"label": "p-redis",
"name": “my_cache_01",
"plan": "shared-vm",
"tags": [
"pivotal",
"redis"
]
}]
}
}

Express is not able to share user sessions out of the box across application instances. In order to support shared sessions across application instances we can use Redis with Express on Node.js. The connect-redis module enables the use Redis with Express session management. To install connect-redis run the following:

$ npm install connect-redis —save

Once the connect-redis module is available we can use it in our code. We must send the Express session into connect-redis so that it can enhance session management:

module.exports = function(session) {
var RedisStore = require('connect-redis')(session);
var options = {};

And again we pull out the relevant connection and credentials from the VCAP_SERVICES environment variable available to our application:

if (process.env.VCAP_SERVICES) {
var services = JSON.parse(process.env.VCAP_SERVICES);
var redisConfig = services["p-redis"];
if (redisConfig) {
var node = redisConfig[0];
options = {
host: node.credentials.host,
port: node.credentials.port,
pass: node.credentials.password,
};
}
}

And finally make the Redis store available with the configuration options as a function:

return {
getRedisStore: function() {
return new RedisStore(options);
}
};
}

Finally, we can configure our application to use the Redis as a store for Express sessions:

app.use(session({
store: cacheConfig.getRedisStore(),
secret: ‘mysecret'
}));

Scaling Application Instances

With Cloud Foundry, it is simple to scale the number of instances for our running application. After we push our application again to Cloud Foundry:

$ cf push my_app_01

We can scale the number of running instances by using the `cf scale` command:

$ cf scale my_app -i 3

And we can verify the number of instances running by looking up our application information from Cloud Foundry:

$ cf app my_app
...
name requested state instances memory disk urls
my_app_01 started 2/2 256M 1G my_app_01.mycfdomain.com

Now a user should be able to authenticate to your application and if you save the user in the session it will be available across all running instances through Redis session store.

Conclusion

It is incredible how fast you can deploy scalable applications with add-on services that enable fairly complex behavior. I’ll post some more code examples for applications in more languages and other platforms over the next couple months.

Published by

Chris Sterling

Chris Sterling is Global Director of DevOps and Cloud Practices at Luxoft (www.luxoft.com), a 10,000+ person, $2B global technology solution provider with approximately 200 employees in the Pacific Northwest. Chris has an extensive technology, product management, process, and consulting background. Chris published the book Managing Software Debt: Building for Inevitable Change with Addison-Wesley in 2010 to provide a framework for teams and organizations to assess and manage debt in their software systems. Chris was a Certified Scrum Trainer with the Scrum Alliance for 8 years and taught thousands of people about how to apply Scrum effectively. Chris has successfully supported organizational transformation across multiple verticals with organizations of 10 up to 800 people. Chris co-founded a company in 2009 called Agile Advantage focused on solving portfolio management problems to leverage the value that Agile teams can deliver, which lead to a successful acquisition by Rally Software. He has spoken at many conferences and user groups on topics such as continuous delivery, software architecture, technology management, Lean and Agile processes, and Lean Startup. Chris has taught the “Advanced Topics in Agile Software Development” class at the University of Washington in the Agile Developer Certificate extension program. Chris brings his diverse experience and deep passion for technology when discussing topics such as Continuous Delivery, Cloud Native architecture, DevOps, Lean and Agile. Follow me @csterwa or get LinkedIn with me at http://linkedin.com/in/chrissterling.