2011
10.14

I have been using CloudFoundry for my latest Grails demos at work because it’s incredibly easy and fun to use with Grails. This week I decided to deploy an app to Amazon Web Services though. I played with AWS Elastic Beanstalk, the AWS Java PaaS, when it first came out earlier this year and wrote a post about it. It was cool back then, but there were some minor issues. When I used it this week though, it was an awesome experience! So, I decided to write a post about it in case anybody else is just getting started with deploying Grails apps to AWS.

First, let’s define everything we are going to be using:

Under the covers, Elastic Beanstalk is actually using numerous different AWS services like EC2, S3 and Auto-Scaling, but this really doesn’t even matter to us! We get them all bundled together at no extra cost in an easy to use interface! This is in contrast to the Rails PaaS, Engine Yard, which also bundles numerous EC2 services together, but charges an additional 5 cents per hour for each EC2 instance. So, let’s dive in!

First thing we need to do is create a MySQL database in RDS.

  • Login to the AWS Console and go to the RDS tab
  • Click Launch DB Instance
  • Select MySQL
  • DB Engine Version: 5.1.57 (this is the default)
  • DB Instance Class: db.m1.small (start with smallest)
  • Multi-AZ Deployment: No (no reason to pay double when starting)
  • Allocated Storage: 5gb (smallest allowed)
  • DB Instance Identifier: sampleappinstance (need this for connection string)
  • Enter username and password
  • Click Continue
  • Database Name: sampleappdb (also needed for connection string)
  • Leave the port and availability zone as default
  • Click Continue
  • Leave backup options as default for now
  • Click Continue
  • Review and click Launch!

Here’s a screenshot of my sample RDS configuration (click for bigger version):

AWS RDS Configuration

Last thing on RDS is we need to modify the security group to allow connections to the MySQL database from Beanstalk. We will need two things:

  • AWS Account ID – Which you can find at the bottom Security Credentials page. Mine is a 12 digit number.
  • Elastic Beanstalk Security Group – Which will be elasticbeanstalk-default by default unless you change it

So, on the RDS tab, click on DB Security Groups under the side navigation. You will see one security group called default. Check the box for default and then look at the properties in the bottom pane. We’re going to add a new connection type to our default security group!

  • Connection Type: EC2 Security Group
  • Security Group: elasticbeanstalk-default
  • AWS Account ID: your id
  • Click Authorize

Now it’s time to prepare our Grails WAR file for deployment! There are three things we need to do before creating the WAR though:

  • Update production data-source
  • Update server url
  • Add dependency for MySQL

grails-app/conf/DataSource.groovy

...
production {
  dataSource {
    pooled = true
    dbCreate = "update"
    driverClassName = "com.mysql.jdbc.Driver"
    url = System.getProperty("JDBC_CONNECTION_STRING")
    dialect = org.hibernate.dialect.MySQL5InnoDBDialect
    properties {
      validationQuery = "SELECT 1"
      testOnBorrow = true
      testOnReturn = true
      testWhileIdle = true
      timeBetweenEvictionRunsMillis = 1000 * 60 * 30
      numTestsPerEvictionRun = 3
      minEvictableIdleTimeMillis = 1000 * 60 * 30
    }
  }
}
...

You’ll notice that I have dbCreate = update, but if you are using the database-migration plugin, you would set this to “none” and configure Grails to automatically run your migrations during start-up. I’m just keeping it simple with “update” for this example though.

Also, we set the URL to JDBC_CONNECTION_STRING so that we don’t have to store the username and password in this file which means it can safely be stored in GitHub (or whatever version control you’re using).

grails-app/conf/Config.groovy

...
production {
  grails.serverURL = "http://www.sampleapp.com"
...
}
...

You will need to register a URL somewhere and then point your name-servers to AWS Route 53 which I will discuss later.

grails-app/conf/BuildConfig.groovy

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

Next, we need to package our Grails WAR and deploy to Beanstalk!

grails prod war

  • Click on the Beanstalk tab in the AWS Console
  • Click on Create New Application
  • Application Name: sampleapp
  • Browse to your WAR file (sampleapp-0.1.war)
  • Enter in whatever you want for the description, url, etc.

