9781449323936
chapter_cloud.html

Chapter 10. The Cloud

"The cloud" is a buzz topic right now, and for good reason. Cloud computing isn’t the best approach for every deployment, but for many scenarios using a cloud provider can save time and money, and make your applications less susceptible to traffic surges. It can also greatly simplify your deployment process and IT needs.

There is no one definition of Cloud computing, and it is starting to become a misused term (some are now referring to any online service as a cloud service). And in fact there are three models of cloud computing; Infrastructure as a Service (Iaas), Software as a Service (Saas), and Platform as a Service (Paas). They’re all cloud services though, meaning that they’re available over the internet as metered ("pay as you go") services. SaaS examples include popular consumer services like GMail, Hotmail, Facebook, and YouTube and also more specialized software services available in a metered fashion over the internet. Amazon EC2, VMware vCloud, and Linode are popular IaaS options, and Amazon AWS, Heroku, Cloud Foundry, and Cloudbees are popular PaaS options. While Grails developers may integrate or create SaaS solutions, we will focus on IaaS and PaaS since they are more integral to the development and deployment process. Also note that while Google App Engine is a viable option for traditional Java applications, Grails applications typically don’t do well there; consider using Gaelyk instead to take advantage of a Groovy-based Grails-like environment.

The hosting being a service rather than a more traditional product-based hosting approach typically means that the provider makes computing resources available to you over the internet. So instead of buying hardware that the provider hosts and monitors for you, they provide everything but your applications and data. This includes the "physical" servers (which are usually virtualized, to make it easier for them to provision new instances and decommission unused instances) as well as services such as relational databases, NoSQL datastores, storage, clustering, and others, and features such as high availability, job scheduling, and even Hadoop, and more.

Typically cloud services are provided by a third party, can also be self-hosted private cloud solutions that function like those provided externally, for example if you were to self-host an implementation of VMware’s Cloud Foundry. The model is the same, and you have the same flexibility and elasiticity to add or remove capacity as needed, but you have the benefit of avoiding going out to the internet, and security concerns are reduced. You can also implement hybrid solutions, mixing public and private cloud services (often at the expense of added integration complexity).

Cost Savings

Users will typically see savings in multiple ways when using cloud solutions. These include not having to purchase or maintain hardware; cloud providers can better take advantage of economies of scale since they buy significant amounts of hardware. They also often buy large servers with multiple processors and lots of RAM and use virtualization to create multiple virtual servers for each physical server. And You will also typically need a smaller IT staff when you outsource your hardware in this way, and can take advantage of the provider’s often more experienced IT staff.

Typically cloud providers implement a "utility computing" payment model where you pay for bandwidth, CPU time, disk storage and other resources on a metered basis. You can use this to your advantage since you only pay for what you use; if you anticipate an upcoming increase in site traffic (because of a sale, a holiday, students returning back to school in the fall, or another event) you can simply provision more servers. Once the traffic returns to regular levels you return the temporary instances to the provider’s pool.

Cloud Foundry

Cloud Foundry is VMware’s entry in the cloud space, and it’s a strong one. VMware shook things up when they announced their open-source cloud solution in April, 2011. Offering a hosted solution (in beta at the time of this writing) as well as a downloadable "micro cloud" that runs in a virtual machine on your own laptop or server, and the option to view and enhance the code base (and even contribute new features back to VMware) make Cloud Foundry an interesting option.

The standard client that developers use to deploy applications is vmc. It’s a Ruby application but it runs on Windows, Linux, and Macs as long as you have Ruby and a few dependencies installed. SpringSource Tool Suite (STS) also has excellent support for Cloud Foundry through its addon; you can simply drag and drop your project onto the configured Cloud Foundry server node to deploy your application, and various wizards help you configure and attach services and configure your application runtime. But being Grails developers, your best bet is the cloud-foundry plugin.

There are several services available to Cloud Foundry applications, including MySQL and PostgreSQL relational databases, MongoDB and Redis NoSQL stores, and RabbitMQ messaging and all are supported with a corresponding Grails plugin and by the Cloud Foundry plugin.

