Khi viết ứng dụng, một vấn đề lớn bạn phải suy nghĩ là cách ứng dụng sẽ được chia sẻ với thế giới.
Một cách phổ biến là triển khai trên Heroku. Nó dễ setup và fully managed. Nhưng cũng thường thấy teams bỏ Heroku sau. Khi traffic tăng, Heroku trở nên quá đắt và thiếu linh hoạt.
Điều gì nếu có thể deploy ứng dụng mới với sự dễ dàng như Heroku mà không hy sinh sự linh hoạt và tiết kiệm chi phí từ platform chung như AWS? Đó là có thể, dùng Elastic Beanstalk — dịch vụ từ AWS.
Trong bài này, tôi sẽ hướng dẫn setup Rails 6 app và chạy trên AWS dùng Elastic Beanstalk làm compute base và RDS (Relational Database Service) — cụ thể Postgres — làm data store.
Cuối tutorial, bạn sẽ có thể:
- Setup Rails 6 app với vài routes và chạy local.
- Tạo AWS account.
- Setup và deploy app lên Elastic Beanstalk dùng free-tier resources.
Hãy bắt đầu.
Elastic Beanstalk Và RDS Là Gì?
Để hiểu Elastic Beanstalk và vấn đề nó giải quyết, trước hãy nói về EC2 của Amazon.
EC2 là Elastic Compute Cloud 2. Dịch vụ này cho bạn provision VPCs, cơ bản là máy tính, chạy OS bạn chọn (ví dụ Ubuntu). App sẽ sống trong máy này và truy cập resources như file system, RAM để deliver tasks. Cuối cùng, app chạy giống như local, chỉ khác máy thuộc Amazon và accessible qua internet dùng infrastructure của Amazon.
Hãy tưởng tượng user Alice, đã provision instance trên EC2. Alice cần:
- Setup security group cho phép requests đến app.
- Setup load balancer.
- SSH vào instance, setup app và environment secrets, v.v.
Điều này cho full control nhưng đôi khi bạn muốn focus vào app chứ không phải infrastructure. Đó là lúc Elastic Beanstalk xuất hiện.
Elastic Beanstalk cung cấp CLI làm dễ dàng mọi việc này và tự động hóa hầu hết: tạo security groups, load balancers. Infrastructure bên dưới vẫn là EC2, nhưng thêm layer abstraction với visual dashboard cho phép setup environment variables, databases, auto-scaling, lấy logs và các functions khác rất đơn giản.
Rails Là Gì?
Nhiều tools có thể đưa web app lên chạy. Thường library/framework bạn chọn phụ thuộc vào ngôn ngữ.
Nếu ngôn ngữ bạn chọn là Ruby, framework phổ biến là Rails (Ruby on Rails). Rails tạo ra tại Basecamp 2003, qua nhiều năm đã trở thành framework đầy đủ, mature, bao gồm gần như mọi thứ để build modern web app.
Với Rails bạn build từ personal blog đơn giản đến Airbnb, GitHub phức tạp. Chắc bạn biết hai công ty này, và đúng, chúng chạy trên Rails!
Dù bài này dùng ví dụ deploy Rails app lên AWS, hầu hết concepts chính giống nhau bất kể language/framework: Python/Django, PHP/Laravel.
Setup Rails
Lưu ý: commands dưới đây chạy out-of-the-box trên UNIX/Linux. Nếu dùng Windows, hãy dùng Windows Subsystem for Linux và/hoặc Microsoft Windows Terminal.
Trước hết, verify Ruby version:
ruby -v
Bất kỳ version 2.5.0 trở lên đều OK. Nếu không, vào đây lấy latest version. Tôi dùng 2.6.5.
Nếu Ruby OK, install Rails:
gem install rails
Sau đó confirm Rails version:
rails --version
Nếu thấy version trên 6.0.0, bạn ready cho tutorial.
Setup Postgres
Chúng ta dùng Postgres DB làm data store. Đây là guide tuyệt vời cài đặt trên mọi platform.
Thêm Và Chạy Code
Chúng ta build API đơn giản lưu movie data: name, release year, genre. API chỉ có 2 endpoints GET & POST cho demo.
Tạo Rails API app mới:
rails new movie-api --api --database=postgresql
Sau khi command chạy thành công, chắc chắn
cdvào project folder trước khi chạy commands tiếp.
Generate model:
rails generate model Movie name:string year:integer genre:string
Setup database và run migrations:
rails db:setup
rails db:migrate
Nếu thành công, bạn thấy migration mới trong db/migrate giống như:
class CreateMovies < ActiveRecord::Migration[6.0]
def change
create_table :movies do |t|
t.string :name
t.integer :year
t.string :genre
t.timestamps
end
end
end
Thêm controller logic cho API endpoints:
rails g controller api/Movies
Thêm code vào app/controllers/movies_controller.rb:
class Api::MoviesController < ApplicationController
# GET /movies
def show
@movies = Movie.all
render json: @movies
end
# POST /movies
def create
@movie = Movie.new(movie_params)
if @movie.save
render json: @movie
else
render error: {error: 'Failed to add movie record'}, status: 400
end
end
private
def movie_params
params.require(:movie).permit(:name, :year, :genre)
end
end
Setup routes vào config/routes.rb:
Rails.application.routes.draw do
# For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
namespace :api do
resource :movies
end
end
Sanity check với rails routes để verify mọi thứ OK. Output chứa tương tự:

Trước khi chạy server, thêm seed data vào db/seeds.rb:
# This file should contain all the record creation needed to seed the database with its default values.
# The data can then be loaded with the Rails db:seed command (or created alongside the database with db:setup).
movies = Movie.create([
{ name: 'Star Wars', year: 1977, genre: 'SCI-FI'},
{ name: 'Lord of the Rings', year: 2001, genre: 'Fantasy' }
])
Chạy command thêm data vào DB:
rails db:seed
Chạy API:
rails s
Truy cập https://127.0.0.1:3000/api/movies thấy seed data:
[
{
"id": 1,
"name": "Star Wars",
"year": 1977,
"genre": "SCI-FI",
"created_at": "2020-01-01T10:04:56.100Z",
"updated_at": "2020-01-01T10:04:56.100Z"
},
{
"id": 2,
"name": "Lord of the Rings",
"year": 2001,
"genre": "Fantasy",
"created_at": "2020-01-01T10:04:56.108Z",
"updated_at": "2020-01-01T10:04:56.108Z"
}
]
Tạo AWS Account
Vào website này. Nếu chưa có account hoặc chưa sign in từ browser, bạn thấy trang như sau:

Click nút cam Create an AWS Account góc trên phải (hoặc sign in nếu đã có). Điền signup form (chọn Account Type là Personal khi điền địa chỉ), bạn vào console. Đừng quên verify email!
Đừng lo nếu UI overwhelming. Nó đơn giản khi bạn biết đi đâu.
Setup IAM User
Tiếp theo setup IAM user. Cho access API keys để SSH và access resources từ ngoài AWS.
Cũng nên có IAM user riêng chỉ access resources cần thiết thay vì dùng admin credentials mặc định cho security.
Trang home, search IAM và navigate đến IAM home page.

Trên IAM homepage, dưới IAM Resources, click Users: 0.

Click Add User. Điền username, chọn checkbox Programmatic access.

Màn hình tiếp theo, chọn Attach existing policies directly, search AdministratorAccess.

Trang sau, thêm name tag để identify user sau:

