Cloud Foundry Blog

About Thomas Risberg


Deploying vert.x Applications to Cloud Foundry

NOTE: Modified to use 0.8.2 version of cloudfoundry-runtime dependency together with the 1.2.3.final version of vert.x (Jan 2, 2013) Developers can now use vert.x, a framework for highly scalable web applications, with CloudFoundry.com. Cloud Foundry has been a leader in providing an open Platform as a Service (PaaS), which allows for polyglot programming with a choice of multiple languages and frameworks. With recent releases of standalone application feature and Java 7 on CloudFoundry.com, developers now have a perfect environment to create vert.x applications, which can be written in any language that can run on the Java Virtual Machine (JVM), and deploy them to run on the JVM at CloudFoundry.com.

About vert.x

vert.x is a framework that builds on event-driven architecture and asynchronous I/O, similar to 

Node.js, but utilizes JVM’s internal capabilities to handle multiple processes and inter-process communications. Using Java threads, vert.x applications can easily scale over available cores making better use of available resources. This is ideal for applications with a large number of concurrent users, such as client applications running on mobile devices. Furthermore, running on the JVM means that it can work seamlessly with code written in other languages that run on the JVM, such as Java, Groovy, Ruby, JavaScript, Coffeescript, Python and others, in the same application. Since vert.x requires Java 7, the addition of Java 7 as a runtime to CloudFoundry.com has enabled developers to use this highly flexible, polyglot framework.

  • vert.x is a community project sponsored by VMware.
  • vert.x includes a distributed event bus that spans the client and server side so your applications components can communicate incredibly easily. The event bus even penetrates into in-browser JavaScript allowing you to create effortless so-called real-time web applications.
  • vert.x also includes Web Sockets and SockJS support plus a MongoDB persistor so you can write real applications from the get-go.

Running vert.x Applications on CloudFoundry.com

vert.x ships with a number of example applications, so let’s take one of the applications–

vToons Groovy example app–and adapt it to run on CloudFoundry.com. This is a simple shopping cart app for an online music store. It mostly consists of client side Javascript, but the server side is written in Groovy and the data is persisted in MongoDB. We have to make some modifications to deploy this application to CloudFoundry.com. The resulting modified application source code can be found under the cloudfoundry-samples GitHub account at https://github.com/cloudfoundry-samples/vertx-vtoons/. We will use the most recent stable release of vert.x (1.2.3.final), which can be downloaded from here: http://vertx.io/downloads.html. The modifications we have to make are the following:

  • Access system properties when app is running on CloudFoundry
  • Configure host and port setting for HTTP server
  • Configure database settings
  • Package the application for deployment including a vert.x runtime and any dependent jars Let’s start with the application changes. You can read about the changes below and see all of source modifications in this commit in the repository.
CloudFoundry.com environment properties:

When your app is running on CloudFoundry.com, there are some environment properties that are available for your app to inspect. This allows you to find the information regarding the services that are bound to the app, such as host and port. We will use the Java cloudfoundry-runtime support library (version 0.8.2) for this task.

 
import org.cloudfoundry.runtime.env.CloudEnvironment 
import org.cloudfoundry.runtime.env.MongoServiceInfo 
def cloudEnv = new CloudEnvironment()

We add the import and create a new instance of the general CloudEnvironment class. Additionally, we added an import for the MongoServiceInfo class since we know that we will be binding a MongoDB service to the application.

Web server:

In order to run on CloudFoundry.com, the application must know the host name and port of the provisioned instance on CloudFoundry.com. The following code reads the host name and port from the

CloudEnvironment object that we created above, but default to localhost:8080 if a Cloud Foundry environment is not detected:

 
port: (cloudEnv.getValue('VCAP_APP_PORT') ?: '8080') as int, 
host: cloudEnv.getValue('VCAP_APP_HOST') ?: 'localhost', /* ssl: true, */ 

Note: In order to simplify this example, the SSL support was removed from the application.

Mongo Persistor:

When we push the application to CloudFoundry.com, we will bind it to a MongoDB. The connection parameters for the MongoDB service can be read from the

CloudEnvironment object. Here we use the MongoServiceInfo to access the service settings:

// Configuration for MongoDb 
def mongoConf = [:] 
if (cloudEnv.isCloudFoundry()) { 
  mongoSvcInfo = cloudEnv.getServiceInfo("mongodb-vtoons", MongoServiceInfo.class) 
  mongoConf.host = mongoSvcInfo.getHost() 
  mongoConf.port = mongoSvcInfo.getPort() as int 
  mongoConf.db_name = mongoSvcInfo.getDatabase() 
  mongoConf.username = mongoSvcInfo.getUserName() 
  mongoConf.password = mongoSvcInfo.getPassword() 
} 

We then modified the mongo-persistor deployment to use these configuration settings:

