AWS Developer Tools Blog
Introducing the ‘aws-rails-provisioner’ gem developer preview
AWS is happy to announce that the aws-rails-provisioner gem for Ruby is now in developer preview and available for you to try!
What is aws-rails-provisioner
?
The new aws-rails-provisioner
gem is a tool that helps you define and deploy your containerized Ruby on Rails applications on AWS. It currently only supports AWS Fargate.
aws-rails-provisioner
is a command line tool using the configuration file aws-rails-provisioner.yml
to generate AWS Cloud Development Kit (CDK) stacks on your behalf. It automates provisioning AWS resources to run your containerized Ruby on Rails applications on AWS Fargate with a few commands. It can also generate a CI/CD AWS CodePipeline pipeline for your applications when you enable its CI/CD option.
Why use aws-rails-provisioner?
Moving a local Ruby on Rails application to a well-configured web application running on the cloud is a complicated task. While aws-rails-provisioner
doesn’t change this into a “one-click” task, it helps ease the most monotonous and detail-oriented aspects of the job.
The aws-rails-provisioner
gem shifts your primary focus to component-oriented definitions inside a concise aws-rails-provisioner.yml file. This file defines the AWS resources your application needs, such as container image environment, a database cluster engine, or Auto Scaling strategies.
The new gem handles default details—like VPC configuration, subnet placement, inbound traffic rules between databases and applications—for you. With CI/CD opt-in, aws-rails-provisioner
can also generate and provision a predefined CI/CD pipeline, including a database migration phase.
For containerized Ruby on Rails applications that you already maintain on AWS, aws-rails-provisioner
helps to keep the AWS infrastructure for your application as code in a maintainable way. This ease allows you to focus more on application development.
Prerequisites
Before using the preview gem, you must have the following resources:
• A Ruby on Rails application with Dockerfile
• A Docker daemon set up locally
• The AWS CDK installed (requires `Node.js` >= 8.11.x) npm i -g aws-cdk
Using aws-rails-provisioner
Getting started with aws-rails-provisioner is fast and easy.
Step 1: Install aws-rails-provisioner
You can download the aws-rails-provisioner
preview gem from RubyGems.
To install the gem, run the following command:
gem install 'aws-rails-provisioner' -v 0.0.0.rc1
Step 2: Define your aws-rails-provisioner.yml file
The aws-rails-provisioner.yml
configuration file allows you to define how and what components you want aws-rails-provisioner
to provision to run your application image on Fargate.
An aws-rails-provisioner.yml
file looks like the following format:
version: '0'
vpc:
max_azs: 2
services:
rails_foo:
source_path: ../sandbox/rails_foo
fargate:
desired_count: 3
public: true
envs:
PORT: 80
RAILS_LOG_TO_STDOUT: true
db_cluster:
engine: aurora-postgresql
db_name: myrails_db
instance: 2
scaling:
max_capacity: 2
on_cpu:
target_util_percent: 80
scale_in_cool_down: 300
rails_bar:
...
aws-rails-provisioner.yml
file overview
The aws-rails-provisioner.yml file contains two parts: vpc
and services
. VPC defines networking settings, such as Amazon VPC hosting your applications and databases. It can be as simple as:
vpc:
max_az: 3
cidr: '10.0.0.0/21'
enable_dns: true
Left unmodified, aws-rails-provisioner
defines a default VPC with three Availability Zones containing public, private, and isolated subnets with a CIDR range of 10.0.0.0/21 and DNS enabled. If these default settings don’t meet your needs, you can configure settings yourself, such as in the following example, which defines the subnets with details:
vpc:
subnets:
application: # a subnet name
cidr_mark: 24
type: private
...
You can review the full range of VPC configuration options to meet your exact needs.
The services
portion of aws-rails-provisioner.yml allows you to define your Rails applications, Database cluster, and Auto Scaling policies.
For every application, you can add their entry with identifiers like:
services:
my_awesome_rails_app:
source_path: ../path/to/awesome_app # relative path from `aws-rails-provisioner.yml`
...
my_another_awesome_rails_app:
source_path: ./path/to/another_awesome_app # relative path from `aws-rails-provisioner.yml`
...
When you run aws-rails-provisioner
commands later, it takes the configuration values of a service—under fargate:
, db_cluster:
, and scaling:
to provision a Fargate service fronted by an Application Load Balancer (DBClusters resource and Auto Scaling policies are optional for a service).
Database cluster
The db_cluster
portion of aws-rails-provisioner.yml
defines database settings for your Rails application. It currently supports Aurora PostgreSQL, Aurora MySQL, and Aurora. You can specify the engine version by appending engine_version
to the command. You can also choose to provide a user name for your databases; if not, aws-rails-provisioner
automatically generates username and password and stores it in AWS Secrets Manager.
To enable storage encryption for the Amazon RDS database cluster, provide kms_key_arn
with the AWS KMS key ARN you use for storage encryption:
my_awesome_rails_app:
source_path: ../path/to/awesome_app
db_cluster:
engine: aurora-postgresql
db_name: awesome_db
username: myadmin
You can review the full list of db_cluster: configuration options to meet your specific needs.
AWS Fargate
The fargate:
portion of aws-rails-provisioner.yml
defines which Fargate services and Tasks that running your application image, for example:
my_awesome_rails_app:
source_path: ../path/to/awesome_app
fargate:
public: true
memory: 512
cpu: 256
container_port: 80
envs:
RAILS_ENV: ...
RAILSLOGTO_STDOUT: ...
...
For HTTPs applications, you can provide certificate
with a certificate ARN from AWS Certificate Manager. This automatically associates with the Application Load Balancer and sets container_port
to 443. You can also provide a domain name and domain zone for your application under domain_name
and domain_zone
. If you don’t provide these elements, the system provides a default DNS address from the Application Load Balancer.
When providing environment variables for your application image, you don’t have to define DATABASE_URL
by yourself; aws-rails-provisioner
computes the value based on your db_cluster
configuration. Make sure to update the config/database.yml
file for your Rails application to recognize the DATABASE_URL
environment variable.
You can review the full list of fargate: configuration options to meet your specific needs.
Scaling
You can also configure the Auto Scaling setting for your service. In this prototype stage, you can configure scaling policies on_cpu
, on_metric
, on_custom_metric
, on_memory
, on_request
, or on_schedule
.
my_awesome_rails_app:
source_path: ../path/to/awesome_app
scaling:
max_capacity: 10
on_memory:
target_util_percent: 80
scale_out_cool_down: 200
on_request:
requests_per_target: 100000
disable_scale_in: true
...
You can review the full list of scaling: configuration options to meet your specific needs.
Step 3: Build and deploy
With aws-rails-provisioner.yml
defined, you can run a build command. Doing so bootstraps AWS CDK stacks in code, defining all the necessary AWS resources and connections for you.
Run the following:
aws-rails-provisioner build
This command initializes and builds a CDK project with stacks—installing all required CDK packages—leaving a deploy-ready project. By default, it generates an InitStack
that defines the VPC and Amazon ECS cluster, hosting Fargate services. It also generates a FargateStack
that defines a database cluster and a load-balanced, scaling Fargate service for each service entry.
When you enable --with-cicd
, the aws-rails-provisioner
also provides a pipeline stack containing source, build, database migration, and deploy stages for each service defined for you. You can enable CI/CD with the following command:
aws-rails-provisioner build --with-cicd
After the build completes, run the following deploy command to deploy all defined AWS resources:
aws-rails-provisioner deploy
Instead of deploying everything all at the same time, you can deploy stack by stack or application by application:
# only deploys the stack that creates the VPC and ECS cluster
aws-rails-provisioner deploy --init
# deploys the fargate service and database cluster when defined
aws-rails-provisioner deploy --fargate
# deploy the CI/CD stack
aws-rails-provisioner deploy --cicd
# deploy only `my_awesome_rails_app` application
aws-rails-provisioner deploy --fargate --service my_awesome_rails_app
You can check on the status of your stacks by logging in to the AWS console and navigating to AWS CloudFormation. Deployment can take several minutes.
Completing deployment leaves your applications running on AWS Fargate, fronted with the Application Load Balancer.
Step 4: View AWS resources
To see your database cluster, log in to the Amazon RDS console.
To see an ECS cluster created, with Fargate Services and tasks running, you can also check the Amazon ECS console.
To view the application via DNS address or domain address, check the Application Load Balancing dashboard.
Any applications with databases need rails migration to work. The generated CI/CD stack contains a migration phase. The following CI/CD section contains additional details.
To view all the aws-rails-provisioner command line options, run:
aws-rails-provisioner -h
Step 5: Trigger the CI/CD pipeline
To trigger the pipeline that aws-rails-provisioner
provisioned for you, you must commit your application source code and Dockerfile with AWS CodeBuild build specs into an AWS CodeCommit repository. The aws-rails-provisioner
gem automatically creates this repository for you.
To experiment with application image build and database migration on your own, try these example build spec files from the aws-rails-provisioner GitHub repo.
Conclusion
Although aws-rails-provisioner
for RubyGems is currently under developer preview, it provides you with a powerful, time-saving tool. I would love for you to try it out and return with feedback for how AWS can improve this asset before its final launch. As always, you can leave your thoughts and feedback on GitHub.