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):
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
pooled = true
dbCreate = "update"
driverClassName = "com.mysql.jdbc.Driver"
url = System.getProperty("JDBC_CONNECTION_STRING")
dialect = org.hibernate.dialect.MySQL5InnoDBDialect
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.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.
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):
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:
- 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!