Guide - Migrating from Heroku to AWS using CloudFormation


Published on

Step by step guide to migrating from Heroku to Amazon AWS using AWS CloudFormation.

Presented at the Australian AWS User Group in Melbourne at the October Meetup.

Published in: Technology
1 Comment
No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide

Guide - Migrating from Heroku to AWS using CloudFormation

  1. 1. Rob Linton Jasondb – a cloud based, CTO & Founder scalable NoSQL database for social and mobile applications. Phone: [AUS] + 61 418 510 155 Email: 2 Migrating from Heroku to Amazon AWS using CloudFormationIn guide number one we looked at how we migrated Amazon EBS backed AMI’sbetween AWS Regions using the tools that already exist on a standard Unix AMI.(Available on at 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 generic introduction onsetting up any application in the Amazon AWS stack.This guide was presented at the Australian AWS Users Group in Melbourne on the26thOctober, 2011.A brief summary of HerokuHeroku is commonly referred to as a Platform as a Service (PaaS) provider, in that theyoffer more than just infrastructure services. Heroku offer a turnkey solution for hosting,originally, Ruby on Rails (RoR) applications, although they now offer other languagessuch 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 onyour application and leave everything else such as the hosting and scaling up to someoneelse. Having done a substantial amount of development over the years (although not inRoR), I can attest to the attraction of any services that eases the deployment of yourapplication.
  2. 2. Why migrate from Heroku?There may be a number of reasons why you may want to migrate from Heroku. WhileHeroku is great in the way it takes the load of managing the deployment and scaling awayfrom 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 startsto gain momentum, it is usually cheaper to host your application on AWS as the numberof users increase.The usual steps for deploying to HerokuThe 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 herokuCreate your hello world application:$ rails hello$ cd hello$ rails generate controller helloOpen 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.2
  3. 3. $ rails serverUse Git to manage your project:$ cd PATH/TO/MY_APP$ gitinit Initialized empty Git repository in .git/$ git add .$ git commit -m "new app"Create a ssh key pair:$ cd ~/.ssh$ mkdirkey_backup$ cpid_rsa* key_backup$ rmid_rsa*$ ssh-keygen -t rsa -C ""Open the file with a text editor and cut & paste into your account settings onthe Heroku web site.Configure Git$ gitconfig --global "FirstnameLastname"$ gitconfig --global ""Create your Heroku application$ heroku createUpload your application to Heroku$ git push heroku master 3
  4. 4. Set up your application database$ heroku rake db:migrateSetting up the Amazon AWS EnvironmentBefore 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 followingproducts: 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 overviewHere is asimple overview of the architecture for the rails application on AWS.4
  5. 5. Overview architecture of the rails applicationAs 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 aRelationalDatabase Instance (RDS) to store its data.Step by stepNow 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 applicationstacks such as Ruby on Rails applications, Wordpress sites and even Drupal CMS sites. 5
  6. 6. Create a new stackClick on the Create New Stack button, this will pop up the Create Stack dialog. Create stack dialogGive your application a name (Hello World) and select the sample template of Rails HelloWorld Application (SSH enabled).At the bottom of the dialog, expand the Show Advanced Options. This exposes someextra options that you can select such as setting a time out on the creation or adding aSimple Notification Service (SNS) topic.6
  7. 7. For this 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 ofinformation such as user names and passwords. Create stack optionsI recommend that you change the rails database password, the rails database user and theoperator 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.Enter the key pair name you created earlier.Once you have entered these pieces of information click on Continue.The final dialog shows a summary of the parameters that will be used to create the Rubyon Rails stack. 7
  8. 8. Create stack summary screenThis is the last point where you can cancel the create stack. By clicking on the CreateStack 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 already have been created and you should have received an email similar to the one below.8
  9. 9. SNS notificationClicking on the link should display the following message. ConfirmedDuring the Ruby on Rails stack creation, the following dialog will be displayed. 9
  10. 10. Creating stackDuring the creation process you will receive a number of email notifications via the SNSservice. Email notificationsAfter your rails stack has been completed, the status will change toCREATE_COMPLETE.10
  11. 11. Resources createdSelecting the Resources tab will show you all of the resources that the CloudFormationstack created for you. Because it is important that you understand what actuallyhappened, I’ll take you through each of the resources created.Here is an overview diagram of what was created above: 11
  12. 12. CloudFormation stack after creationEC2SecurityGroupThis 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 instancecreated as part of the CloudFormation stack can only be accessed via port 8888, or port22 (ssh), even if the source of the access was a second EC2 instance in the same group.ElasticLoadBalancerThe ELB accepts traffic in on port 80 and redirects it out on port 8888 to each of therunning rails servers. Note how it changes the port number to ensure that each of the railsservers are not accessible on port 80.12
  13. 13. Note however, that if you knew the direct address of one of the EC2 instances, this does not prevent you from connecting to the instance directly by using the following syntax in your browser. database security group restricts access to the RDS instance by only allowing EC2instances that are members of a specific EC2 security group to connect. In this case onlymembers of the Rails security group can connect to RDS.SampleDatabaseThis is the RDS MySQL instance that was created for you. By default a db.m1.smallinstance was created.Also by default a Multi AZ RDS deployment was done. Selecting a Multi AZdeployment allows a hidden replica to be created in a different availability zone, allowingfor fail-over of your RDS instance if one availability zone goes down.AlarmTopicThis is the Simple Notification Service (SNS) that was created as part of the stackcreation. As part of the creation process I received 22 notifications in the space of around30 minutes, so I would recommend that you create a mail rule to move these off to theirown folder in your mail program.TooManyUnhealthHostsAlarmYou can see the details for this alarm by clicking on it in the CloudWatch tab. 13
  14. 14. Alarm detailsAs you can see from the highlighted section above, this alarm will trigger if the numberof 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.RequestLatencyAlarmHighThis is the second alarm. This alarm will trigger if the latency is greater than 1 secondfrom the ELB to a Rails instance for longer than 1 minute. If this alarm triggers a SNSnotification will be sent.LaunchConfigThis is a component of the Auto Scaling. The launch configuration defines the type ofinstances that will be started as well as what AMI to launch. This has been taken care offor you so you will not need to edit this unless you would like to upgrade to a largerinstance type or if you would like to use a ‘Golden Image AMI’(We see later on how touse Golden Images)WebServerGroupThe Web Server Group defines which availability zones to start any new instances in aswell as the maximum and minimum instance numbers. The default configuration for the14
  15. 15. web server group that was set up is a minimum of 1 with a maximum of 3. Unfortunatelythis is not visible in the Web GUI, other than by reading the template. The followingsection 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" }CPUAlarmHighThis is the third alarm and will send a notification to SNS if the average CPU of anyinstance 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 implemented 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 Group defined as having a minimum of 1 server and a maximum of 3. 15
  16. 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 will need to do this manually. The 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 retention 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 applicationNow that you have configured the infrastructure for your Ruby on Rails stack, we need tobe able to do two more things. Install our application. Scale up and scale down our Rails servers.Installing your applicationOne of the interesting dilemmas when using products like CloudFormation is the one ofhow to install your application on new EC2 instances that are created in response toscaling events.There are a number of ways to configure and scale your applications in your new stackand there is a great article that should be used as a guide (although quite a long read). reality AWS doesn’t provide the tools required to complete the last mile, however theeasiest way is to create a ‘Golden Image’ AMI which is used by CloudFormation whenstarting new instances. A Golden Image is a master AMI which already has your application installed and configured on it.16
  17. 17. There is a trick to this, and the main one is enabling ssh access to your default Rails EC2instance as part of the stack install. (which is why we chose this option at the beginningof this guide) The steps are actually pretty straight forward.Configure your rails instance1. Using scp, copy your rails application to the new rails EC2 instance using the same private key you specified when starting it up. (If you don’t know where to copy it to, copy it to ~/my-rails-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.orig5. Rename your new application directory to ~/hwrails6. 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 ImageOnce you have configured your server with your application, and tested it, you will needto create an AMI Image from it. This is quite straight forward, just locate the instance inthe 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 CloudFormationtemplate.Edit the CloudFormation TemplateOnce the new AMI has been created, cut and paste the template file to a local file on yourcomputer. Open it up in Notepad or Textedit 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-1af28c48", "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 piecerepresents a 32 bit instance running in us-east-1. (The default) 17
  18. 18. Update the CloudFormation StackOnce you have your new template ready to go, you will need to edit the existingCloudFormation stack.To do this highlight the CloudFormation and click on the Update Stack in the toolbar, thefollowing dialog will be presented. Update stackSelect 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 youprovided previously.You may not notice any changes at this point, and in fact there are no changes. Theeasiest way to see if your changes work is to terminate your existing EC2 instance!Don’t panic though, because it is part of an Auto Scaling Group, AWS will automaticallyrestart 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.18
  19. 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, thenlook at the new instance in the EC2 tab. Take a look at the AMI-ID and confirm that it isindeed 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 Config: as-delete-launch-config as-create-launch-configAdding more servers to the Autoscaling GroupNow that we have installed our application, it would be nice to be able to add moreservers 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 tomodify the autoscaling group is to either use the command line tools or modify theexisting template.For this example I’m going to modify the template using the same process that I used inthe previous section and increase the minimum number of servers in my Auto ScalingGroup to two.Edit the template fileFind 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" 19
  20. 20. }, "a" ] ] } ],"MaxSize": "3" }Change the MinSize from 1 to 2 and once again update the stack with the new templateas 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 changes have workedalmost straight away. There should now be two instances of your rails applicationrunning.It has automagically been added to the Elastic Load Balancer, the correct security groupsand will start taking traffic almost straight away. (As soon 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. this guide we looked at how to migrate a Heroku Ruby on Rails application to AWS.We looked at setting up an application stack using CloudFormation and how to installand configure your stack after it creation.20
  21. 21. 21