Here’s a screenshot of my sample Beanstalk configuration (click for bigger version):

AWS ElasticBeanstalk configuration for sampleapp

We will get an error when Beanstalk tries to start the application though because remember we said we wanted a system property called JDBC_CONNECTION_STRING to be used for the MySQL URL. So, we need to add this. So, on the Beanstalk tab expand the Environment Details for the sampleapp application and click on Edit Configuration. Then click on the Container tab. Scroll down to where you see JDBC_CONNECTION_STRING and enter in the following:

jdbc:mysql://sampleappinstance.AAAAAA.BBBBBB.rds.amazonaws.com:3306/sampleappdb?user=CCCCCC&password=DDDDDD

  • AAAAAA: the value for your instance, which you can get from the RDS tab
  • BBBBBB: correct region, which you can get from the RDS tab
  • CCCCCC: username, whatever you entered during RDS instance creation/li>
  • DDDDDD: password, whatever you entered during RDS instance creation

Then restart the application in Beanstalk. Now the moment of truth! Go to the url for the application and make sure it works! For example: http://sampleapp-prod.elasticbeanstalk.com was the one I used. Hopefully everything works and the app is successfully configured in Beanstalk using RDS! If not, you’ll need to go back and double check the configuration.

Now the final touch! Let’s configure our own domain because we don’t want users going to an elasticbeanstalk.com url for our app! There was a problem with Route 53 earlier this year where you couldn’t route a root domain to an Elastic Load Balancer, but this is fixed now! So, we can use Route 53 to host our domain as well as make sure the root domain and the www subdomain are sent to our application on Beanstalk.

There isn’t an official interface from Amazon for Route 53, but Interstate 53 will do the job! Go to https://interstate53.com. You can see we need two things to login: Access Key and Secret Key. We can get these from the AWS Security Credentials page. Once logged in, click on Add New Domain and enter your domain. On the domain page, note down the 4 name server records listed and enter those in at your registrar. We want to point the domain to Route 53′s name servers at wherever the domain is registered.

Now we are going to create two records for the domain: Alias Record to ELB and Alias CNAME Record.

Alias Record to ELB

  • Goto EC2 tab in AWS console
  • Under My Resources, click on 1 Load Balancer
  • Select the load balancer and look at the properties below
  • Copy the Hosted Zone ID and the DNS Name listed for “A Record” to a text file
  • Back in Interstate53, click on your domain and then Add Record
  • Select Alias Record to ELB
  • Leave Name blank and type as A
  • Put your Hosted Zone ID and DNS Name for the load balancer into the respective fields
  • Click Save

Alias CNAME Record

  • Click Add Record again
  • Select Alias CNAME Record
  • Enter www for Alias
  • Enter your load balancer DNS for Canonical Name
  • Click Save

Back on the domain overview page, click on Accept Changes. Then back on the main page, hover over the Actions section and click Push (to send the changes to AWS). If everything works, the root domain and www subdomain are now pointed at the Elastic Load Balancer! That’s all there is to it! You can certainly change lots of configuration items in RDS and Beanstalk after your app is deployed like creating read-replicas of MySQL and setting the minimum number of Tomcats to more than one, but this obviously all depends on what resources your Grails app needs (and how much you want to spend, ha!)

I hope you enjoyed reading my post on Grails on AWS! Please leave a comment if you have any questions or feedback about this post!

23 comments so far