Database applications

To create a Grails application that uses a database (MySQL or PostgreSQL) and hosting it at Cloud Foundry, take the following steps:

  • create an account if you haven’t already
  • create the Grails application like you would for any hosting provider, but don’t worry about the production datasource configuration yet
  • install the cloud-foundry plugin by adding it to BuildConfig.groovy or with the install-plugin command
  • store your username and password in $HOME/.grails/settings.groovy or Config.groovy
  • configure a database service, either MySQL or PostgreSQL (or you can wait and have this automatically done for you when deploying)
  • deploy the application, binding the database service that you already created, or creating and binding a new one as part of the deployment step

That’s not a lot of work, and once you’ve created an account and added your login credentials to $HOME/.grails/settings.groovy, it’s even simpler for the second application (assuming you want to automatically create and bind a database service):

  • create the Grails application
  • install the cloud-foundry plugin
  • deploy the application, creating and binding a new database service

You’ll notice that there’s no configuration mentioned other than specifying your login credentials. That’s not an omission; it’s how the deployment process works. The plugin includes a Spring bean post-processor (grails.plugin.cloudfoundry.AppCloudServiceBeanPostprocessor, although most of the functionality is in its grails.plugin.cloudsupport.AbstractCloudBeanPostprocessor base class from the cloud-support plugin) that reconfigures the DataSource bean based on the runtime database service information that Cloud Foundry makes available during deployment. As long as you have a dataSource bean configured and the VCAP_SERVICES environment variable is set, its JSON content is parsed and the database username, password, and URL values will be used to reconfigure the dataSource bean for you. This is obviously convenient, since you don’t have to run a command to find the cryptic connection values. But it also means there’s next to zero coupling with the hosting provider. So you can easily change to a different cloud or more traditional hosting provider, or even deploy to multiple providers.

Creating an application

To make this more concrete, let’s look at an example. I’ll assume that you already have a Cloud Foundry account, and that you’ve added your username and password to $HOME/.grails/settings.groovy (the file isn’t created for you, so create a new empty file if you haven’t already done so) to avoid having your password in source control, e.g.

grails.plugin.cloudfoundry.username = 'your_username'
grails.plugin.cloudfoundry.password = 'your_password'

Add a dependency on the cloud-foundry plugin to your application’s BuildConfig.groovy in the plugins section:

plugins {
   runtime ":hibernate:$grailsVersion"
   runtime ':jquery:1.7.1'
   runtime ':resources:1.1.6'
   build ":tomcat:$grailsVersion"

   compile ':cloud-foundry:1.2.1'
}

and run grails compile to let the plugins resolve. If you want to use a MySQL database, add a dependency for its driver in the dependencies section:

dependencies {
   runtime 'mysql:mysql-connector-java:5.1.16'
}

otherwise add a dependency for the PostgreSQL driver:

dependencies {
   runtime 'postgresql:postgresql:8.4-702.jdbc3'
}

Create a simple domain class so we can test the database persistence:

$ grails create-domain-class cloud.foundry.test.Person

and add some fields so it looks something like this:

package cloud.foundry.test

class Person {
   String firstName
   String lastName
}

Generate a static scaffolded UI:

$ grails generate-all cloud.foundry.test.Person

Enable the database console with the grails.dbconsole.enabled attribute in the production section in Config.groovy so we can take a look at the database and run some queries once the application is deployed:

environments {
   ...
   production {
      ...
      grails.dbconsole.enabled = true
   }
}

Also add some logging code in BootStrap.groovy to display the database connection information so we can use it to connect with the database console UI:

import grails.converters.JSON

class BootStrap {