deployVerticle('mongo-persistor', mongoConf, 1) { // And when it's deployed run a script to load it with some reference // data for the demo deployVerticle('StaticData.groovy') } 

At this point we are done with the code changes and can move on to packaging the app.

Package and deploy to CloudFoundry:

To simplify the build and deployment we will move the application code to a vert.x module – you can see this change in this

commit in the repository. While we could package the application by copying a few directories from vert.x distribution and then using ‘vmc push’ as usual, let’s simplify by creating a Gradle build script as seen here. This build script provides the following:
1. Defines repository locations for Maven Central, Spring milestone releases and vert.x release distributions
2. Defines two configurations, one for runtime and one for dependent jars, as well as their dependencies
3. Provides a “runtime” task that downloads and packages the vert/x runtime
4. Provides a “build” task that packages the app source into a module directory
5. Provides an “assemble” task packages the application as a zip file to be deployed
6. Provides a “clean” task to clean up the build directory
7. Configures the Gradle CloudFoundry plugin so we can use the build script to deploy the app With everything in place, let’s just build and deploy the app:

$ ./gradlew assemble
:runtime
Download http://vertx.io/downloads/vert.x-1.2.3.final.zip
:build
Download http://repo.springsource.org/libs-snapshot/org/cloudfoundry/cloudfoundry-runtime/0.8.2/cloudfoundry-runtime-0.8.2.pom
:assemble

BUILD SUCCESSFUL

Total time: 18.586 secs

$ ./gradlew cf-add-service -PcfUser=user@email.com -PcfPasswd=secret
:cf-add-service
CloudFoundry - Connecting to 'http://api.cloudfoundry.com' with user 'user@email.com'
CloudFoundry - Provisioning mongodb service 'mongodb-vtoons'

BUILD SUCCESSFUL

Total time: 7.435 secs

$ ./gradlew cf-push -PcfUser=user@email.com -PcfPasswd=secret
:cf-push
CloudFoundry - Connecting to 'http://api.cloudfoundry.com' with user 'user@email.com'
GET request for "http://api.cloudfoundry.com/apps/vtoons" resulted in 404 (Not Found); invoking error handler
CloudFoundry - Creating standalone application 'vtoons' with runtime java7
CloudFoundry - Deploying '/Users/trisberg/Projects/github/cloudfoundry-samples/vertx-vtoons/build/vertx-vtoons.zip'
CloudFoundry - Starting 'vtoons'

BUILD SUCCESSFUL

Total time: 21.358 secs

We can now open a browser and enter http://vtoons.cloudfoundry.com/ to see the vert.x vToons application come to life and order some tunes. vToons

Try vert.x on CloudFoundry.com

Cloud Foundry continues its goal of creating the best open PaaS for developers to run applications based on a choice of languages and frameworks. In this blog, we detailed the few simple steps required to deploy a vert.x app, an exciting new Javascript framework for the JVM, to CloudFoundry.com. Feel free to experiment with and deploy the numerous other sample apps that are part of the vert.x download on CloudFoundry.com. Peter Ledbrook (@pledbrook) took the open source Collide collaborative IDE project and deployed it to CloudFoundry.com, take a look at it here: http://collide-pal.cloudfoundry.com.

Thanks to Tim Fox (@timfox), who created vert.x, and to Scott Frederick and Peter Ledbrook, who also contributed to this blog post.

- Thomas Risberg, The Cloud Foundry Team

Facebook Twitter Linkedin Digg Delicious Reddit Stumbleupon Email

Using Cloud Foundry Services with Ruby: Part 2 – Run-time Support for Ruby Applications

The services offered in Cloud Foundry are necessary for writing any serious application. Our aim is to make it easy to configure and consume these services. In addition to the auto-reconfiguration described in the Using Cloud Foundry Services with Ruby: Part 1 – Auto-reconfiguration blog post we also have support for manual service property lookup as well as library calls to obtain a pre-configured connection object.

Library call to obtain client object

For each supported service type there are corresponding library calls to obtain a pre-configured client object. This makes it easy to use in your code since you don’t have to lookup connection properties, instead you can rely on the library to do the work for you. Here are some examples for the supported service types:

  • Relational database (PostgreSQL)
 require 'cfruntime/postgres' client = CFRuntime::PGClient.create_from_svc('postgres-test') ... 
  • Relational database (MySQL)
 require 'cfruntime/mysql' client = CFRuntime::Mysql2Client.create_from_svc('mysql-test') ... 
  • Document database (MongoDB)
 require 'cfruntime/mongodb' connection = CFRuntime::MongoClient.create_from_svc('mongo-test') db = connection.db ... 
  • Key-Value store (Redis)
 require 'cfruntime/redis' client = CFRuntime::RedisClient.create_from_svc('redis-test') ... 
  • AMQP Client
 require 'cfruntime/amqp' client = CFRuntime::AMQPClient.create_from_svc('rabbit-test') ... 
  • Carrot
 require 'cfruntime/carrot' client = CFRuntime::CarrotClient.create_from_svc('rabbit-test') ... 

These library calls all use the “create_from_svc” method where you need to specify the name of the service you are connecting to. If you only have a single service of a specific type bound to the app, then you can omit the service name and use the “create” method instead. You can also provide connection parameters that can be used for local testing. This can be done using a rescue clause since the cloud connection method throws an exception if a cloud service can’t be located. The following is an example of using the “create” method to connect to a single MongoDB service bound to the app with an added rescue clause to provide a localhost db connection for running locally.

 
require 'cfruntime/mongodb' 
... 
db = (CFRuntime::MongoClient.create.db rescue Mongo::Connection.new("localhost", 27017).db("db")) 
... 

The following table shows the available methods and parameters for each service type:

Service Type Returns Method Signatures Comment
PostgreSQL PGConn instance CFRuntime::PGClient.create([options]) options parameter is an optional hash of connection settings to be passed to the PostgreSQL client
CFRuntime::PGClient.create_from_svc (service_name, [options]) service_name is the name of a service bound to the app, options parameter is an optional hash of connection settings to be passed to the PostgreSQL client
MySQL Mysql2 Client instance CFRuntime::Mysql2Client.create([options]) options parameter is an optional hash of connection settings to be passed to the MySQL client
CFRuntime::Mysql2Client.create_from_svc (service_name, [options]) service_name is the name of a service bound to the app, options parameter is an optional hash of connection settings to be passed to the MySQL client
MongoDB Mongo Connection proxy* CFRuntime::MongoClient.create([options]) options parameter is an optional hash of connection settings to be passed to the Mongo client
CFRuntime::MongoClient.create_from_svc (service_name, [options]) service_name is the name of a service bound to the app, options parameter is an optional hash of connection settings to be passed to the Mongo client
Redis Redis instance CFRuntime::RedisClient.create([options]) options parameter is an optional hash of connection settings to be passed to the Redis client
CFRuntime::RedisClient.create_from_svc (service_name, [options]) service_name is the name of a service bound to the app, options parameter is an optional hash of connection settings to be passed to the Redis client
RabbitMQ AMQP Client instance CFRuntime::AMQPClient.create([options]) options parameter is an optional hash of connection settings to be passed to the AMQP client
CFRuntime::AMQPClient.create_from_svc (service_name, [options]) service_name is the name of a service bound to the app, options parameter is an optional hash of connection settings to be passed to the AMQP client
RabbitMQ Carrot instance CFRuntime::CarrotClient.create([options]) options parameter is an optional hash of connection settings to be passed to the Carrot client
CFRuntime::CarrotClient.create_from_svc (service_name, [options]) service_name is the name of a service bound to the app, options parameter is an optional hash of connection settings to be passed to the Carrot client
  • The proxy returned for the MongoDB Connection has a no-argument ‘db’ method to get access to the DB object for the database created for the CloudFoundry service.

Service configuration properties lookup

For applications where you want more control, we provide a service configuration properties look-up library. To use this, you can programmatically check whether you are running in a cloud environment, and then use the library to look up a service specific properties needed for manual connection configuration. What services are supported and what properties are exposed for these services? All services have the following properties provided in a hash:

  • :label
  • :version
  • :name
  • :username
  • :password
  • :host
  • :port Each supported service also provides the following properties:

  • Relational database (PostgreSQL, MySQL)

    • :database – the name of the database
  • Document database (MongoDB)
    • :db – the name of the database
  • Key-Value store (Redis)
    • no additional properties
  • Messaging (RabbitMQ)
    • :url – the connection URL Here is a brief MongoDB example:
 
require 'cfruntime/properties' 
if CFRuntime::CloudApp.running_in_cloud? 
  @service_props = CFRuntime::CloudApp.service_props('myservice') 
else 
  @service_props = {} 
  @service_props[:host] = 'localhost' 
  @service_props[:port] = 27017 
  @service_props[:db] = 'testdb' 
end 
db = Mongo::Connection.new(@service_props[:host], @service_props[:port]).db(@service_props[:db]) 
if CFRuntime::CloudApp.running_in_cloud? 
  db.authenticate(@service_props[:username], @service_props[:password]) 
end

Conclusion

In the previous blog post, you learned about Ruby auto-reconfiguration, and in this post we have covered manual configuration. We are pleased to offer these two new approaches to make it even easier to connect to Cloud Foundry services from your Ruby applications. Please feel free to send us any feedback via the Cloud Foundry Support Forums.

- Thomas Risberg The Cloud Foundry Team
Don’t have a Cloud Foundry account yet?  Sign up for free today

Facebook Twitter Linkedin Digg Delicious Reddit Stumbleupon Email