Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Ruby

ปรับใช้ Rails 6 บน AWS Elastic Beanstalk และ RDS ได้อย่างราบรื่น: คู่มือฉบับสมบูรณ์

เมื่อเขียนแอปพลิเคชัน หนึ่งในประเด็นหลักที่ต้องคิดคือวิธีที่แอปจะถูกแชร์ให้โลกทราบ

วิธีทั่วไปคือการเปิดตัวบน Heroku มันตั้งค่าได้ง่ายและจัดการให้เต็มที่ แต่ทีมมักจะเลิกใช้ Heroku ต่อมา เนื่องจากเมื่อトラフィคเพิ่มขึ้น Heroku จะแพงเกินไปและไม่ยืดหยุ่น

จะเป็นอย่างไรถ้าสามารถปรับใช้แอปใหม่ได้ด้วยความสะดวกของ Heroku โดยไม่ต้องเสียความยืดหยุ่นและการประหยัดต้นทุนจากแพลตฟอร์มทั่วไปอย่าง AWS? ทำได้ด้วย Elastic Beanstalk — บริการจาก AWS

ในบทความนี้ ผมจะแนะนำการตั้งค่าแอปพลิเคชัน Rails 6 และรันบน AWS โดยใช้ Elastic Beanstalk เป็นฐานคอมพิวต์ และ RDS (Relational Database Service) — โดยเฉพาะบริการ Postgres — เป็นที่เก็บข้อมูล

ในตอนท้ายของบทช่วยสอนนี้ คุณควรจะสามารถ:

  1. ตั้งค่าแอป Rails 6 พร้อมเส้นทางบางส่วนและรันในเครื่องได้
  2. สร้างบัญชี AWS
  3. ตั้งค่าและปรับใช้แอปไปยัง Elastic Beanstalk โดยใช้ทรัพยากร free-tier

มาเริ่มกันเลย

Elastic Beanstalk และ RDS คืออะไร?

เพื่อเข้าใจ Elastic Beanstalk และปัญหาที่มันแก้ไข เรามาพูดถึง EC2 ของ Amazon ก่อน

EC2 ย่อมาจาก Elastic Compute Cloud 2 บริการนี้อนุญาตให้คุณจัดเตรียม VPC ซึ่งคือคอมพิวเตอร์ที่รัน OS ที่คุณเลือก (เช่น Ubuntu) แอปของคุณจะอยู่ในคอมพิวเตอร์นี้และเข้าถึงทรัพยากรอย่างไฟล์ระบบและ RAM เพื่อทำหน้าที่ ในที่สุด แอปของคุณจะทำงานคล้ายกับบนเครื่องโลคอล แต่ในเครื่องของ Amazon ที่เข้าถึงได้ผ่านอินเทอร์เน็ต

จินตนาการผู้ใช้ชื่อ Alice ที่จัดเตรียมอินสแตนซ์บน EC2 Alice จะต้อง:

  • ตั้งค่า security group เพื่ออนุญาตคำขอไปยังแอปของเธอ
  • ตั้งค่า load balancer
  • SSH เข้าอินสแตนซ์ ตั้งค่าแอปและ environment secrets ต่างๆ

แม้จะให้ควบคุมเครื่องเต็มที่ แต่บางครั้งคุณอยากโฟกัสที่แอป ไม่ใช่โครงสร้างพื้นฐาน นี่คือที่มาของ Elastic Beanstalk

Elastic Beanstalk มี CLI ที่ทำให้ทำสิ่งเหล่านี้ง่ายขึ้น และจะทำให้ส่วนใหญ่เป็นอัตโนมัติ เช่น การสร้าง security groups และ load balancers ในขณะที่โครงสร้างพื้นฐานยังคงเป็น EC2 แต่มีเลเยอร์การนามธรรมเพิ่มขึ้น พร้อมแดชบอร์ดภาพที่ช่วยให้ตั้งค่าตัวแปรสภาพแวดล้อม ฐานข้อมูล auto-scaling ดู logs และทำฟังก์ชันอื่นๆ ได้อย่างง่ายดาย

