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

Don’t have a Cloud Foundry account yet? Sign up for free today

Facebook Twitter Linkedin Digg Delicious Reddit Stumbleupon Email

Using JRuby for Rails Applications on Cloud Foundry

JRuby Rails applications can be deployed to CloudFoundry.com today with simple configuration changes. JRuby applications are commonly deployed to servlet containers by creating a .war file that contains the Rails app. We will do the same for Cloud Foundry with some changes to the database configuration, so the application can also access a database service on CloudFoundry.com.

Changes needed for deploying JRuby on Rails Applications to Cloud Foundry

There are two tasks we need to accomplish in order to get a JRuby application running on CloudFoundry.com. First we need to configure the application to connect to the database service on CloudFoundry.com by modifying the database.yml file in the configuration directory. We also need to run the equivalent of ‘rake db:migrate', when we deploy the application so that the database tables are created. We can do this by adding an initializer in the config/initializers directory.

The information we need to configure the database connection is available in the environment variable, VCAP_SERVICES. We could either parse that variable programmatically or use the convenient Cloud Foundry run-time gem (see Using Cloud Foundry Services with Ruby: Part 2 – Run-time Support for Ruby Applications blogpost), which is what we will do here. To use this gem we need to include it in our Gemfile:

...
gem  'cf-runtime'
...

Now that we have added this gem, we can add some code snippets to the database.yml file to access the database service information for the production environment. The following is the production portion from a database.yml file, where we are using a MySQL database:

config/database.yml

production:
  adapter: mysql
  <% require 'cfruntime/properties' %>
  <% db_svc = CFRuntime::CloudApp.service_props('mysql') %>
  database: <%= db_svc[:database] rescue 'bookshelf_production' %>
  username: <%= db_svc[:username] rescue 'root' %>
  password: <%= db_svc[:password] rescue '' %>
  host: <%= db_svc[:host] rescue 'localhost' %>
  port: <%= db_svc[:port] rescue '3306' %>

As you can see, we added a require statement for cfruntime/properties, and then we get a hash of the service properties by calling the service_props method passing in the type of service we are using. If there is only one service of that type bound to the application, then there is no need to specify the actual name of the service. You will need to specify the actual service name if you bind multiple services of the same type to your app. The hash of service properties is stored in a variable called db_svc, and code extracts the corresponding values to be used for database, username, password, host, and port. Each of these statements have a rescue clause that provides values to use if we are not operating in a Cloud Foundry environment, in which case the db_svc would be nil.

Alternatively, the production portion of the database.yml file would look like this for PostgreSQL:

production:
  adapter: postgresql
  encoding: unicode
  <% require 'cfruntime/properties' %>
  <% db_svc = CFRuntime::CloudApp.service_props('postgresql') %>
  database: <%= db_svc[:database] rescue 'bookshelf_production' %>
  username: <%= db_svc[:username] rescue 'bookshelf' %>
  password: <%= db_svc[:password] rescue '' %>
  host: <%= db_svc[:host] rescue 'localhost' %>
  port: <%= db_svc[:port] rescue '5432' %>

Next, we turn our attention to the creation of the tables we need for our app. For this to happen, we need to add the following initializer to the config/initializers directory when we deploy the app. I named this initializer cf_db_migrate.rb:

config/initializers/cf_db_migrate.rb

require 'cfruntime/properties'

# Run the equivalent of rake db:migrate on startup
if CFRuntime::CloudApp.running_in_cloud?
  migrations = Rails.root.join('db','migrate')
  if migrations.directory?
    ActiveRecord::Migrator.migrate(migrations)
  end
end

We use cfruntime/properties again and check to see that we are running in the cloud. Next we check to see if the db/migrate directory exists and if it does we run the database migration using the migration files in the directory ( ActiveRecord::Migrator.migrate(migrations) ).

One additional change we have to make is to the warble configuration. It does not include the db/migrate directory in the generated war file by default, so we need to add this to the configuration by specifying config.includes = FileList["db/migrate/*"]. Here are the relevant contents of the config/warble.rb file:

config/warble.rb

# Warbler web application assembly configuration file
Warbler::Config.new do |config|

  # Application directories to be included in the webapp.
  config.dirs = %w(app config lib log vendor tmp)

  # Additional files/directories to include, above those in config.dirs
  config.includes = FileList["db/migrate/*"]

end

A complete example

This assumes that you have a working JRuby environment with Rails, Warbler and MySQL gems already installed.

We have seen above what changes are needed, so let’s quickly generate a Rails app and make the required changes and deploy the app to CloudFoundry.com. If you don’t already have JRuby installed a good place to start is Getting Started with JRuby.

Create the JRuby Rails App

First we create the new app and create the first domain object with full scaffolding.

jruby -S rails new bookshelf -d mysql
cd bookshelf
jruby -S rails generate scaffold Book title:string category:string published:integer price:decimal{10.2} isbn:string