   def init = { servletContext ->
      String VCAP_SERVICES = System.getenv('VCAP_SERVICES')
      println "VCAP_SERVICES: ${System.getenv('VCAP_SERVICES')}\n"

      def service = JSON.parse(VCAP_SERVICES).find { it.key.startsWith('mysql') }.value[0]
      println """
MySQL url:      jdbc:mysql://$service.credentials.hostname:$service.credentials.port/$service.credentials.name
      user:     $service.credentials.user
      password: $service.credentials.password"""
   }
}

And that’s it - we’ll leave the settings in DataSource.groovy alone since the connection settings will be reconfigured for us when deploying. You can add some extra JDBC URL parameters to a placeholder URL to configure the database if you want, for example to enable Unicode and UTF-8:

environments {
   ...
   production {
      dataSource {
         ...
         url = 'jdbc:mysql://localhost/db?useUnicode=true&characterEncoding=utf8'
      }
   }
}

Warning

The cf-push (and cf-update) script can deploy an existing war file, for example if you have a nonstandard build that requires more than running grails war, but by default will create a war for you. Since all Grails commands except war and test-app default to the development environment unless a different one is specified, it’s very important that you always run grails prod cf-push and grails prod cf-update to ensure that you build a war optimized for a production deployment.

Run the cf-push command to deploy the application. You should see output similar to this if you don’t already have a MySQL service configured and you let the script add and bind it for you:

$ grails prod cf-push
| Environment set to production.....
Building war file
| Done creating WAR target/cf-temp-1331686075902.war
>
Application Deployed URL: 'testing-testing-testing-1-2-3.cloudfoundry.com'? y
>
Would you like to create and bind a mysql service?[y,n] y
Service 'mysql-84fba3d' provisioned.
>
Would you like to create and bind a postgresql service?[y,n] n

Creating application testing-testing-testing-1-2-3 at testing-testing-testing-1-2-3.cloudfoundry.com with 512MB and services [mysql-84fba3d]:
 OK
Uploading Application:
  Checking for available resources:
 OK
  Processing resources:
 OK
  Packing application:
 OK
  Uploading (452K):
 OK

Trying to start Application: 'testing-testing-testing-1-2-3'.
.....

Application 'testing-testing-testing-1-2-3' started at http://testing-testing-testing-1-2-3.cloudfoundry.com

Note

Although the cf-push script builds an entire war file (typically at least 25MB) you can see from the output that only 452K was transferred to Cloud Foundry (this isn’t a fixed value; the number will be different for each application). This is because the client is smart enough to calculate a hash of all of the files in your war file and compare them to previously uploaded files, and not upload anything that’s already available at the server. This is particularly helpful for jar files, since it’s very likely that other users have already deployed applications with the Grails, Spring, Hibernate, and other library jars that your application is using. So you only need to upload rarely used jars and your actual application classes and files.

View the contents of the stdout.log file from the server with the cf-get-file script and it should look something like this:

$ grails cf-get-file logs/stdout.log
| Environment set to development.....

VCAP_SERVICES: {"mysql-5.1":[{"name":"mysql-84fba3d","label":"mysql-5.1",
"plan":"free","tags":["mysql","mysql-5.1","relational"],
"credentials"{"name":"d2df723ab1f14440a9dcbd37af9c1a4d1",
"hostname":"172.30.48.22","host":"172.30.48.22","port":3306,
"user":"umASXSmfZneBu","username":"umASXSmfZneBu","password":"pMKFw9EqZNuOS"}}]}

MySQL url:      jdbc:mysql://172.30.48.22:3306/d2df723ab1f14440a9dcbd37af9c1a4d1
      user:     umASXSmfZneBu
      password: pMKFw9EqZNuOS

If you navigate to the root url of your application it should display the start page with a link to the scaffolded controller you created as shown in Figure 10.1, “Home page of the test application”.

Figure 10.1. Home page of the test application

Home page of the test application

and you can open up the database console by navigating to /dbconsole/; choose "Generic MySQL" from the "Saved Settings" dropdown and enter the URL, username, and password that was in the server log file to login. Figure 10.2, “Database console UI” shows the console after connecting.

Figure 10.2. Database console UI

Database console UI