Trang review, click Create User.
Trang sau, download CSV file chứa credentials. Cần cho phần sau.
Mở file credentials.csv trong spreadsheet app hoặc editor. Quan tâm nhất: Access key ID và Secret access key.
Cuối cùng, vào HOME folder, tạo folder .aws. Bên trong tạo file config (không extension). Full path như /Users/your-user/.aws/config.
Nếu không tạo được folder
.awsvà fileconfig, có thể skip. Quan trọng là có CSV credentials cho sau.
Đặt vào file config:
[profile eb-cli]
region = us-east-1
aws_access_key_id = your-aws-access-key-id
aws_secret_access_key = your-aws-secret-access-key
AWS region tìm thấy góc trên phải AWS account page khi sign in.
Tạo RDS DB
Tạo Postgres DB để app communicate. Search RDS từ home page.
Trang RDS home, click Create database.

Chọn Standard Create; dưới Engine Options chọn PostgreSQL.

Kéo xuống, chọn Free tier dưới Templates, dưới Settings để DB instance identifier là movie-api. Master username để postgres, thêm password.

Bỏ qua DB instance size, Storage, Availability & durability. Dưới Connectivity, chọn Additional connectivity configuration, set Publicly accessible = Yes, VPC Security group = Create new.

Bỏ qua Database authentication. Dưới Additional configuration, thêm Initial database name; movie_api_db OK. Bỏ qua hết, click Create Database cuối trang.
Quay lại RDS dashboard, click default group dưới VPC Security groups cột phải:

Cuối trang, chọn Inbound edit rules như sau:

Đảm bảo Outbound rules như sau:

Tạo Elastic Beanstalk App
Navigate đến Elastic Beanstalk home, click Create New Application.

Điền form application.

Thấy message No environments currently exist for this application. Create one now. Click Create one now.
Chọn Web server environment.

Đổi Environment name thành production-env. Domain để trống. Dưới Base Configuration, chọn Preconfigured platform chọn Ruby. Application code để Sample application, click Create environment. Mất thời gian, kiên nhẫn.

Xong, thấy trang như sau:

Tìm URL sau environment ID. Click để xem default Ruby app trên Elastic Beanstalk. Sớm API bạn sẽ chạy trên URL đó.
Chuẩn Bị App Cho Deployment
Để app ready cho deployment, config web server trước.
Rails ship Puma — production-ready web server — làm default. Edit config tại config/puma.rb:
max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }
min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count }
threads min_threads_count, max_threads_count
# Specifies the `port` that Puma will listen on to receive requests; default is 3000.
# port ENV.fetch("PORT") { 3000 }
# Specifies the `environment` that Puma will run in.
# environment ENV.fetch("RAILS_ENV") { "development" }
# Specifies the `pidfile` that Puma will use.
pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" }
# Specifies the number of `workers` to boot in clustered mode.
# Workers are forked web server processes. If using threads and workers together,
# the concurrency of the application would be max `threads` * `workers.`
# Workers do not work on JRuby or Windows (both of which do not support
# processes).
# workers ENV.fetch("WEB_CONCURRENCY") { 2 } # <------ uncomment this line
# Use the `preload_app!` method when specifying a `workers` number.
# This directive tells Puma to first boot the application and load code
# before forking the application. This takes advantage of Copy On Write
# process behavior so workers use less memory.
# preload_app! # <------ uncomment this line
# Allow Puma to be restarted by the `Rails restart` command.
plugin :tmp_restart
Edit cuối config/database.yml, comment existing production config, dùng:
production:
url: <%= ENV['DATABASE_URL'] %>
Vào Elastic Beanstalk console, chọn environment production-env, vào Configuration.
Màn hình configuration overview, click Modify cho Software:

Thêm DATABASE_URL và RAILS_ENV, click 'Apply':

DB URL dùng
Endpointtừ RDS dashboard. Format:postgresql://postgres:YOURPASSWORD@ENDPOINT:5432/movie_api_db. Quên password? Đổi ởModifysection của DB RDS dashboard.
Manual Deployment
Đơn giản: tạo zip file app từ command line, upload lên Elastic Beanstalk console.
cd vào project folder. Tạo zip:
zip -r deploy_1.zip .
deploy_1.zip xuất hiện trong project directory. Xong? Vào AWS.
Từ Elastic Beanstalk Dashboard, click Upload and Deploy:

Đổi version label meaningful hơn:

Sau khi Elastic Beanstalk update environment xong, truy cập environment URL xem API running! Dùng free service để send requests populate DB trên AWS.
Deployment Với EB CLI
Elastic Beanstalk CLI làm dễ dàng hầu hết việc manual trên với vài commands. Setup và dùng trên project hiện tại. Phụ thuộc vào IAM user setup đúng, đảm bảo step đó OK hoặc có CSV credentials.
Hầu hết máy đã có Python. Install:
pip install awsebcli --user
MacOS cũng dùng:
brew install awsebcli
Đọc thêm về installation tại đây.
Sau install, cd project folder chạy eb init.
Follow prompts theo AWS environment. Chọn region bằng số:
Select a default region
1) us-east-1 : US East (N. Virginia)
2) us-west-1 : US West (N. California)
3) us-west-2 : US West (Oregon)
4) eu-west-1 : EU (Ireland)
5) eu-central-1 : EU (Frankfurt)
6) ap-south-1 : Asia Pacific (Mumbai)
7) ap-southeast-1 : Asia Pacific (Singapore)
8) ap-southeast-2 : Asia Pacific (Sydney)
9) ap-northeast-1 : Asia Pacific (Tokyo)
10) ap-northeast-2 : Asia Pacific (Seoul)
11) sa-east-1 : South America (Sao Paulo)
12) cn-north-1 : China (Beijing)
13) cn-northwest-1 : China (Ningxia)
14) us-east-2 : US East (Ohio)
15) ca-central-1 : Canada (Central)
16) eu-west-2 : EU (London)
17) eu-west-3 : EU (Paris)
Phần Ruby version, chọn version liên quan dùng Puma:
1) Ruby 2.6 (Passenger Standalone)
2) Ruby 2.6 (Puma)
3) Ruby 2.5 (Passenger Standalone)
4) Ruby 2.5 (Puma)
5) Ruby 2.4 (Passenger Standalone)
6) Ruby 2.4 (Puma)
7) Ruby 2.3 (Passenger Standalone)
8) Ruby 2.3 (Puma)
9) Ruby 2.2 (Passenger Standalone)
10) Ruby 2.2 (Puma)
11) Ruby 2.1 (Passenger Standalone)
12) Ruby 2.1 (Puma)
13) Ruby 2.0 (Passenger Standalone)
14) Ruby 2.0 (Puma)
15) Ruby 1.9.3
Tôi chọn 2.
Làm theo prompts còn lại, chọn 'no' cho CodeCommit và 'no' cho setup SSH.
Nếu không setup AWS config, CLI sẽ prompt AWS keys. Thêm như yêu cầu.
Xong, CLI exit. Chạy commands như eb status check status app deployed.
Environment details for: production-env
Application name: movie-api
Region: us-east-2
Deployed Version: Deploy 2-2
Environment ID: e-mab3kjy6pp
Platform: arn:aws:elasticbeanstalk:us-east-2::platform/Puma with Ruby 2.6 running on 64bit Amazon Linux/2.11.1
Tier: WebServer-Standard-1.0
CNAME: production-env.qnbznvpp2t.us-east-2.elasticbeanstalk.com
Updated: 2020-01-22 23:37:17.183000+00:00
Status: Ready
Health: Green
Deploy version mới, chạy eb deploy.
Xong! Đọc thêm CLI commands khác tại đây.
Tóm Tắt
Trong tutorial, chúng ta học setup Rails API đơn giản, setup AWS resources (Elastic Beanstalk, RDS), deploy app dùng chúng.
Cũng cover dùng Elastic Beanstalk CLI tự động hóa deployments. Bây giờ bạn biết cách từ app chạy local đến app shared với thế giới trên AWS.