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.
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
- Go to sign up and get free your AWS account
- Install AWS CLI and config with your account
- Install the EB CLI
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.