Deploy and Manage Production Rails 5 App with AWS Elastic Beanstalk

Play around with AWS Elastic Beanstalk (EB) configurations and share experiences for Rails deployment automation.

Photo by Tim Gouw on Unsplash

From my recently Rails 5 project, sometime deploying the project become a daunting task and get slow down development process. While I have been using Capistrano like a main supporter in deployment, it seems to have no chance suitable to load balancing and auto-scaling servers on AWS (Amazon Web Services) infrastructure if the project have gained popularity.

In this story, I want to share my experiences about AWS Elastic Beanstalk configuration and troubleshooting.

Thankfully, here is their solution mentioned as AWS Elastic Beanstalk:

AWS Elastic Beanstalk is an easy-to-use service for deploying and scaling web applications and services developed with Java, .NET, PHP, Node.js, Python, Ruby, Go, and Docker on familiar servers such as Apache, Nginx, Passenger, and IIS.
You can simply upload your code and Elastic Beanstalk automatically handles the deployment, from capacity provisioning, load balancing, auto-scaling to application health monitoring. At the same time, you retain full control over the AWS resources powering your application and can access the underlying resources at any time.
There is no additional charge for Elastic Beanstalk — you pay only for the AWS resources needed to store and run your applications.

The most interesting parts of EB from my experiences on current project:

  • Handles the deployment process, you just need to bundle the app and send to EB then you’re free to do others thing. Don’t need to wait for processing tasks via SSH connection, as result in speed up your development.
  • Handles load balancing, auto-scaling by triggered to the app health monitoring. You can easy to setting up from EB management console.
  • And finally, no additional charge for using EB. If you are using the same resources (EC2, CloudFront, S3, RDS, Route 53, ElasticCache,…) then EB won’t add more charges to your bill.

But downside, that EB is not really easy to started when you want to deploy a complex project that requires writing external customization. And I had been experienced stuck in several days. If you find out some points useful from my story, then that’s why I would like to share them.


Using Development Environment

Here is the environment that my project is developing on:

  • Linux/Ubuntu 17.04
  • Ruby 2.5
  • NodeJS
  • Yarn
  • Python 2.7.1
  • Rails 5.2
  • Puma
  • MySQL

Getting started your tool belt

After install the CLI, you can update and verify it

$pip install awsebcli --upgrade --user && eb --version

Setting up EB application

Assumes your Rails project is ready to deploy, then go to the project directory, initialize EB application first:

$eb init

After running the command, you will be asked some questions concern to the application configs on EB such as:

  • Default deploy region (us-west-2)
  • Create new application on EB and define its name.
  • Select platform version (Ruby 2.5 + Puma)
  • Setup SSH to your instances? (Yes)

If you have already config AWS CLI before, it will be get the default region from that, you’re free to change later. When you have many applications on EB with the same platform version, it will ask you to choose or create new application. For my project, I’m using Ruby 2.5 + Puma app server. Also, I want to create SSH connection to instances with registered private key.

End up progress above you will see .elasticbeanstalk/config.xml in your project folder and almost everything you can change later.

Notes: If you’re using an old platform, then want to update its version. You can do it via AWS CLI, not in EB CLI and EB Management Console. The command is similar to:

Setting up EB environment

After done with creating EB application, if you log into your AWS console and head over to Elastic Beanstalk, you’ll see your just created app. Then everything is ready to go next.

At this step, you will create the environment of your app that want to deploy on EB. Usually you would like to define them like ‘myapp-development’, ‘myapp-stage’, ‘myapp-production’ depend on how you set up environment variables to the app later then.

To create the environment.

$eb create myapp-development

Then EB will bundle your project into zip file, upload to the cloud server, … just wait moreover EB is setting everything up for you, load balancer, security groups, EC2 servers, auto scaling group and more. And you can manage all things in one place.

But at here deploying process of the project would be failed, because the project need to install several prerequisite packages on EC2 server where .ebextensions come to help us modify environment configuration with files.

Creating your .ebextensions config files

In the project folder, you will create .ebextensions folder that contain all customization config files.

For my project, here is additional Linux packages that required to build process. Especially I need some software such as curl, git, mysql-devel, node, yarn and several related packages.

