I previously posted instructions a year ago about how to do this in rails 4.1 on an old version of Elastic Beanstalk. This is the updated version.
Deploying Rails apps can be tricky. For simple projects, tools like Heroku can be perfect. It’s great for prototyping apps and testing out different ideas without a lot of hassle. However, when your project gets more complicated and you want to have better control of your servers, load balancers, workers, auto-scaling conditions, etc, you will not have the flexibility you desire.
There are many services that can be used to get a Rails app up and running quickly while still keeping full control of your infrastructure. One reasonable option is Amazon’s Elastic Beanstalk. The service is aptly described by Amazon as follows:
AWS Elastic Beanstalk makes it even easier for developers to quickly deploy and manage applications in the AWS cloud. Developers simply upload their application, and Elastic Beanstalk automatically handles the deployment details of capacity provisioning, load balancing, auto-scaling, and application health monitoring.
Now that Amazon supports PostgreSQL via RDS having a fully-managed postgres-backed Rails app has never been easier!
You can find all of the code for this post at github.com/jtescher/example-rails-4.2-elastic-beanstalk-blog
If you get stuck or have other issues the documentation for Elastic Beanstalk is pretty good.
Sign up for an AWS account via the instructions at the AWS Console and then download the Elastic Beanstalk Command Line Tools via Homebrew (or here for PC).
$ brew update$ brew install aws-elasticbeanstalk
The most current version of rails at the time of this writing is 4.2.1 so that’s what we will use now.
$ gem install rails -v 4.2.1$ rails new blog$ cd blog$ git init && git add -A && git commit -m "Add rails scaffold"
We will be creating a simple example app that allows you to manipulate posts. To generate this in Rails use:
$ rails generate scaffold post title:string body:text$ bundle exec rake db:migrate$ git add -A && git commit -am "Add post resource"
Now we can initialize a new Beanstalk app through the eb command.
$ eb init
I would choose the following settings, but for a description of each option see the AWS example here.
Select a default region3) us-west-2 : US West (Oregon)
Select an application to use[ Create new Application ]
Enter Application NameblogApplication blog has been created.
It appears you are using Ruby. Is this correct?(y/n): y
Select a platform version.
Do you want to set up SSH for your instances?(y/n): n
This will set up a .elasticbeanstalk directory in the root of your project and add it to your .gitignore file. You do not want your configuration stored in git because there could be private information in there. Let’s commit those changes now:
$ git commit -am "Ignore elasticbeanstalk settings"
You can have many environments per Elastic Beanstalk application. This can be useful for having both dev and production environments for the same app.
To create a new environment, run the following:
$ eb create blog-env:
Creating application version archive "b303".Uploading blog/b303.zip to S3. This may take a while.Upload Complete.Environment details for: blog-envApplication name: blogRegion: us-west-2Deployed Version: b303Environment ID: e-g5mkeawrnzPlatform: 64bit Amazon Linux 2015.03 v1.3.0 running Ruby 2.2 (Puma)Tier: WebServer-StandardCNAME: UNKNOWNUpdated: 2015-04-19 23:38:50.955000+00:00Printing Status:INFO: createEnvironment is starting.INFO: Using elasticbeanstalk-us-west-2-83376862866 as Amazon S3 storage bucket for environment data.INFO: Created load balancer named: awseb-e-g-AWSEBLoa-7R0CSEMQ6W2MINFO: Created security group named: awseb-e-g5mkeawrnz-stack-AWSEBSecurityGroup-56IUD2ZYQ5FRINFO: Created Auto Scaling launch configuration named: awseb-e-g5mkeawrnz-stack-AWSEBAutoScalingLaunchConfigurat...INFO: Created Auto Scaling group named: awseb-e-g5mkeawrnz-stack-AWSEBAutoScalingGroup-2URXDKL0NCIJINFO: Waiting for EC2 instances to launch. This may take a few minutes.INFO: Created Auto Scaling group policy named: arn:aws:autoscaling:us-west-2:833768628226:scalingPolicy:02920f8b...INFO: Created Auto Scaling group policy named: arn:aws:autoscaling:us-west-2:833768628666:scalingPolicy:b143cea1...INFO: Created CloudWatch alarm named: awseb-e-g5mkeawrnz-stack-AWSEBCloudwatchAlarmHigh-APCUnlMHNIS1INFO: Created CloudWatch alarm named: awseb-e-g5mkeawrnz-stack-AWSEBCloudwatchAlarmLow-1UL48B2CC2OM8INFO: Added EC2 instance 'i-7f4b6eb7' to Auto Scaling Group 'awseb-e-g7mkeawrnz-stack-AWSEBAutoScalingGroup-2URX...INFO: Application available at blog-env-zckzptpdgy.elasticbeanstalk.com.INFO: Successfully launched environment: blog-env
The environment should now be running. To see the status and URL:
$ eb statusEnvironment details for: blog-envApplication name: blogRegion: us-west-2Deployed Version: b303Environment ID: e-g5mkeawrnPlatform: 64bit Amazon Linux 2015.03 v1.3.0 running Ruby 2.2Tier: WebServer-StandardCNAME: blog-env-zckzptpdg2.elasticbeanstalk.comUpdated: 2015-04-19 23:51:59.259000+00:00Status: ReadyHealth: Green
The last thing that we have to do to get Rails set up is to add a SECRET_KEY_BASE environment variable.
To generate a new secret key use:
$ rake secretf655b5cfeb452e49d9182c6b5e6856704e6e1674082fa1e5f1a330782bad1833ba4cc30951e094f9250c87573dc0bbd3d46d37c5d79ff57...
Then in order to add the secret to your elastic beanstalk environment, use:
$ eb setenv SECRET_KEY_BASE=f655b5cfeb452e49d9182c6b5e6856704e6e1674082fa1e5f1a330782bad1833ba4cc30951e094f9250...
Now if you navigate to [YOUR-ENV].elasticbeanstalk.com/posts you should see your posts index view:
Right now our app is just using SQLite, which is not made for production use and cannot be shared across instances. We can solve this by adding PostgreSQL to your app and to your Elastic Beanstalk environment.
Open your Gemfile. Move the sqlite3 gem into your development andtest block and add a production group with the pg gem in it. Afterward it should look something like this:
source 'https://rubygems.org'
gem 'rails', '4.2.1'
gem 'sass-rails', '~> 5.0'
gem 'uglifier', '>= 1.3.0'
gem 'coffee-rails', '~> 4.1.0'
gem 'jquery-rails'
gem 'turbolinks'
gem 'jbuilder', '~> 2.0'
gem 'sdoc', '~> 0.4.0', group: :doc
group :development, :test do# Use sqlite3 as the database for Active Recordgem 'sqlite3', '~> 1.3.10'
# Call 'byebug' anywhere in the code to stop execution and get a debugger console
gem 'byebug'
# Access an IRB console on exception pages or by using <%= console %> in views
gem 'web-console', '~> 2.0'
# Spring speeds up development by keeping your application running in the background. Read more: [https://github.com/rails/spring](https://github.com/rails/spring)
gem 'spring'
end
group :production do# Use PostgreSQL as the database for Active Recordgem 'pg', '~> 0.18.1'end
Now run $ bundle install to install the gem.
Database credentials should never be hard coded and Elastic Beanstalk makes setting them as environment variables quite simple. RDS variables are configured and updated automatically so your production section of config/database.yml can be updated to the following:
production:<<: *defaultadapter: postgresqlencoding: unicodedatabase: <%= ENV['RDS_DB_NAME'] %>username: <%= ENV['RDS_USERNAME'] %>password: <%= ENV['RDS_PASSWORD'] %>host: <%= ENV['RDS_HOSTNAME'] %>port: <%= ENV['RDS_PORT'] %>
Now let’s add the database to our environment. This takes a few steps but I’ll walk you through it. First go to the Elastic Beanstalk section in the AWS console: console.aws.amazon.com/elasticbeanstalk/?region=us-west-2 (Note the region is us-west-2, if you deployed to a different region, check there.)
Now click on blog-env and go to configuration on the left nav. At the bottom you should see:
Now click “create a new RDS database”, set the DB Engine to “postgres” and create a Master Username and Master Password.
Click “Save” and you will have a fully functioning PostgreSQL instance and the environment variables will have been added to your Beanstalk environment automatically.
Now to install the pg gem on your server the postgresql93-devel yum package is required. Configuring packages on Elastic Beanstalk instances is as simple as dropping a YAML formatted .config file in a top level .ebextensions folder.
# .ebextensions/packages.configpackages:yum:postgresql93-devel: []
Now commit this change and redeploy the app.
$ git add -A && git commit -am "Add PostgreSQL as production database"$ eb deploy
Once this is done you can reload the /posts page and see your fully-functional postgres-backed Rails app! Hooray!