Rails คืออะไร?

มีเครื่องมือมากมายสำหรับรันเว็บแอปพลิเคชัน โดยเฟรมเวิร์กที่เลือกใช้มักถูกบังคับโดยภาษาที่เขียน

ถ้าภาษาที่เลือกคือ Ruby เฟรมเวิร์กยอดนิยมคือ Rails (หรือ Ruby on Rails) Rails ถูกสร้างที่ Basecamp ในปี 2003 และพัฒนาเป็นเฟรมเวิร์กเต็มรูปแบบที่สมบูรณ์มาก รวมทุกอย่างที่คุณคิดได้สำหรับสร้างเว็บแอปสมัยใหม่

สิ่งที่สร้างได้กับ Rails ตั้งแต่บล็อกส่วนตัวง่ายๆ จนถึงระบบซับซ้อนอย่าง Airbnb และ GitHub — ใช่ บริษัททั้งสองรันบน Rails!

แม้บทความนี้ใช้ตัวอย่าง Rails บน AWS แต่มุมมองหลักใช้ได้กับภาษาและเฟรมเวิร์กอื่นๆ เช่น Python/Django หรือ PHP/Laravel

ตั้งค่า Rails

คำสั่งที่แสดงจะทำงานบนระบบ UNIX/Linux ทันที หากใช้ Windows พิจารณาใช้ Windows Subsystem for Linux และ/หรือ Microsoft Windows Terminal

ตรวจสอบเวอร์ชัน Ruby ก่อน:

ruby -v

เวอร์ชัน 2.5.0 ขึ้นไปใช้ได้ หากไม่ใช่ ไปดาวน์โหลดเวอร์ชันล่าสุด ผมใช้ 2.6.5

ถ้าการติดตั้ง Ruby ปกติ ติดตั้ง Rails:

gem install rails

ยืนยันเวอร์ชัน Rails:

rails --version

ถ้ามี 6.0.0 ขึ้นไป พร้อมสำหรับบทช่วยสอนนี้

ตั้งค่า Postgres

เราจะใช้ Postgres DB เป็นที่เก็บข้อมูล นี่คือคู่มือการติดตั้งที่ดีสำหรับทุกแพลตฟอร์ม

เพิ่มและรันโค้ดของเรา

เราจะสร้าง API เรียบง่ายสำหรับเก็บข้อมูลหนัง เช่น ชื่อ ปีเปิด และแนวหนัง API มีแค่ 2 endpoints: GET และ POST เพื่อสาธิต

สร้างแอป Rails API ใหม่:

rails new movie-api --api --database=postgresql

หลังคำสั่งรวมเสร็จ เปลี่ยน directory ไปโฟลเดอร์โปรเจกต์ก่อนรันคำสั่งต่อไป

สร้างโมเดล:

rails generate model Movie name:string year:integer genre:string

ตั้งค่าฐานข้อมูลและรันไมเกรชัน:

rails db:setup
rails db:migrate

ถ้าสำเร็จ คุณจะเห็นไมเกรชันใหม่ใน db/migrate ที่มีโค้ดคล้ายนี้:

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

เพิ่มลอจิกคอนโทรลเลอร์สำหรับ API endpoints:

rails g controller api/Movies

เพิ่มโค้ดต่อไปนี้ใน 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

ตั้งค่าเส้นทางใน config/routes.rb:

Rails.application.routes.draw do
  namespace :api do
    resource :movies
  end
end

ตรวจสอบด้วย rails routes ควรเห็น output คล้ายรูป: ปรับใช้ Rails 6 บน AWS Elastic Beanstalk และ RDS ได้อย่างราบรื่น: คู่มือฉบับสมบูรณ์

เพิ่ม seed data ใน db/seeds.rb:

movies = Movie.create([
  { name: 'Star Wars', year: 1977, genre: 'SCI-FI'},
  { name: 'Lord of the Rings', year: 2001, genre: 'Fantasy' }
])

รันคำสั่งเพื่อเพิ่มข้อมูล:

rails db:seed

รัน API:

rails s

ไปที่ https://127.0.0.1:3000/api/movies ควรเห็น 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" }
]

สร้างบัญชี AWS

ไปที่เว็บไซต์ AWS ถ้ายังไม่มีบัญชี จะเห็นหน้าลงทะเบียน คลิกปุ่มส้ม Create an AWS Account มุมขวาบน (หรือ sign in ถ้ามีอยู่แล้ว) กรอกฟอร์ม (เลือก Account Type เป็น Personal) และ verify อีเมล

ปรับใช้ Rails 6 บน AWS Elastic Beanstalk และ RDS ได้อย่างราบรื่น: คู่มือฉบับสมบูรณ์

ตั้งค่า IAM User

ขั้นตอนต่อไป สร้าง IAM user เพื่อให้ได้ API keys สำหรับ SSH และเข้าถึงทรัพยากรจากภายนอก AWS และเพื่อความปลอดภัย ควรมี IAM user แยกที่เข้าถึงเฉพาะทรัพยากรที่ต้องการ แทนที่จะใช้ admin credentials ตั้งต้น

บนหน้าแรก ค้นหา IAM และไปหน้า IAM home

ปรับใช้ Rails 6 บน AWS Elastic Beanstalk และ RDS ได้อย่างราบรื่น: คู่มือฉบับสมบูรณ์

ภายใต้ IAM Resources คลิก Users: 0

ปรับใช้ Rails 6 บน AWS Elastic Beanstalk และ RDS ได้อย่างราบรื่น: คู่มือฉบับสมบูรณ์

คลิก Add User กรอกชื่อผู้ใช้ เลือก Programmatic access

ปรับใช้ Rails 6 บน AWS Elastic Beanstalk และ RDS ได้อย่างราบรื่น: คู่มือฉบับสมบูรณ์

หน้าถัดไป เลือก Attach existing policies directly ค้นหา AdministratorAccess

ปรับใช้ Rails 6 บน AWS Elastic Beanstalk และ RDS ได้อย่างราบรื่น: คู่มือฉบับสมบูรณ์

เพิ่ม name tag เพื่อระบุ user นี้ภายหลัง

ปรับใช้ Rails 6 บน AWS Elastic Beanstalk และ RDS ได้อย่างราบรื่น: คู่มือฉบับสมบูรณ์

หน้าตรวจสอบ คลิก Create User

หน้าถัดไป ดาวน์โหลดไฟล์ CSV credentials เราจะต้องใช้ในขั้นสุดท้าย

เปิดไฟล์ credentials.csv ดูค่า Access key ID และ Secret access key

สร้างโฟลเดอร์ .aws ใน HOME folder และไฟล์ config ภายใน (โฟลเดอร์ขึ้นต้นด้วยจุด ไฟล์ไม่มี extension) path เต็มประมาณ /Users/your-user/.aws/config

ถ้าสร้างโฟลเดอร์และไฟล์ไม่ได้ ข้ามไปได้ สำคัญคือมีไฟล์ CSV credentials ไว้ใช้

ใส่ในไฟล์ 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 หาได้ที่มุมขวาบนของหน้าบัญชี AWS

สร้าง RDS DB

สร้าง Postgres DB ที่แอปจะติดต่อ ค้นหา RDS จากหน้าแรก

หน้า RDS คลิก Create database

ปรับใช้ Rails 6 บน AWS Elastic Beanstalk และ RDS ได้อย่างราบรื่น: คู่มือฉบับสมบูรณ์

เลือก Standard Create ภายใต้ Engine Options เลือก PostgreSQL

ปรับใช้ Rails 6 บน AWS Elastic Beanstalk และ RDS ได้อย่างราบรื่น: คู่มือฉบับสมบูรณ์