There’s not much to see yet since the application just started, but you can open up the Person CRUD pages and add some data so you can run some queries. You can also run show create table person to see the DDL that was used to create the table; it should show that it’s an InnoDB table (since the plugin configures the appropriate Hibernate Dialect for you) and that it uses UTF-8 charset (from the JDBC URL settings that you added to DataSource.groovy).

Scaling

Initially your application will be deployed on a single Tomcat instance, but it’s easy to scale up your deployment with the cf-update-instances script and view instance information with the cf-show-instances script.

You can see the single instance running with the cf-show-instances script:

grails> cf-show-instances
| Environment set to development.....

+-------+---------+--------------------+
| Index | State   | Start Time         |
+-------+---------+--------------------+
| 0     | RUNNING | 03/14/2012 02:11AM |
+-------+---------+--------------------+

and increase it to four instances (the max since the account is limited to 2GB of memory across all instances and each is 512MB by default) with the cf-update-instances script:

grails> cf-update-instances 4

Scaled 'testing-testing-testing-1-2-3' up to 4 instances.

You can see that three new instances get allocated but aren’t immediately available since the Tomcat instances need some time to startup and deploy the war file:

grails> cf-show-instances

+-------+----------+--------------------+
| Index | State    | Start Time         |
+-------+----------+--------------------+
| 0     | RUNNING  | 03/14/2012 02:11AM |
+-------+----------+--------------------+
| 1     | STARTING | 03/14/2012 08:27PM |
+-------+----------+--------------------+
| 2     | STARTING | 03/14/2012 08:27PM |
+-------+----------+--------------------+
| 3     | STARTING | 03/14/2012 08:27PM |
+-------+----------+--------------------+

All four instances should be running soon afterwards though:

grails> cf-show-instances

+-------+---------+--------------------+
| Index | State   | Start Time         |
+-------+---------+--------------------+
| 0     | RUNNING | 03/14/2012 02:11AM |
+-------+---------+--------------------+
| 1     | RUNNING | 03/14/2012 08:27PM |
+-------+---------+--------------------+
| 2     | RUNNING | 03/14/2012 08:27PM |
+-------+---------+--------------------+
| 3     | RUNNING | 03/14/2012 08:27PM |
+-------+---------+--------------------+

And you can scale back down at any time:

grails> cf-update-instances 1

Scaled 'testing-testing-testing-1-2-3' down to 1 instance.

HTTP sessions

Cloud Foundry uses sticky sessions between your instances, so functionality that depends on a consistent HTTP session will work well for the most part since all requests will go to a single server. Sessions aren’t replicated however, so if the server that a user is on crashes, the HTTP session will be lost and after getting redirected to another server, the session will have to be reinitialized. If authentication credentials are stored in the session, the user will no longer be authenticated and have to login again.

Server crashes are rare, but you might consider using an alternative approach to session management. There are three plugins that you can use to change how sessions and session data are stored; database-session (which stores sessions in a relational database), mongodb-session (which stores sessions in a MongoDB datastore), and cookie-session (which stores sessions in a cookie, limiting you to a total of 4K of session storage).

NoSQL, RabbitMQ, and Searchable

In addition to traditional relational databases, Cloud Foundry also supports the MongoDB and Redis NoSQL stores, and RabbitMQ messaging. And if your application uses one or more of the mongodb, redis-gorm, or rabbitmq plugins and you have the corresponding Cloud Foundry services configured for your application, the bean post-processor that updates the dataSource bean will do the same auto-reconfiguration of the connection configuration for these services. The plugin also has support for ensuring that the Lucene index created by the searchable plugin gets created in a writeable directory.

Monitoring and the Cloud Foundry UI plugin

The primary function of the Cloud Foundry plugin is to deploy and update your application, but it also has scripts that can give you a view into what’s happening with your application.

Grails interactive mode makes monitoring your application from the commandline a lot faster, since you only incur the JVM startup and Spring application context configuration once. Just execute grails to get started:

$ grails
| Enter a script name to run. Use TAB for completion:
grails>

Once the application is running, you can look at the stdout.log and stderr.log files with the cf-logs command:

grails> cf-logs
| Environment set to development.....
==== logs/stderr.log ====
Mar 14, 2012 1:06:23 AM org.apache.coyote.http11.Http11Protocol init
INFO: Initializing Coyote HTTP/1.1 on http-51810
Mar 14, 2012 1:06:23 AM org.apache.catalina.startup.Catalina load
INFO: Initialization processed in 379 ms
...

==== logs/stdout.log ====
VCAP_SERVICES: {"mysql-5.1":[{"name":"mysql-84fba3d","label":"mysql-5.1",
"plan":"free","tags":["mysql","mysql-5.1","relational"],
"credentials"{"name":"d2df723ab1f14440a9dcbd37af9c1a4d1","hostname":"172.30.48.22",
"host":"172.30.48.22","port":3306,"user":"umASXSmfZneBu","username":"umASXSmfZneBu",
"password":"pMKFw9EqZNuOS"}}]}


MySQL url:      jdbc:mysql://172.30.48.22:3306/d2df723ab1f14440a9dcbd37af9c1a4d1
      user:     umASXSmfZneBu
      password: pMKFw9EqZNuOS

Use the cf-info script to see your allocated memory, services, and application usage:

grails> cf-info

VMware's Cloud Application Platform
For support visit http://support.cloudfoundry.com
Target:   http://api.cloudfoundry.com (v0.999)

User:     beckwithb@vmware.com
Usage:    Memory   (512.0M of 2.0G total)
          Services (1 of 16 total)
          Apps     (1 of 20 total)

Use the cf-stats script to see the runtime CPU, memory, and disk usage, and total uptime for your application:

grails> cf-stats

+----------+-------------+----------------+--------------+---------------+
| Instance | CPU (Cores) | Memory (limit) | Disk (limit) | Uptime        |
+----------+-------------+----------------+--------------+---------------+
| 0        | 0.3% (4)    | 382.2M (512M)  | 41.0M (2G)   | 0d:1h:46m:42s |
+----------+-------------+----------------+--------------+---------------+

You can also use the cf-list-files script to get a directory listing at the server:

grails> cf-list-files /tomcat/webapps/ROOT/js

application.js                            183B

and the cf-get-file script to view a file once you’ve found it with the cf-list-files script:

The cloud-foundry-ui plugin

You can get a lot of information by using the commandline scripts, but they can be tedious and impractical to work with. There is an addon plugin for the cloud-foundry plugin, the cloud-foundry-ui plugin which creates a simple but very useful monitoring front end for your application. To use it, install it just like you did the cloud-foundry plugin, i.e. add it to BuildConfig.groovy (or use install-plugin):

plugins {
   runtime ":hibernate:$grailsVersion"
   runtime ':jquery:1.7.1'
   runtime ':resources:1.1.6'
   build ":tomcat:$grailsVersion"

   compile ':cloud-foundry:1.2.1'

   compile ':cloud-foundry-ui:1.1.1'
}

There isn’t much configuration required for this plugin, but you will need to add some controller mappings in UrlMappings.groovy. You have flexibility in the prefix of the URLs, but the other values must be the same as these:

class UrlMappings {

   static mappings = {
      "/$controller/$action?/$id?"{
         constraints {
            // apply constraints here
         }
      }

      "/admin/cfDashboard/$action?"(controller: 'cloudFoundryDashboard')

      "/admin/cfDashboard/application/$appName"(
              controller: 'cloudFoundryDashboard', action: 'application')

      "/admin/cfDashboard/service/$serviceName"(
              controller: 'cloudFoundryDashboard', action: 'service')

      "/admin/cfDashboard/files/$appName/$instanceIndex?"(
              controller: 'cloudFoundryDashboard', action: 'files')

      "/"(view:"/index")
      "500"(view:'/error')
   }
}

