Developer Blog

How to Deploy Play Framework on AWS OpsWorks

AWS OpsWorks is the next evolution of Amazon’s auto scaling, cloud deployment solution Elastic Beanstalk. OpsWorks attempts to abstract things a bit further, giving you more control over the various pieces of your deployment, see a tutorial here.

OpsWork has a pretty steep learning curve. To help with that, pre-made layers for various kinds of web apps are available (Rails, Node.js, PHP, Java, Static). This post will show you how to setup a Play! Framework app on OpsWorks in just a few steps.

I – Create Your Deployment Cookbook

An OpsWorks app uses Chef cookbooks to provision instances and deploy applications. For this example we’ll create a public git repository with a copy of Originate’s Play Framework cookbook. Creating a separate repository for your app’s cookbooks makes it easier to work with OpsWorks and also allows you to customize things as needed down the road.

Create a custom cookbook

First, install Berkshelf, which is available through ChefDK. Berkshelf makes it easier to manage cookbooks.

1
2
3
4
mkdir play-sample-opsworks
cd play-sample-opsworks
git init
berks cookbook app --skip-git # this creates the cookbook for our play application

This creates the basic structure of the cookbook. Next we need to add a reference to Originate’s play2 cookbook in the Berksfile:

1
2
3
4
5
6
7
# app/Berksfile

source "https://supermarket.getchef.com"

metadata

cookbook "play2", git: "https://github.com/Originate/cookbooks.git", rel: "play2"

You also need to add that reference to metadata.rb so OpsWorks can find the play2 cookbook:

1
2
3
4
5
6
7
8
9
10
11
# app/metadata.rb

name             'app'
maintainer       'YOUR NAME'
maintainer_email 'YOUR EMAIL'
license          'All rights reserved'
description      'Installs/Configures app'
long_description 'Installs/Configures app'
version          '0.1.0'

depends "play2", "~> 0.1.0" # add a dependency on Originate's play2 cookbook

One caveat of the OpsWorks Chef integration is that it doesn’t automatically fetch dependencies. Berkshelf can solve this for us by grabbing dependencies and vendoring them into our repository. Note that Berkshelf nukes the directory you point it at (including the .git folder), so use the following to download dependencies to a temporary directory and move the files afterwards:

1
berks vendor /tmp/cookbooks -b app/Berksfile && cp -rf /tmp/cookbooks/* .

Next create the recipes for the OpsWorks setup and deploy phases:

1
2
3
4
5
6
7
8
# app/recipes/setup.rb
#
# Cookbook Name:: app
# Recipe:: setup
#

# This installs the play framework
include_recipe "play2::setup"
1
2
3
4
5
6
7
8
9
10
11
# app/recipes/deploy.rb
#
# Cookbook Name:: app
# Recipe:: deploy
#

# This deploys the application
opsworks_play2 do
  app "app"
  deploy_data node[:deploy][:app] # This data comes from OpsWorks' JSON blob
end

In the next section, we’ll use what you’ve done here to setup a running OpsWorks system. If you’re following along, commit your work and push it to a repository that OpsWorks can access. Alternatively, you can use this sample repository.

II – Configure AWS OpsWorks

Now that you have your cookbook for your app setup, head to the OpsWorks Home Page to setup and deploy your app.

Create a Stack

The first step is to create a new stack. A stack is composed of one or more layers. A layer represents a group of instances with a specific purpose. For example, OpsWorks comes with a load balancer layer, a database layer, and some common web application layers such as Rails or Node. OpsWorks doesn’t provide a pre-made layer for Play! applications, so make sure to select “Use custom Chef Cookbooks” and fill in the URL of the repository you created in part I. If you’re using a private repository, don’t forget to add the SSH key in the textbox.

Create AWS OpsWorks Stack

Next we need to tell the play2 cookbook to install version 2.1.3 of the Play! Framework and to bind the web server to port 80 instead of the default 9000. Add the following to the “Custom JSON” text box:

1
2
3
4
5
6
7
8
9
10
11
{
  "play2": {
    "version": "2.1.3",
    "http_port": 80,
    "conf": {
      "application": {
        "langs": "en"
      }
    }
  }
}

You can also add custom configuration for your application in the conf object. For additional information about which parameters can be tweaked, check out the README.

Create a Layer

Choose “Custom” as your layer type. This will represent the machines that run your Play application.

Create AWS OpsWorks Layer

Edit Settings to Call Custom Recipes

When you edit your layer, you can add custom recipes to the different steps of your deployment. In order to get up and running, add app::setup to the “Setup” step and app::deploy to the “Deploy” step.

In general, the format for adding cookbooks to a specific step of the deploy process is <cookbook_name>::<recipe_name>.

Edit Layer

Add the application

Add the sample application to your OpsWorks stack. Select “Other” for the application type, and use https://github.com/Bowbaq/sample-play-app.git for the repository URL.

Create Application

Add an Instance

The next step is to add an instance to the stack. This will provision and deploy an EC2 machine into a context completely managed by OpsWorks.

Add Instance

Newly added instances are not started by default. Click on start, and OpsWorks will run the setup recipes for you (which will install Play!) and then the deploy recipes (which will deploy the app).

Start App

Once OpsWorks finishes, you should be able to visit http://<instance public ip> and see the following:

Running Application

III – Profit

Now that you have your app setup on AWS OpsWorks, you can look forward to the following awesome features:

  • One click deploy
  • Automatic scaling based on various metrics
  • Integrated instance monitoring
  • Deployment tracking
  • Easy environment management
  • Easy Elastic Load Balancer integration

Conclusion

If you found this tutorial helpful and would like to contribute, feel free to fork the repository and submit pull requests. If you add any enhancements to your custom cookbooks that are worth sharing, contributions would be welcome. Additionally, I could use some help working on the enhancements listed here: https://github.com/Originate/cookbooks/issues.

Comments