Next we remove the generated public/index.html and modify the config/routes.rb to use ‘books’ as the root:

rm public/index.html
vi config/routes.rb

Here is the route that I added in config/routes.rb:

Bookshelf::Application.routes.draw do
  resources :books

  # You can have the root of your site routed with "root"
  # just remember to delete public/index.html.
  # root :to => 'welcome#index'
  root :to => 'books#index'

  # See how all your routes lay out with "rake routes"

end

Now we will run this app locally to make sure it works:

jruby -S rake db:create
jruby -S rake db:migrate
jruby -S rails server

The Rails empty list view of the Book entity shows that this is indeed working. Now I can add new books to my bookshelf.

Modify the JRuby Rails App for CloudFoundry deployment

Let’s start by making the following changes that we mentioned above:

  • add the gem cf-runtime to the Gemfile
  • modify the “production:” section of the config/database.yml file as shown above
  • add a file named config/initializers/cf_db_migrate.rb with the content shown above

Next we need to generate the Warbler config file so we run:

jruby -S warble config

Now we can:

  • modify the config/warble.rb to add the db/migrate directory as shown above

Those are all the changes needed and we are now ready to package and deploy this app.

Package and deploy the JRuby Rails App to CloudFoundry

We will use Warbler to package the app into a war and the CloudFoundry vmc command line utility to deploy it.

The process we use to package the application into a war file is a simple: bundle, pre-compile assets and run Warbler:

jruby -S bundle install
jruby -S rake assets:precompile
jruby -S warble

This creates a bookshelf.war in the root directory of our Rails app. At the moment there are some issues running the vmc command with JRuby but we are working on a fix for this. In the meantime we can move the war file to another directory, so that I can easier switch to use regular “C” Ruby. I’ll create a ‘deploy‘ directory and configure that to use Ruby 1.9.2-p290 (I’m using rbenv, but you could use RVM as well):

mkdir deploy
mv bookshelf.war deploy/.
cd deploy
rbenv local 1.9.2-p290
# (if you use RVM the command should be 'rvm ruby-1.9.2-p290')

Now we are ready to log in to CloudFoundry and deploy our application. For this part you need to have vmc installed.

vmc target api.cloudfoundry.com
vmc login cloud@mycompany.com
Password: *****
Successfully logged into [http://api.cloudfoundry.com]
vmc push bookshelf
Would you like to deploy from the current directory? [Yn]: Y
Application Deployed URL [bookshelf.cloudfoundry.com]: mybookshelf.cloudfoundry.com
Detected a Java Web Application, is this correct? [Yn]: Y
Memory reservation (128M, 256M, 512M, 1G, 2G) [512M]: 512M
How many instances? [1]: 1
Bind existing services to 'bookshelf'? [yN]: N
Create services to bind to 'bookshelf'? [yN]: Y
1: mongodb
2: mysql
3: postgresql
4: rabbitmq
5: redis
What kind of service?: 2
Specify the name of the service [mysql-a4fd7]: mysql-books
Create another? [yN]: N
Would you like to save this configuration? [yN]: N
Creating Application: OK
Creating Service [mysql-books]: OK
Binding Service [mysql-books]: OK
Uploading Application:
  Checking for available resources: OK
  Processing resources: OK
  Packing application: OK
  Uploading (707K): OK
Push Status: OK
Staging Application 'bookshelf': OK
Starting Application 'bookshelf': OK

The vmc commands are highlighted above. Most defaults have been accepted except for the URL and whether a service should be created. I used the URL ‘mybookshelf.cloudfoundry.com‘ instead of the default to avoid collision with existing bookshelf applications. I answered ‘Y‘ to the question of creating a new service and picked (2) mysql and gave it the name of ‘mysql-books‘.

We should now see the app running:

vmc apps

+-------------+----+---------+---------------------------------+---------------+
| Application | #  | Health  | URLS                            | Services      |
+-------------+----+---------+---------------------------------+---------------+
| bookshelf   | 1  | RUNNING | mybookshelf.cloudfoundry.com    | mysql-books   |
+-------------+----+---------+---------------------------------+---------------+

So we can now enter ‘http://mybookshelf.cloudfoundry.com/‘ and see the Bookshelf application come to life and add some books.

You can review and download the entire source used for this sample at cloudfoundry-samples/jruby-rails-bookshelf or if you just want to see the changes needed to deploy in Cloud Foundry look at this commit.

Conclusion

We have shown that it’s possible to deploy a simple JRuby on Rails application to cloudfoundry and use a MySQL service as the backing data store. All that is required is some modifications to the apps configuration of the database.

In a future post we’ll take a look at similar changes that we need to do for a JRuby Sinatra app that uses DataMapper for persistence.

- 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

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')
    ...
    
  • Messaging (RabbitMQ)
    • 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