Migrating from Heroku to Amazon AWS using CloudFormation

AMServers

Nov 2, 2011 (5 years and 9 months ago)

2,703 views

In guide number one we looked at how we migrated Amazon EBS backed AMI’s between AWS Regions using the tools that already exist on a standard Unix AMI.



Jasondb


a cloud based,
scalable NoSQL
database for social and
mobile applications
.

Rob Linton

CTO & Founder

www.jasondb.com


Phon
e:




[AUS] + 61

418 510
155

Email:






robl@jasondb.com



2

Migrating from Heroku to
Amazon AWS

using
CloudFormation

In guide number one we looked at how we migrate
d

Amazon EBS backed AMI’s
between AWS Regions using the tools that already exist on a standard Unix AMI.

(Available on slideshare.net at
http://www.slideshare.net/pleasebiteme/presentation
-
migrating
-
aws
-
ebs
-
backed
-
amis
-
between
-
regions
-
9465619
)


In this guide we look at migrating a Ruby on Rails application to Amazon AWS.

This guide, while focussed on Ruby on Rails, can be used as a gener
ic introduction on
setting up any application in the Amazon AWS stack.

This guide was presented at the Australian AWS Users Group in Melbourne on the 26
th

October, 2011.

A brief summary of Heroku

Heroku is commonly referred to as a
Platform as a Service (P
aaS)

provider, in that they
offer more than just infrastructure services. Heroku offer a turnkey solution for hosting,
originally,
Ruby on Rails (RoR)

applications, although they now offer other languages
such as
Node.js
,
Clojure
,
Java
,
Python

and
Scala
.

Heroku’s success lies in the fact that as a Ruby on Rails developer, you could focus on
your application and leave everything else such as the hosting and scaling up to someone
else. Having done a substantial amount of development over the years (although
not in
RoR)
, I can attest to the attraction of any services that eases the deployment of your
application.


2

Why migrate from Heroku?

There may be a number of reasons why you may want to migrate from Heroku. While
Heroku is
great in the way it takes the load

of managing the deployment and scaling
away
from

you, there are always compromises.

In this case Heroku, while reducing the complexity, also reduces the flexibility.

There are just some things that you cannot do in Heroku. Also as your application start
s
to gain momentum, it is usually cheaper to host your application on AWS
as the number
of users increase.

The usual steps for deploying to Heroku

The usual steps for deploying to Heroku are as follows:


Install the required software


1.

Install Ruby on Rails

2.

Install Git

3.

Create an Heroku account

4.

Install the Heroku Gem


$ gem install heroku

Create your hello world application
:


$ rails hello

$ cd hello

$ rails generate controller hello

