How to deploy a Grails 3 app to AWS Beanstalk and CloudFront CDN


After sharing our initial experience on How to publish your Grails 3 plugin to Bintray few month ago, here is a quick guide on how we deploy our Grails 3 app to AWS Beanstalk with Gradle and Travis, a great combination of our weapons of choice.

Note: this is a follow up article to my 2014 Gr8Conf talk (Running a lean startup) and corresponding article (Running a Startup with Lean & DevOps culture), which was based on Grails 2.

On the Grails side

First step: we need a Grails 3 app.

  • run grails create-app my-app (or use an existing app),
  • edit grails-app/conf/application.yml to use in memory DB (to be replaced by our RDS config later)
production:
dataSource:
dbCreate: update
url: jdbc:h2:mem:testDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE
  • run grails war or gradle assemble to generate the artefact to deploy.

On the AWS side

Next step: let’s deploy manually our Grails 3 app.

  • select Create web server to generate your first environment,
  • select Tomcat prefigured configuration,
  • select your own source and pick up you war file (my-app/build/libs/my-app-0.1.war)
  • enter environment information and unique URL,
  • and continue with the different settings for you environment (instance type, EC2 key pair, ), you can keep most of them by default,
  • once your ready, Launch your environment and wait for the magic of Beanstalk to happen…
Groovy !
Your Grails 3 app is running in AWS Cloud.

Now let’s automate the deployment by using the awesome Beanstalk Gradle plugin (https://github.com/EvidentSolutions/gradle-beanstalk-plugin).

On the Gradle side

  • in your Grails app, edit build.gradle to add Beanstalk Gradle plugin,
plugins {
...
id "fi.evident.beanstalk" version "0.0.6"
}
  • add the corresponding configuration (after the apply plugin section),
beanstalk {
s3Endpoint = "s3-eu-west-1.amazonaws.com"
beanstalkEndpoint = "elasticbeanstalk.eu-west-1.amazonaws.com"
deployments {
// Example to deploy to the same env
beta {
war = tasks.war
application = 'MyApp'
environment = 'beta'
}
}
}

With these settings, it will re-deploy to the same environment (which is usually fine for a beta/staging env).

If you run on more than 1 instance in production, Beanstalk will perform batch deployment (default to 30% of your fleet at a time) in order to get zero-downtime deployment.

Another option is to perform blue/green deployment for production, simply define an environment name based on your project version : the Beanstalk Gradle plugin will create a new environment for each release of your app. Then use “swap environment URLs” to perform zero-downtime deployment.

deployments {
// Example to create a new env for each version
production {
war = tasks.war
application = 'MyApp'
environment = "my-app-${project.version.replaceAll('\\.', '-')}"
// Saved configuration name to use to create each env
template = 'default'
}
}
  • now, to deploy your app with a new production env, simply run gradle deployProduction.

On the Travis side

Last step to build our deployment pipeline: configuring Travis to run our gradle task after a git commit.

language: groovy
jdk: oraclejdk8
sudo: false # To use new Travis docker-based infrastructure
branches:
only:
- beta
env:
global:
# $AWS_ACCESS_KEY_ID
- secure: "..."
# $AWS_SECRET_ACCESS_KEY
- secure: "..."
script:
- gradle deployBeta
  • configure Travis integration with your GitHub repo,
  • to automatically deploy your app, merge you develop branch to beta branch and push your commit!

BONUS — Static assets deployment to CloudFront CDN

Let’s add an extra step to our deployment pipeline: static assets upload to an S3 bucket (used as an origin for CloudFront CDN) with the Asset Pipeline CDN Gradle plugin, my first Gradle plugin ;)(https://github.com/agorapulse/gradle-asset-pipeline-cdn).

  • in your Grails app, edit build.gradle to add Asset Pipeline CDN Gradle plugin,
plugins {
...
id "agorapulse.plugins.asset-pipeline-cdn" version "0.1.1"
}
  • add the corresponding configuration (after the apply plugin section),
assetsCdn {
accessKey = System.getenv('AWS_ACCESS_KEY_ID')
secretKey = System.getenv('AWS_SECRET_ACCESS_KEY')
region = 'eu-west-1'
directory = 'my-bucket'
storagePath = "assets/${project.name}-${project.version}/"
expires = 365 // Expires in 1 year (value in days)
gzip = true
}
  • edit ./grails-app/conf/application.groovy to enable CDN-based hosting of your static assets in your production environment,
// Asset pipeline CDN assets
environments {
production {
// Put your CloudFront URL (or S3 bucket URL if you don't use CloudFront CDN)
grails.assets.url = "https://s3-eu-west-1.amazonaws.com/my-bucket/assets/${appName}-${appVersion}/"
}
}
  • upload/sync your assets to your S3 bucket by running gradle uploadAssets,
  • And/or edit your .travis.yml,
...
script:
- gradle uploadAssets deployBeta
Et voila!
You can now deploy your Grails 3 app to AWS Beanstalk and CloudFront CDN, with a single git commit.

Note: we’re hiring! Are you kick-ass fullstack or front-end dev that want to work on Angular 2, Java or Groovy? You must contact me to join our dream team in Paris!

If you liked this article, please hit the ❤ button to recommend it. This will make it easier for other Medium users to discover this.