In this example I’ve used the "/admin" prefix to differentiate the URLs from the main site, and to make it easier to guard the pages with security since I can most likely use a wildcard pattern for "/admin/**". Once you’ve installed the plugin and deployed the application with cf-push or updated an existing application with cf-update, you can navigate to the root URL that you defined in UrlMappings.groovy, for example http://appname.cloudfoundry.com/admin/cfDashboard

If you set your Cloud Foundry username and password in Config.groovy then you’ll immediately see the UI screens. If you set the values in $HOME/.grails/settings.groovy however, they’re not available at runtime so you’ll be prompted with a login screen as shown in Figure 10.3, “Login screen” to enter your credentials so the plugin can make API calls on your behalf:

Figure 10.3. Login screen

Login screen

Once you’ve logged in, click the toolbar button with your application name and you’ll see the statistics dashboard as shown in Figure 10.4, “Statistics page”:

Figure 10.4. Statistics page

Statistics page

The gauges update themselves every five seconds unless you click the "Disable auto-refresh" link. If you click the "View" link on the left under "Files" you’ll see the file viewer pages like the example in Figure 10.5, “File viewer” that lets you see the entire directory tree (as much as you’re allowed to see anyway) and view any file:

Figure 10.5. File viewer

File viewer

You can also right-click on any file to download it to your local machine.

Heroku

Heroku is another great cloud hosting option for Grails applications. For a long time Heroku was known for hosting Rails and other non-JVM platforms, but they have jumped into JVM hosting with both feet and provide a solid deployment option for Grails and Java applications. It’s a more established solution than Cloud Foundry, so their addon selection is much more extensive.

The workflow for creating Grails applications and deploying them to Heroku is quite similar to that for Cloud Foundry. As of this writing there isn’t a Java API client for Heroku’s REST API yet, so you end up using a mix of the Grails plugin, the heroku commandline client, and Git tools to get everything going, but even so it is still an easy process.

The Heroku deployment philosophy is quite different from that of Cloud Foundry; instead of building and deploying a standard WAR file, you create your project and commit it to a local Git repository, and configure a Git remote at the Heroku servers. Pushing to the Heroku remote triggers the deployment process and the server-side components (a "build pack" in Heroku terminology) package up your application and deploy it.

The Heroku model is convenient since you’ll end up using less bandwidth to push the initial application and to update and redeploy changes. Cloud Foundry does use an intelligent hashing approach to avoid uploading files that are already available at the server so you don’t actually upload an entire war in either case, but with Heroku you only push application code. Jar files and plugin dependencies referenced in BuildConfig.groovy are resolved at the Heroku servers when building the war file. This convenience comes at a small cost however; you cannot use unreleased or locally modified plugins. This isn’t a general problem since most of the time you will be using released plugins, but it makes testing new plugins somewhat harder. One workaround is to publish the in-progress plugins to your own plugin repository (as long as it’s accessible to Heroku’s servers), and you can also publish a snapshot release of an in-progress plugin the the central Grails plugin repository (if you’re the plugin owner).

Heroku addons that work well with Grails applications include their PostgreSQL, Memcache, MongoHQ and MongoLab, RabbitMQ, and Redis To Go services. All are supported with a corresponding Grails plugin and by the Heroku plugin.

Database applications

The general workflow for creating a Grails application that uses a PostgreSQL database and hosting it at Heroku is

  • create an account if you haven’t already
  • install the heroku client and a Git client
  • create the Grails application like you would for any hosting provider, but don’t worry about the production datasource configuration yet
  • install the heroku plugin by adding it to BuildConfig.groovy or with the install-plugin command
  • commit your application code to a local Git repository
  • register the application with the heroku create command (this also creates a Git remote so you can push to deploy)
  • deploy the application with git push

You don’t have to register a database addon since all Grails applications get a small, free PostgreSQL instance.