Open the file config/routes.rb. Almost at the bottom (line #57) is this
line:

# match ':controller(/:action(/:id(.:format)))'

Remove the # in front so the line looks like:

match ':controller(/:action(/:id(.:format)))'

Create a file named index.html.erb in app/views/hello containing the text ‘Hello world’.

Start the server.


3

$
rails server

Use Git to manage your project:


$ cd PATH/TO/MY_APP

$ git init Initialized empty Git repository in .git/

$ git add .

$ git commit
-
m "new app"

Create a ssh key pair:


$ cd ~/.ssh

$ mkdir key_backup

$ cp id_rsa* key_backup

$ rm id_rsa*

$
ssh
-
keygen
-
t rsa
-
C "your_email@youremail.com"


Open the id_rsa.pub file with a text editor and cut & paste into your account settings on
the Heroku web site.

Configure Git


$ git config
--
global user.name "Firstname Lastname"


$ git config
--
global user
.email "your_email@youremail.com"


Create your Heroku application


$ heroku create

Upload your application to Heroku


$ git push heroku master


4

Set up your application database


$ heroku rake db:migrate


Setting up the Amazon AWS Environment

Before we
begin, let’s make sure we have the pre
-
requisites in place.

Make sure you have created an AWS account and have enabled access to the following
products:

1.

Elastic Compute
Cloud (
EC2
)

2.

Relational Database Service (
RDS
)

3.

Elastic Load Balancing (
ELB
)

4.

CloudWatch

5.

CloudFormation

6.

Simple Notification Service (
SNS
)


Also before you start make sure you have created a key/pair and download the
private key to a safe place on your local computer.

Architecture overview

Here is a

simple
overview of the architecture for the r
ails application on AWS.


5


Overview architecture of the rails application

As you can see from the diagram above, the layout is relatively simple.

The load balancer will have two rails servers, which in

turn will use a

Relational
Database Instance (RDS)

to
store its data.

Step by step

Now let’s put the pieces in place.

To create the application stack we are going to use AWS
CloudFormation
.

CloudFormation is a great way to speed up the creation of commonly used application
stacks such as Ruby on Rails applica
tions, Wordpress sites and even Drupal CMS sites.



6

Create a new stack

Click on the
Create New Stack

button, this will pop up the Create Stack dialog.


Create stack dialog

Give your application a name (
Hello World
) and select the sample template of
Rails

Hello
World Application (SSH enabled)
.


7

At the bottom of the dialog, expand the
Show Advanced Options
. This exposes some
extra options that you can select such as setting a time out on the creation or adding a
Simple Notification Service (SNS) topic.

For t
his example we will be adding a SNS topic that notifications can be sent to.

This next dialog looks pretty daunting, but is effect just asking for some standard bits of
information such as user names and passwords.


Create stack options

I recommend that y
ou change the rails database password, the rails database user and the
operator email address.

Make sure you scroll down and get the last option to enter a key pair name, as
this is hidden at the bottom of the dialog.

E
nter the key pair name you created ea
rlier.

Once you have enter
ed

these pieces of information click on
Continue
.


8

The final dialog shows a summary of the parameters that will be used to create th
e

Ruby
on Rails stack.



Create stack summary screen

This is the last point where you can cancel t
he create stack. By clicking on the Create
Stack button, amazon will go ahead and create

an Auto Scaled sample Ruby application,
backed by an Amazon RDS instance.

Note the Notification section at the bottom, at this point the SNS notification will
have alr
eady have been created and you should have received an email similar to
the one below.


9


SNS notification

Clicking on the link should display the following message.


Confirmed

During the Ruby on Rails stack creation, the following dialog will be
displayed.


10


Creating stack

During the
creation

process you will receive a number of email notifications via the SNS
service.



Email notifications

After your rails stack has been completed, the status will change to
CREATE_COMPLETE
.


11



Resources created

Selecting the
Resources

tab will show you all of the resources that the CloudFormation
stack created for you. Because it is important that you understand what actually
happened, I’ll take you through each of the resources created.

Here is
an overview
diag
ram
of what was created

above:


12


CloudFormation stack after creation

EC2SecurityGroup

This is
the

AWS security Group used to restrict access to your rails hosts.

For AWS,
security groups work on individual servers, so for example,
A

single EC2 instance
created as part of the CloudFormation stack can only be accessed via port 8888, or port
22 (ssh), even if the source of the access was a second EC2 instance in the same group.

ElasticLoadBalancer

The ELB accepts traffic in on port 80 a
nd redirects it out on port 8888 to each of the
running rails servers.

Note how it changes the port number to ensure that each of the rails
servers are not accessible on port 80.


13

Note however, that if you knew the direct address of one of the EC2 instance
s,
this does not prevent you from connecting to the instance directly by using the
following syntax in your browser.

http://ec2
-
107
-
20
-
81
-
60.compute
-
1.amazonaws.com:8888/

DBSecurityGroup

The database security group restricts access to the RDS instance by only allowing EC2
instances that are members of a specific EC2 security group to connect. In this case only
members of the Rails security group can connect to RDS.

SampleDatabase

This is
the RDS MySQL instance that was created for you. By default a db.m1.small
instance was created.

Also by default a Multi AZ RDS deployment was done. Selecting a Multi AZ
deployment allows a
hidden
replica to be created in a different availability zone, allo
wing
for fai
l
-
over of your RDS instance if one availability zone goes down.

AlarmTopic

This is the Simple Notification Service (SNS) that was created as part of the stack
creation. As part of the creation process I received 22 notifications in the space of

around
30 minutes, so I would recommend that you create a mail rule to move these off to their
own folder in your mail program.

TooManyUnhealthHostsAlarm

You can see the details for this alarm by clicking on it in the CloudWatch tab.


14


Alarm details

As yo
u can see from the highlighted section above, this alarm will trigger if the number
of unhealthy hosts > 0 for 1 minute.

The action for this alarm is to send a notification to the SNS service that we set up earlier.

RequestLatencyAlarmHigh

This is the seco
nd alarm. This alarm will trigger if the latency is greater than 1 second
from the ELB to a Rails instance for longer than 1 minute. If this alarm triggers a SNS
notification will be sent.

LaunchConfig

This is a component of the Auto Scaling. The launch co
nfiguration defines the type of
instances that will be started as well as what AMI to launch. This has been taken care of
for you so you will not need to edit this unless you would like to upg
rade to a larger
instance type or if you would like to use a
‘Go
lden Image AMI’

(We see later on how to
use Golden Images)

WebServerGroup

The Web Server Group defines which availability zones to start any new instances in as
well as the maximum and minimum instance numbers. The default configuration for the

15

web server group that was set up is a minimum of 1 with a maximum of 3. Unfortunately
this is not visible in the Web GUI, other than by reading the template. The following
section
of the template
shows the
WebServerGroup

details.


"WebServerGroup": {



"Properties": {


"LoadBalancerNames": [


{


"Ref": "ElasticLoadBalancer"


}


],


"MinSize": "1"
,


"LaunchConfigurationName": {


"Ref": "LaunchConfig"


},


"AvailabilityZones
": [


{


"Fn::Join": [


"",


[


{


"Ref": "AWS::Region"


},


"a"


]


]


}


],


"MaxSize": "3"


}

CPUAlarmHigh

This is the third alarm and will send a notification to SNS if the average CPU of any
instance in the
WebServerGroup

is great than 10% for more than one minute.

Overview of what was implemented by the stack

So the overview of what was impleme
nted by the stack in simple English is as
follows:



The stack consists of an Elastic Load Balancer (ELB) which accepts
connections on port 80 and distributes them to the
WebServerGroup

on port
8888.



The
WebServerGroup

is an Auto Scaling
G
roup defined as
having a
minimum of 1 server and a maximum of 3.


16

The Auto Scaling Group however does not automatically respond to alarms as no
Auto Scaling Policies

have been put in place by the stack. So to scale the group
up and down you w
ill need to do this manually
.



T
he EC2 instances in the
WebServerGroup

are protected by a Security
Group restricting access to port 8888 and port 22 (ssh) from any source IP.

The database instance created was a MySQL instance with Multi AZ fail
-
over enabled. Also by default the backup re
tention period has been set to one
day.



The servers in the
WebServerGroup

all have Ruby on Rails installed

and
already running
, however, your application will not already be installed on
any of them.


Configuring

your application

Now that you have
configured the infrastructure for your Ruby on Rails stack, we need to
be able to do two more things.

1.

Install our application.

2.

Scale up and scale down
our Rails servers.


Installing your application

One of the interesting dilemmas when using products like
CloudFormation

is the one of
how to install your application on new EC2 instances that are created in response to
scaling events.

There are a number of ways to configure and scale your application
s

in your new stack
and there is a great article that should

be used as a guide

(although quite a long read).

https://s3.amazonaws.com/cloudformation
-
examples/BoostrappingApplicationsWithAWSCloudFormat
ion.pdf

In reality AWS doesn’t provide the tools required to complete the last mile, however the
easiest way is to create a ‘
Golden Image’

AMI which is used by CloudFormation when
starting new instances.

A Golden Image is a master AMI which already has yo
ur application installed
and configured on it.


17

T
here is a trick to this, and the main one is enabling ssh access to your default Rails EC2
instance as part of the stack install.
(which is why we chose this option at the beginning
of this guide)
The steps a
re actually pretty straight forward.

Configure your rails instance

1.

Using
scp
, copy your rails application to the new rails EC2 instance using the
same private key yo
u specified when starting it up.

(If you don’t know where to copy it to, copy it to
~
/
my
-
ra
ils
-
app

initially)

2.

Log into the new rails EC2 instance using the private/public key pair you
specified when configuring the stack

using
ssh
.

3.

Stop the rails server.

4.

Move the existing directory ~/hwrails to ~/hwrails.orig

5.

Rename your new application
directory to ~/hwrails

6.

As part of the install you will need to edit the database.yaml file to configure
access to the new RDS instance that was created for you.

7.

Restart the rails server.


Create an Image

Once you have configured your server with your appli
cation,
and tested it,
you will need
to create an AMI Image from it. This is quite straight forward, just locate the instance in
the EC2 window, right click and select
Create Image (EBS AMI)
.

This will create a new AMI for you to use as the new base AMI in

the CloudFormation
template.

Edit the CloudFormation Template

Once the new AMI has been created, cut and paste the template file to a local file on your
computer. Open it up in Notepad or Text
edit and edit the following section
:


"AWSRegionArch2AMI" :

{


"us
-
east
-
1" : { "32" : "
ami
-
d411e2bd
", "64" : "ami
-
da11e2b3" },


"us
-
west
-
1" : { "32" : "ami
-
e7c797a2", "64" : "ami
-
e5c797a0" },


"eu
-
west
-
1" : { "32" : "ami
-
17c2f663", "64" : "ami
-
13c2f667" },


"ap
-
southeast
-
1" : { "32" : "ami
-
1
af2
8c48", "64" : "ami
-
1ef28c4c"
},


"ap
-
northeast
-
1" : { "32" : "ami
-
b403a8b5", "64" : "ami
-
b803a8b9" }


}