You would like to know that EB use to Amazon Linux AMI is a Linux image that have the repositories are accessed via yum.

This file will customize software on Linux server. As you see above, I have used to two keys packages and commands

You can use the packages key to download and install prepackaged applications and components.
You can use the commands key to execute commands on the EC2 instance. The commands are processed in alphabetical order by name, and they run before the application and web server are set up and the application version file is extracted.

After installing required software on the server, I want to run yarn install for downloading front-end libraries.

$yarn install

The command above should run at specific step in deployment process, how to do it? you will need create the file that hooks to EB deployment process like this

Look at the file name is created 101_yarn_packages.sh, in fact it will run right after 10_bundle_install.sh file executed.

Now, you can run deploy command

$eb deploy

Verify your config scripts were executed successfully, also you can access the instance via SSH

$eb ssh

And check files existed in the folder specified. The project might be failed, just because it is configured incompletely. Let’s check deployment logs

$eb logs 

Checking Rails app environment variables

Besides, one of my experiences that you should double check the app environment variables (ENV) which used in your Rails app.

You can print environment variables with CLI

$eb printenv

change or add more ENV

$eb setenv RACK_ENV=development 

or from modifying Software of Configuration tab on EB management console.

Have several variables should be verified

BUNDLE_WITHOUT
RACK_ENV
RAILS_SKIP_ASSET_COMPILATION
RAILS_SKIP_MIGRATIONS
SECRET_KEY_BASE

And other ENV variables that are required to running app correctly.

Notes: When you set RACK_ENV=development and RAILS_SKIP_ASSET_COMPILATION=false for EB environment. It means that your Rails app will map to using Development environment settings from config/environment/development.rb and also run rake assets:precompile during deployment progress. So if you set config.assets.debug=true, you could get errors when assets is not found in the pipeline, because of mismatching asset hash-fingers included. Then let turn off debug mode.

Concern to connecting RDS

There are two ways of creating database connection. Firstly, in case you want to create new Amazon Relational Database Service (RDS) with your database engine. You should create it from EB management console under Database card of Configuration tab then RDS can integrate to your EB environment. After that comeback and update your app ENV.

However, if you want to connect to existing RDS, just need to define ENV in EB configuration console and open RDS security group to EB environment security group with suitable port.

Troubleshooting: In case of, you connect to the same database of RDS instance from multiple EB environment, you might want to check max_connections in parameter groups of RDS. Because it will give you fails during migrating database in deployment progress.

Integrating to CloudFront service

It’s simple to config and use CloudFront (a CDN service) for Rails app. I already write down in another story here. You might want to read it.

Just one thing from my experience, regarding to CORS issue on EB when your CSS want get loading font files or font-awesome. Because EB run your app with Nginx server serve public static files, then work around would be overwriting web server config in Nginx with add_header Access-Control-Allow-Origin ‘*’ by creating .ebextensions file something like

After running deploy app with overwriting Nginx server script above, you also need to re-deploy CloudFront distribution.

Routing traffic for your EB environment with Route 53

You might want to config the app serve HTTPS, then should modify load balancer on EB configuration console. Simplest way that config to listen to 443 port then route to 80 port on the instance

You will be required to create SSL certificate, let do it with AWS Certificate Manager.

With Route 53 service,

You can’t create a CNAME record for the root domain name. For example, if your domain name is example.com, you can create a record that routes traffic for acme.example.com to your Elastic Beanstalk environment, but you can’t create a record that routes traffic for example.com to your Elastic Beanstalk environment.

In that case, you might want to create an alias record.

You can create alias records for the root domain name or for subdomains. For example, if your domain name is example.com, you can create a record that routes requests for example.com or for acme.example.com to your Elastic Beanstalk environment.

When it done, you can access to web app from the domain.

Conclusion

With AWS Elastic Beanstalk, it save my time and speed up development process. Also, in simple configuration approach, it give my application advantages of auto-scaling and optimize load balancing from AWS cloud infrastructure.

AWS Elastic Beanstalk is powerful and flexible modification when you get familiar with its extension configuration files and understanding hooks process.