Like with the Cloud Foundry plugin, there’s hardly any configuration needed since the heroku plugin uses a similar approach where a Spring bean post-processor (grails.plugin.heroku.HerokuBeanPostprocessor) reconfigures the DataSource bean based on the runtime database service information that Heroku makes available during deployment. Instead of one large JSON string in a single environment variable like Cloud Foundry, each addon registers its own environment variable(s), for example DATABASE_URL for the PostgreSQL addon, MONGOHQ_URL for the MongoHQ addon, MEMCACHE_SERVERS, MEMCACHE_USERNAME, and MEMCACHE_PASSWORD for Memcache, etc. You could run heroku config and use the connection information there to hard-code values in DataSource.groovy, but it’s best to use the plugin and stay as decoupled as possible to leave your options open.

Creating an application

Let’s look at an example of deploying to Heroku. I’ll assume that you already have a Heroku account and that you’ve installed the heroku and git clients and have authenticated at Heroku.

Add a dependency on the heroku plugin to your application’s BuildConfig.groovy in the plugins section:

plugins {
   runtime ":hibernate:$grailsVersion"
   runtime ':jquery:1.7.1'
   runtime ':resources:1.1.6'
   build ":tomcat:$grailsVersion"

   compile ':heroku:1.0.1'
}

and run grails compile to let the plugins resolve. Add a dependency for the PostgreSQL driver:

dependencies {
   runtime 'postgresql:postgresql:8.4-702.jdbc3'
}

Create a simple domain class so we can test the database persistence:

$ grails create-domain-class heroku.test.Person

and add some fields so it looks something like this:

package heroku.test

class Person {
   String firstName
   String lastName
}

Generate a static scaffolded UI:

$ grails generate-all heroku.test.Person

Enable the database console with the grails.dbconsole.enabled attribute in the production section in Config.groovy so we can take a look at the database and run some queries once the application is deployed:

environments {
   ...
   production {
      ...
      grails.dbconsole.enabled = true
   }
}

Also add some logging code in BootStrap.groovy to display the database connection information so we can use it to connect with the database console UI:

import grails.plugin.heroku.PostgresqlServiceInfo

class BootStrap {

   def init = { servletContext ->
      String DATABASE_URL = System.getenv('DATABASE_URL')
      if (DATABASE_URL) {
         try {
            PostgresqlServiceInfo info = new PostgresqlServiceInfo()
            println "\nPostgreSQL service ($DATABASE_URL): url='$info.url', " +
                    "user='$info.username', password='$info.password'\n"
         }
         catch (e) {
            println "Error occurred parsing DATABASE_URL: $e.message"
         }
      }
   }
}

Leave the settings in DataSource.groovy alone since the connection settings will be reconfigured for us when deploying.

Now we just need to initialize the Git repo and configure the Heroku project. Run git init:

$ git init
Initialized empty Git repository in /home/burt/workspace/heroku_grails/.git/

Run grails integrate-with --git to create a .gitignore file, and add the files and commit them:

$ grails integrate-with --git
| Created Git project files..
$ git add .
$ git commit -m "initial commit"
[master (root-commit) 78181a3] initial commit
 69 files changed, 4487 insertions(+), 0 deletions(-)
 create mode 100644 .classpath
 create mode 100644 .gitignore
 create mode 100644 .project
 create mode 100644 application.properties
...

Create the application using heroku create:

$ heroku create --stack cedar

This command creates the application at Heroku’s server (but doesn’t deploy anything yet). You can verify this by going to https://api.heroku.com/myapps where it will be listed along with any other application you may have created. The command also registers a Git remote to Heroku, which you can see by running git remote -v.

And we’re now ready to deploy. It’s as simple as pushing the commited application files to the Heroku remote added by heroku create, so run git push heroku master and watch the output. You’ll see that your application jar and plugin dependencies are resolved at the server, and a war file will be created and deployed to a Jetty server instance. If there’s an error during deployment, the Git push will fail and you can fix the issue, commit the changes, and push again to try deploying with the fixes applied.

If the deployment is sucessful, you can run heroku logs to see the server log output, and run heroku logs -t to "tail" the log and continuously display updated lines of output. The PostgreSQL connection information in the logs should look something like this:

PostgreSQL service (
postgres://syrmypn:Dp_RHcV@ec2-23-21-182-175.compute-1.amazonaws.com/syrmypn):
url='jdbc:postgresql://ec2-23-21-182-175.compute-1.amazonaws.com:5432/syrmypn',
user='syrmypn', password='Dp_RHcV'

If you navigate to the root url of your application it should display the start page with a link to the scaffolded controller you created. Figure 10.6, “Home page of the test application” shows an example.

Figure 10.6. Home page of the test application

Home page of the test application

and you can open up the database console by navigating to /dbconsole/; choose "Generic PostgreSQL" from the "Saved Settings" dropdown and enter the URL, username, and password that was in the server log file to login. Figure 10.7, “Database console UI” shows the console after connecting.

Figure 10.7. Database console UI

Database console UI

There’s not much to see yet since the application just started, but you can open up the Person CRUD pages and add some data so you can run some queries.

Scaling

Initially your application will be deployed on a single Jetty instance, but it’s easy to scale up your deployment with the heroku scale command:

$ heroku scale web=4
Scaling web processes... done, now running 4

and if you re-run heroku logs -t after increasing the server count you’ll see the three new instances logging startup messages (each message contains the web instance it was generated by).

Unlike the equivalent Cloud Foundry command, this isn’t limited by your account’s quotas since you pay for additional resources. Each account gets 750 "dyno hours" free per month, and a single application deployed on one instance running full time for a month will use 744 hours, so as long as you use the free versions of the various addon services you won’t have to pay anything for your hosting. But once you add one or more web processes, you’ll go beyond the 750 hour limit and have to pay for the rest.

Use the heroku ps command to get some state and uptime information about the various instances:

$ heroku ps
Process  State       Command
-------  ----------  ------------------------------------
web.1    up for 38m  java $JAVA_OPTS -jar server/jetty-..
web.2    up for 4m   java $JAVA_OPTS -jar server/jetty-..
web.3    up for 4m   java $JAVA_OPTS -jar server/jetty-..
web.4    up for 4m   java $JAVA_OPTS -jar server/jetty-..

HTTP sessions

Heroku does not offer session affinity, sticky sessions, or session clustering options. This means that functionality that depends on a consistent HTTP session will not work on Heroku. The includes basic HTTP session storage, but also Grails flash scope since that is implemented by storing the flash-scope data in the session until the next request. It also means that plugins like spring-security-core which store authentication details in your session will not work; you can authenticate but since your requests will be randomly assigned to different servers, you’ll appear logged in only on one instance but not the others. Whereas alternative approaches to session management are an option for Cloud Foundry, they’re more necessary for Heroku.

The heroku plugin depends on the database-session plugin, so by default your users will continue to split requests across multiple servers, but the session data will be stored in the PostgreSQL database and shared across all servers. If you prefer to use the MongoDB version of the plugin, add an exclusion for the database-session plugin in BuildConfig.groovy and add a dependency for the mongodb-session plugin:

plugins {
   runtime ":hibernate:$grailsVersion"
   runtime ':jquery:1.7.1'
   runtime ':resources:1.1.6'
   build ":tomcat:$grailsVersion"

   compile(':heroku:1.0.1') {
      excludes 'database-session'
   }

   compile ':mongodb-session:0.1'
}

Or if you prefer to use cookie-based storage (and you’re confident that user sessions won’t go beyond the 4K limit), use the cookie-session plugin instead:

plugins {
   runtime ":hibernate:$grailsVersion"
   runtime ':jquery:1.7.1'
   runtime ':resources:1.1.6'
   build ":tomcat:$grailsVersion"

   compile(':heroku:1.0.1') {
      excludes 'database-session'
   }

   compile ':cookie-session:0.1.2'
}

TBD

  • Amazon AWS
  • Cloudbees
  • Jelastic
Site last updated on: December 11, 2012 at 11:47:18 AM PST