Replace the
highlighted bit in yellow with the name of your new AMI. The yellow piece
represents a 32 bit instance running in us
-
east
-
1.

(The def
ault)


18


Update the CloudFormation Stack

Once you have your new template ready to go, you will need to edit the existing
CloudFormation stack.

To do this highlight the
CloudFormation

and click on the
Update Stack

in the toolbar, the
following dialog will be
presented.


Update stack

Select the
Upload a Template File

option and upload the edited template.

Then just click Continue through all of the next dialogs and accept the
answers

that you
provided previously.

You may not notice any changes at this point, and in fact there are no changes.
T
he
easiest way to see if your changes work is to terminate your existing EC2 instance
!

Don’t panic though, b
ecause it is part of an Auto Scaling Group, AWS will automatically

restart a new instance based on your new AMI.

There is a bug in the current CloudFormation where it does not update the
Launch Config to the new AMI unless the instance type is changed in the
configuration screen.


19

So you will need to upload the template
file twice. The first time change the
instance type to m1.large, then the second time change it back to m1.small.

Give AWS a few minutes to detect that the group is below its minimum threshold
, then
look at the new instance in the EC2 tab. Take a look at t
he
AMI
-
ID and confirm that it is
indeed the new AMI that you added to the template file.

Another way to
do

this would have been to install the Auto Scaling command
line tools and use the
following commands to edit the Launch C
onfig:

as
-
delete
-
launch
-
config

as
-
create
-
launch
-
config

Adding more servers to the Autoscaling Group

Now that we have installed our application, it would be nice to be able to add more
servers to our Auto Scaling Group if the number of users connecting increases.

Unfortunately there is
currently no way to do this from the Web GUI, the only way to
modify the autoscaling group is to either use the command line tools or modify the
existing template.

For this example I’m going to modify the template using the same process that I used in
the
previous section and increase the minimum number of servers in my Auto Scaling
Group to two.

Edit the template file

Find the WebServerGroup section in the template file and edit the highlighted section.


"WebServerGroup": {


"Properties": {


"LoadBalancerNames": [


{


"Ref": "ElasticLoadBalancer"


}


],


"MinSize": "1"
,


"LaunchConfigurationName": {


"Ref": "LaunchConfig"


},


"AvailabilityZones": [


{


"Fn::Join": [


"",


[


{


"Ref": "AWS::Region"


20


},


"a"


]


]


}


],


"MaxSize": "3"


}

Change the MinSi
ze from 1 to 2 and once again update the stack with the new template

as in the previous example.

This time the changes will take affect without needing to change any other
parameters.

Take another look at the EC2 instance tab and you will see that the chan
ges have worked
almost straight away. There should now be two instances of your rails application
running.

It has automagically been added to the Elastic Load Balancer, the correct security groups
and will
start taking traffic almost straight away. (As soo
n as the ELB puts it in service,
which by default is around 20 seconds)


That’s it!


For a step by step guide on implementing automatic Auto Scaling based on CPU load,
please take a look at chapter 9 of my book:

Amazon Web Services: Migrating your .NET
Enterprise Application.

http://www.amazon.com/Amazon
-
Web
-
Services
-
Enterprise
-
Application/dp/1849681945


Summary

In this
guide we looked at how to migrate a Herok
u Ruby on Rails application to AWS.
We looked at setting up an application stack using CloudFormation and how to install
and configure your stack after it creation.



21