Add Your Comment
  1. This is a great read. I am currently trying to find the best hosting solution for a Grails project and Beanstalk has been in the lead over Cloudfoundry. Cloudfoundry scares me a bit because I do not know how much it will cost in the future.

    The info on Interstate 53 will be helpful as I have not heard of the need for Route 53 before.

    Thank you,
    Royce

  2. [...] Bobby Warner » Grails on AWS [...]

  3. [...] Grails on AWS [...]

  4. [...] Grails on AWS [...]

  5. [...] Grails on AWS and grails cloud foundry cheat sheet. [...]

  6. this helped. thank you!

  7. Thanks, great post! We’ve tried several hosting options including cloudfoundry, Rackspace, and various flavors of AWS. This one looked interesting, but the AWS documentation was too daunting. This summary was really helpful.

  8. What about the http sessions when amazon has you running on multiple servers?

    Grails holds the session in-memory, which means that if a user is load balanced to a different server his next page may be delivered as though he’s logged out. This assumes sessions are important to your web app.

    I’ve pinned users to a particular server. This is a feature of my load balancer. It can suck when we reboot a server because the user is bounced somewhere new and is basically logged out.

    I’ve read about grails being able to share a session cache between servers. I’d be a little concerned about performance because it’s a hit on each and every page.

    What works in AWS?

  9. @Roger Yes, you have to deal with sessions being in memory on Tomcat. So far, I’ve just been doing exactly what you described by using sticky-sessions on the ELB. The best solution will be to either store sessions in a database and there’s a new plugin in the works for this (http://grails.org/plugin/database-session) or to use session-replication, which is what Jelastic does (http://jelastic.com/docs/session-replication).

  10. Thanks, Bobby. That’s useful information.

    How would jelastic compare to terracotta? They both seem to have koolaid-drinking-partisans in the blog-o-sphere.

  11. @Roger Jelastic is another PaaS, a competitor to AWS BeanStalk, Heroku and CloudBees. Terracotta is a distributed in-memory cache (among other things) that can be used for session clustering, object caching, etc. You could use Terracotta on AWS for instance. Jelastic uses native app server (Tomcat, Jetty, Glassfish, etc.) clustering.

  12. Yeah, I realized that after I clicked away from the page. Jelastic seems very interesting because locating my servers in europe would be beneficial for me.

    Thanks!

  13. Have you tried to use RDS read-replica with a Grails app?

    It looks like GORM multiple datasources support is limited to spreading your domain objects between different datasources.

    A read-replica in RDS is just another DB server / different datasource.
    How do you specify in Grails that some of your finder methods are executed on the replica datasource?

  14. @Benoit I have not used the read-replicas in RDS yet. So, I unfortunately can’t answer your question. When I do look at read-replicas, I can add a comment about how I implemented it. Thanks for reading!

  15. Hi Bobby,

    Thanks for the article. I have tried to follow your instructions exactly as you have laid out here but am unable to connect my app to the rds. I am using grails 1.3.7 and was wondering has something changed. I have a feeling it is something to do with the jdbc connection string, I would be grateful if you had any advice. I have followed your instructions exactly.

    Thanks,

    Des

  16. Do you have any information regarding the cost? The whole Amazon documentation and calculation sheets are a mess and I’ve heard many warnings particularly regarding RDS pricing.

  17. Hi Bobby

    My db connection fails to recognise the “JDBC_CONNECTION_STRING” I have supplied. I’ve double checked this numerous times, so I’m sure my URL value is correct. But the logs tell the app is trying to connect to somewhere completely different, with user ‘sa’ (is that a default for EC2 or something)? The top of the stack trace reads:

    Caused by: java.sql.SQLException: Access denied for user ‘sa’@'ip-10-226-5-172.eu-west-1.compute.internal’ (using password: YES)
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1073)
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4096)
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4028)

    Any ideas perhaps? I’m very keen to get this working :)

    Thanks a million.

  18. Seems the security groups configuration has changed since this blog.
    May i get any reference/details from the second step on the latest AWS.
    The details mentioned are changed in the new AWS and i am very new to it.

  19. Sounds like you’ve built a “dev” war file not a production one – or you’ve left the username and password defaults in your DataSource.groovy file.

  20. I’m having the same issue as Donovan with the MySQL access. Access denied for user ‘sa’.

  21. [...] app on AWS for the first time using the AWS Free Tier. I’m using Bobby Warner’s post from October 2011 as a guide to setting up the AWS services. Some field locations and the order [...]

  22. [...] Bobby Warner made thre [...]

  23. […] Bobby Warner made thre […]

*

Switch to our mobile site