เลือก Free tier ภายใต้ Templates และใต้ Settings ให้ DB instance identifier เป็น movie-api Master username เป็น postgres ตั้งรหัสผ่าน

ปรับใช้ Rails 6 บน AWS Elastic Beanstalk และ RDS ได้อย่างราบรื่น: คู่มือฉบับสมบูรณ์

ข้าม DB instance size, Storage, Availability & durability ภายใต้ Connectivity เลือก Additional connectivity configuration ตั้ง Publicly accessible = Yes และ VPC Security group = Create new

ปรับใช้ Rails 6 บน AWS Elastic Beanstalk และ RDS ได้อย่างราบรื่น: คู่มือฉบับสมบูรณ์

ข้าม Database authentication ภายใต้ Additional configuration ใส่ Initial database name เช่น movie_api_db แล้วคลิก Create Database

กลับหน้า RDS dashboard คลิก default group ภายใต้ VPC Security groups คอลัมน์ขวา

ปรับใช้ Rails 6 บน AWS Elastic Beanstalk และ RDS ได้อย่างราบรื่น: คู่มือฉบับสมบูรณ์

ล่างหน้า เลือก Inbound แก้ไข rules:

ปรับใช้ Rails 6 บน AWS Elastic Beanstalk และ RDS ได้อย่างราบรื่น: คู่มือฉบับสมบูรณ์

ตรวจสอบ Outbound rules:

ปรับใช้ Rails 6 บน AWS Elastic Beanstalk และ RDS ได้อย่างราบรื่น: คู่มือฉบับสมบูรณ์

สร้าง Elastic Beanstalk App

ไปหน้า Elastic Beanstalk คลิก Create New Application

ปรับใช้ Rails 6 บน AWS Elastic Beanstalk และ RDS ได้อย่างราบรื่น: คู่มือฉบับสมบูรณ์

กรอกฟอร์มแอปใหม่

ปรับใช้ Rails 6 บน AWS Elastic Beanstalk และ RDS ได้อย่างราบรื่น: คู่มือฉบับสมบูรณ์

จะเห็นข้อความ No environments currently exist for this application. Create one now. คลิก Create one now

เลือก Web server environment

ปรับใช้ Rails 6 บน AWS Elastic Beanstalk และ RDS ได้อย่างราบรื่น: คู่มือฉบับสมบูรณ์

ตั้ง Environment name = production-env Domain เว้นว่าง ภายใต้ Base Configuration เลือก Preconfigured platform และ Ruby จาก dropdown Application code ปล่อย Sample application คลิก Create environment (ใช้เวลาสักพัก)

ปรับใช้ Rails 6 บน AWS Elastic Beanstalk และ RDS ได้อย่างราบรื่น: คู่มือฉบับสมบูรณ์

เสร็จแล้วจะเห็นหน้าประมาณนี้:

ปรับใช้ Rails 6 บน AWS Elastic Beanstalk และ RDS ได้อย่างราบรื่น: คู่มือฉบับสมบูรณ์

หา URL หลัง environment ID คลิกเพื่อดูแอป Ruby เริ่มต้นบน Elastic Beanstalk เร็วๆ นี้ API ของคุณจะรันที่ URL เดียวกัน

เตรียมแอปสำหรับการปรับใช้

ตั้งค่าเว็บเซิร์ฟเวอร์ก่อน Rails มาพร้อม Puma (production-ready web server) เป็น default server แก้ไข config ที่ 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

แก้ส่วนท้ายของ config/database.yml โดย comment production config เดิม และใช้แทน:

production:
  url: <%= ENV['DATABASE_URL'] %>

ไปที่ Elastic Beanstalk console เลือก environment production-env แล้ว Configuration

หน้า configuration overview คลิก Modify สำหรับ Software:

ปรับใช้ Rails 6 บน AWS Elastic Beanstalk และ RDS ได้อย่างราบรื่น: คู่มือฉบับสมบูรณ์

