How to deploy a Ruby on Rails application to AWS Elastic Beanstalk
Overview
This tutorial will show you how to deploy a Rails application to AWS Elastic Beanstalk.
Using Elastic Beanstalk is just one of many (perhaps an infinite number of!) AWS deployment options. Each approach has different pros and cons. I’ll briefly go over some of them because it’s good to understand the pros and cons of various approaches (at least to an extent) before choosing one.
Manual EC2 deployment
One option is to do things “the old fashioned way” and manually set up a Rails application on a single EC2 instance. This is the approach I go over in this AWS/Rails deployment post and it’s perfectly fine for hobby projects where the stakes are low.
The downside to manual EC2 deployment is you end up with a snowflake server, a server with a one-of-a-kind configuration that’s hard to understand, modify, or replicate.
Elastic Beanstalk
Elastic Beanstalk is kind of analogous to Heroku. The basic idea is the same in that both Elastic Beanstalk and Heroku are abstraction layers on top of AWS services. The big difference is that Heroku is generally really easy and Elastic Beanstalk is a giant pain in the ass.
But the upside is that EB provides more easily replicable and understandable server instances than a manual EC2 instance. The server configuration is expressed in files, and then that configuration can be applied to an indefinite number of servers. This makes scaling easier. It’s also nice to know that if I somehow accidentally blow away one of my EC2 instances, EB will just automatically spin up a new identical one for me.
Another drawback to EB is that I understand EB can be kind of overly rigid. I ran into this trouble myself on a project where I needed to set up Sidekiq. I discovered that EB boxed me in in a way that made Sidekiq setup very difficult. So for a production project that grows over time, EB is perhaps a good place to start, but it should be expected that you might want to migrate to something more flexible sometime in the future.
An infrastructure-as-code approach
An infrastructure-as-code approach is probably the best long-term solution, although it currently also seems to be the most difficult and time-consuming to set up initially.
Options in this area include Ansible, Chef, Puppet, ECS, and probably a lot more. I’ve personally only used Ansible. I found Ansible to be great. This post will of course only cover Elastic Beanstalk though.
Configuration steps
Here are the steps we’ll be carrying out in this tutorial.
- Install the Elastic Beanstalk CLI
- Create the Elastic Beanstalk application
- Create the Elastic Beanstalk environment
- Create the RDS instance
- Deploy
Let’s get started.
Install the Elastic Beanstalk CLI
Much of what we’ll be doing involves the Elastic Beanstalk CLI (command-line interface). It can be installed with this command:
Create the Elastic Beanstalk application
Now cd
into the directory that contains your Rails project and run eb init
.
When prompted, Select Create new Application
. Accept the defaults for all other options.
When this command finishes running you’ll end up with a file called .elasticbeanstalk/config.yml
that looks something like this:
branch-defaults: master: environment: null group_suffix: null global: application_name: discuss_with branch: null default_ec2_keyname: aws-eb-cwj-post default_platform: Ruby 2.6 (Passenger Standalone) default_region: us-east-1 include_git_submodules: true instance_profile: null platform_name: null platform_version: null profile: personal repository: null sc: git workspace_type: Application
Now that we’ve created our Elastic Beanstalk application, we’ll need to create an Elastic Beanstalk environment inside of that application. I typically set up one production environment and one staging environment inside a single application.
Create the Elastic Beanstalk environment
The command to create an environment is eb create
.
You’ll be prompted for what to call your environment. I called mine discuss-with-production
.
For load balancer type, choose application
.
This step will take a long time. When it finishes, health will probably be “Severe”. Ignore this.
Set up SECRET_KEY_BASE
We’ll need to set a value for the SECRET_KEY_BASE
environment variable. This can be done using the following eb setenv
command which just sets the variable to a random string.
Set up ebextensions
With Elastic Beanstalk, you can add files in an .ebextensions
directory at your project root to control how your server is configured. We need to add three ebextensions
files.
The first, .ebextensions/01_ruby.config
, looks like this:
The second, .ebextensions/02_yarn.config
, looks like this:
The last, .ebextensions/gem_install_bundler.config
, looks like this:
Deploy the application
Now we can make our first deployment attempt.
Unfortunately, it doesn’t work. We get an error that says: /opt/elasticbeanstalk/hooks/appdeploy/pre/12_db_migration.sh failed.
Why does this happen? Because he haven’t set up a database yet. Let’s do that now.
Create the RDS instance
In the AWS console, go to RDS, go to Databases, and click Create database.
Choose Postgresql and Free tier.
Choose whatever name you like for your database. I’m calling mine discuss-with-production
For size, choose t2.micro.
Make sure to set public accessibility to Yes so you can remotely connect to your database from your development machine.
Click Create database.
On the next screen, click View credential details.
Copy what’s there to a separate place for later use. You’ll also need the RDS instance’s endpoint URL which is found in a different place, under Connectivity & security and then Endpoint & port.
Make sure your database’s security group has port 5432 open.
Set the database credentials and create the database instance
Our production server will need to know the database endpoint URL and database credentials. Run the eb setenv
command, with your own values of course replaced for mine, to set these values.
Even though the RDS instance exists, our actual PostgreSQL instance doesn’t exist yet. The RDS instance itself is more like just a container. We can run the rails db:create
command remotely on the RDS instance by supplying the RDS endpoint URL when we run rails db:create
.
Before running this command, make sure the production
section of config/database.yml
matches up with these environment variable names as follows:
Now create the database.
Deploy the application
Now the application can finally be deployed for real using eb deploy
.
Once this finishes you can use the eb open
command to visit your environment’s URL in the browser.
Comments
Post a Comment