เพิ่ม DATABASE_URL และ RAILS_ENV แล้วกด Apply:

ปรับใช้ Rails 6 บน AWS Elastic Beanstalk และ RDS ได้อย่างราบรื่น: คู่มือฉบับสมบูรณ์

DB URL สร้างจาก Endpoint ที่บันทึกจาก RDS dashboard รูปแบบ postgresql://postgres:YOURPASSWORD@ENDPOINT:5432/movie_api_db ถ้าลืมรหัสผ่าน เปลี่ยนได้ในส่วน Modify ของ DB RDS dashboard

การปรับใช้ด้วยตนเอง

แค่สร้างไฟล์ zip ของแอปจาก command line และอัปโหลดบน Elastic Beanstalk console

cd เข้าโฟลเดอร์โปรเจกต์ สร้าง zip:

zip -r deploy_1.zip .

deploy_1.zip จะปรากฏในโปรเจกต์ directory ไปที่ AWS

จาก Elastic Beanstalk dashboard คลิก Upload and Deploy:

ปรับใช้ Rails 6 บน AWS Elastic Beanstalk และ RDS ได้อย่างราบรื่น: คู่มือฉบับสมบูรณ์

เปลี่ยน version label ให้มีความหมาย:

ปรับใช้ Rails 6 บน AWS Elastic Beanstalk และ RDS ได้อย่างราบรื่น: คู่มือฉบับสมบูรณ์

Elastic Beanstalk อัปเดต environment เสร็จ เยี่ยม environment URL จะเห็น API ทำงาน! ใช้บริการฟรีเพื่อส่ง request และ populate DB บน AWS

การปรับใช้ด้วย EB CLI

Elastic Beanstalk CLI ทำให้สิ่งที่ทำด้วยตนเองง่ายขึ้นด้วยคำสั่งไม่กี่คำ แสดงวิธีตั้งค่าและใช้กับโปรเจกต์ปัจจุบัน ขึ้นอยู่กับ IAM user ที่ตั้งค่าถูกต้อง

ส่วนใหญ่มี Python ติดตั้งอยู่แล้ว ติดตั้งง่ายๆ:

pip install awsebcli --user

บน MacOS:

brew install awsebcli

cd ไปโปรเจกต์ รัน eb init

ตอบ prompts ตามสภาพแวดล้อม AWS เลือก region โดยใส่หมายเลข:

Select a default region
1) us-east-1 : US East (N. Virginia)
2) us-west-1 : US West (N. California)
...
17) eu-west-3 : EU (Paris)

ส่วน Ruby version เลือกเวอร์ชันที่ใช้ Puma:

1) Ruby 2.6 (Passenger Standalone)
2) Ruby 2.6 (Puma)
...
15) Ruby 1.9.3

ผมเลือก 2

ตอบ prompts ที่เหลือ เลือก 'no' สำหรับ CodeCommit และ 'no' สำหรับ SSH setup

ถ้ายังไม่ตั้งค่า AWS config CLI จะขอ AWS keys ใส่ตามที่ต้องการ

เสร็จแล้ว CLI จะออก รันคำสั่งอย่าง eb status เพื่อเช็คสถานะ:

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

ปรับใช้เวอร์ชันใหม่ รัน eb deploy

แค่นั้น! อ่านคำสั่ง CLI อื่นๆ ได้ที่นี่

สรุป

ในบทช่วยสอนนี้ เราเรียนรู้การตั้งค่า Rails API เรียบง่าย ตั้งค่าทรัพยากร AWS เช่น Elastic Beanstalk และ RDS และปรับใช้แอปเพื่อใช้ทรัพยากรเหล่านั้น

เรายังครอบคลุมการใช้ EB CLI เพื่อทำให้การปรับใช้เป็นอัตโนมัติ ตอนนี้คุณเรียนรู้แล้วว่าจะนำแอปที่ทำงานในเครื่องไปสู่แอปที่ทำงานบน AWS ได้อย่างไร