- vừa được xem lúc

Hướng dẫn deploy ứng dụng Ruby on Rails lên AWS EC2

0 0 4

Người đăng: Phuc Dang Xuan

Theo Viblo Asia

1. Giới thiệu

AWS (Amazon Web Services) là một trong những nền tảng cloud phổ biến nhất hiện nay. Trong bài viết này, chúng ta sẽ hướng dẫn cách triển khai một ứng dụng Ruby on Rails lên EC2 với Capistrano, PostgreSQL, Nginx và Puma.

2. Tạo tài khoản AWS

  • Truy cập AWS và tạo 1 tài khoản cho riêng mình.

  • Điền thông tin cá nhân, địa chỉ email và thiết lập mật khẩu.

  • Nhập thông tin thanh toán (AWS cung cấp Free Tier trong 12 tháng).

  • Xác minh danh tính bằng số điện thoại.

  • Chọn gói Basic Support - Free.

  • Hoàn tất đăng ký và đăng nhập vào AWS Management Console.

3. Chuẩn bị server EC2

Khởi tạo EC2 Instance

  • Truy cập EC2 Dashboard từ AWS Console.

  • Nhấn Launch Instance để truy cập trang tạo Instance.

  • Tiếp theo chúng ta sẽ điền 1 số thông tin cần thiết như sau:

    • Name: Đặt tên cho instance (ví dụ: RailsApp).

    • Amazon Machine Image (AMI): Chọn Ubuntu 22.04.

    • Instance Type: Chọn t2.micro (Free Tier).

    • Key Pair: Tạo hoặc chọn key pair để đăng nhập SSH.

    • Security Group: Bạn hãy tạo security group với inbound rules là HTTP và SSH để cho phép truy cập port 22 (SSH), 80 (HTTP).

  • Nhấn Launch Instance và chờ instance khởi động.

Kết nối EC2 Instance

  • Sau khi Instance ở trạng thái Running thì bây giờ chúng ta có thể Connect được vào Instance bằng cách click button Connect

  • Tại màn hình Connect to Instance, AWS đã hướng dẫn cách chúng ta có thể connect được vào Instance

  • Đầu tiên chúng ta phải cấp quyền cho file key pem đã tạo trước đó bằng cách chạy lệnh

    chmod 400 "rails-key.pem"
    
  • Tiếp theo chúng ta sẽ chạy lệnh bên dưới để connect vào Instance

    ssh -i "rails-app.pem" ubuntu@ec2-13-208-183-82.ap-northeast-3.compute.amazonaws.com
    
  • Sau khi chạy lệnh trên, chúng ta sẽ connect được vào Instance

Tạo user để deploy

  • Tiếp theo chúng ta sẽ tạo 1 user để deploy, ở đây mình sẽ đặt tên luôn là deploy cho dễ nhớ

    ubuntu@ip-172-31-43-219:~$ sudo adduser deploy
    
  • Sau khi tạo user deploy thành công, bạn có thể access bằng cách chạy lệnh bên dưới

    ubuntu@ip-172-31-43-219:~$ sudo su - deploy
    

    Tuy nhiên có một vấn đề phát sinh là user deploy chúng ta vừa tạo chỉ có thể truy cập bằng cách dùng quyền sudo, khi chúng ta deploy thì không thể chạy sudo được, vì vậy chúng ta cần phải cấp quyền sudo cho deploy user.

  • Chúng ta sẽ quay lại user ubuntu và thực hiện như bên dưới:

    Mở file /etc/sudoers

    sudo vi /etc/sudoers
    

    Và thêm đoạn bên dưới vào file

    %deploy ALL=(ALL) ALL
    

  • Sau khi lưu file, user deploy bây giờ đã có quyền sudo

Add ssh key authentication

  • Câu chuyện đặt ra là làm thế nào để connect trực tiếp với user deploy từ máy local mà không cần dùng password hay thông qua user ubuntu. Giải pháp ở đây là chúng ta sẽ thiết lập ssh authentication

  • Đầu tiên trên máy local các bạn hãy chạy lệnh bên dưới để sinh ra ssh key

    ssh-keygen -t rsa -C rails-app
    
  • Sau đó gõ lệnh cat ~/.ssh/id_rsa.pub để lấy nội dụng public_key của ssh rồi copy

  • Tiếp theo chúng ta hãy connect vào user deploy và chạy các lệnh bên dưới

    mkdir .ssh
    sudo chmod 700 .ssh
    vi ~/.ssh/authorized_keys # paste nội dung file public_key của ssh trên local bạn vào đây
    sudo chmod 600 ~/.ssh/authorized_keys
    
  • Sau khi lưu thì giờ đây, chúng ta có thể connect tới user deploy mà không cần password nữa

  • Trên máy local các bạn hãy gõ ssh deploy@15.152.49.239, 15.152.49.239 ở đây chính là Public IPv4 của EC2 Instance của bạn

4. Cài đặt môi trường

Giờ đây server của chúng ta giống như 1 máy local bình thường, các cài đặt cơ bản như Rbenv, Ruby, Rails, PostgreSQL,... các bạn có thể tham khảo trang này để cài nhé.

5. Cấu hình Project

  • Chúng ta sẽ sử dụng gem Capistrano để hỗ trợ cho việc deploy, trong Gemfile, hãy thêm những gem bên dưới và chạy bundle install

    gem 'capistrano'
    gem 'capistrano3-puma'
    gem 'capistrano-bundler', require: false
    gem 'capistrano-rails', require: false
    gem 'capistrano-rbenv' group :development, :test do gem 'capistrano-local-precompile', '~> 1.2.0', require: false
    end
    
  • Tiếp theo cần phải cài đặt Capistrano, chúng ta hãy chạy lệnh: cap install, sau khi chạy thì nó sẽ tự động sinh cho chúng ta những file như deploy.rb, deploy/staging.rb, deploy/production.rb, Capfile

    Đầu tiên các bạn hãy mở file Capfile và sửa thành nội dung bên dưới:

    require 'capistrano/setup'
    require 'capistrano/deploy'
    require 'capistrano/scm/git'
    install_plugin Capistrano::SCM::Git require 'capistrano/rbenv'
    require 'capistrano/bundler'
    require 'capistrano/local_precompile' require 'capistrano/puma'
    install_plugin Capistrano::Puma
    install_plugin Capistrano::Puma::Systemd set :rbenv_type, :user
    set :rbenv_ruby, '3.1.2' Dir.glob('lib/capistrano/tasks/*.rake').each { |r| import r }
    

    Đây là phần cấu hình Capistrano để triển khai việc deploy Rails, các bạn hãy sửa ruby version sao cho phù hợp với project của mình. Ở đây mình chú ý tới config liên quan tới local_precompile, config này giúp biên dịch các file assets trên máy local thay vì trên server, sẽ phù hợp với những server yếu dùng free tier như này

    require 'capistrano/local_precompile'
    
  • Bây giờ chúng ta sẽ mở file deploy.rb và sửa như bên dưới:

    # frozen_string_literal: true # config valid only for current version of Capistrano
    lock '3.19.2' set :application, 'rails-app'
    set :repo_url, 'git@github.com:dangxuanphuc/rails-app.git'
    set :pty, true
    set :linked_files, %w[config/database.yml config/application.yml]
    set :linked_dirs, %w[log tmp/pids tmp/cache tmp/sockets vendor/bundle public/system public/uploads]
    set :keep_releases, 5
    set :rbenv_type, :user set :puma_rackup, -> { File.join(current_path, 'config.ru') }
    set :puma_state, -> { "#{shared_path}/tmp/pids/puma.state" }
    set :puma_pid, -> { "#{shared_path}/tmp/pids/puma.pid" }
    set :puma_bind, -> { "unix://#{shared_path}/tmp/sockets/puma.sock" }
    set :puma_conf, -> { "#{shared_path}/puma.rb" }
    set :puma_access_log, -> { "#{shared_path}/log/puma_access.log" }
    set :puma_error_log, -> { "#{shared_path}/log/puma_error.log" }
    set :puma_role, :app
    set :puma_env, fetch(:rack_env, fetch(:rails_env, 'production'))
    set :puma_threads, [0, 8]
    set :puma_workers, 0
    set :puma_worker_timeout, nil
    set :puma_init_active_record, true
    set :puma_preload_app, false set :precompile_env, 'production'
    set :assets_dir, 'public/assets'
    
  • Ở đây các bạn chỉ cần quan tâm đến 2 dòng bên dưới, hãy đổi tên application và repo theo đúng project mà các bạn muốn deploy

    set :application, 'rails-app'
    set :repo_url, 'git@github.com:dangxuanphuc/rails-app.git'
    
  • Tiếp theo là file production.rb, các bạn hãy sửa thành nội dung bên dưới, riêng phần deploy_to, IPv4user thì các bạn hãy đổi thành thông tin server của mình

    set :stage, :production
    set :rails_env, :production
    set :deploy_to, '/var/www/rails_app'
    set :branch, 'master'
    server '15.152.49.239', user: 'deploy', roles: %w[web app db], ssh_options: { keys: ['~/.ssh/id_rsa'], forward_agent: true, auth_methods: %w[publickey] }
    
  • Một vấn đề phát sinh ở đây là làm thế nào để server EC2 của chúng ta có thể lấy source code từ repo trên github về mỗi khi chúng ta deploy. Giải pháp ở đây là ssh authentication, chúng ta chỉ cần tạo ssh key cho thằng server EC2 rồi lấy public key thêm vào github là được.

    Chúng ta hãy connect tới user deploy và chạy lệnh bên dưới để generate ssh key

     ssh-keygen -t rsa -C "rails-server"
    

    Sau đó lấy public key thêm vào phần Deploy keys

    OKe như vậy là xong, giờ con server EC2 này đã có thể lấy source code mỗi khi deploy

6. Cấu hình nginx

  • Connect vào user deploy và tiến hành cài đặt Nginx

    sudo apt-get install nginx
    
  • Chạy 2 câu lệnh bên dưới để xóa đi file default config và tạo 1 file default.conf

    sudo rm /etc/nginx/sites-enabled/default
    sudo vi /etc/nginx/conf.d/default.conf
    
  • Bên dưới là nội dung file config của mình, các bạn có thể tham khảo

    upstream app { server unix:/var/www/rails_server/shared/tmp/sockets/puma.sock fail_timeout=0;
    } server { listen 80; listen [::]:80; server_name _; root /var/www/rails_server/current/public; try_files $uri $uri/ @app; location / { proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Real-IP $remote_addr; proxy_set_header Host $host; proxy_redirect off; proxy_set_header Connection ''; proxy_pass http://app; proxy_read_timeout 150; } location ~ ^/(assets|fonts|system)/|favicon.ico|robots.txt { gzip_static on; expires max; add_header Cache-Control public; } error_page 500 502 503 504 /500.html; client_max_body_size 4G; keepalive_timeout 10;
    }
    
  • Trong đoạn config trên, chúng ta sẽ chỉ cần để ý một số thông tin sau:

    server unix:/var/www/rails_server/shared/tmp/sockets/puma.sock fail_timeout=0;
    

    Ứng dụng Rails của chúng ta sử dụng máy chủ Puma, đây là đoạn config giúp Nginx kết nối và chuyển tiếp request tới Puma thông qua Unix socket thay vì cổng TCP

    listen 80;
    listen [::]:80;
    

    Server của chúng ta sẽ lắng nghe trên cổng 80 (HTTP) và cả IP6

    root /var/www/rails_server/current/public;
    

    Đây là thư mục chứa ứng dụng Rails, thư mục public là nơi chứa assets, favicon và các file tĩnh

    try_files $uri $uri/ @app;
    

    Dòng này sẽ kiểm tra nếu $uri tồn tại thì trả về file đó, $uri/ tồn tại thì trả về thư mục đó, nếu không thì sẽ chuyển tiếp request tới @app

  • Lưu file và khởi động lại nginx

    sudo service nginx restart
    

7. Cấu hình Puma

  • Tiếp theo chúng ta cần phải cấu hình puma, các bạn hãy chạy lệnh bên dưới để tạo ra file puma.service

    sudo vi /etc/systemd/system/puma.service
    
  • Sau đó hãy copy nội dung config bên dưới, chú ý là các bạn hãy đổi một số thông tin như WorkingDirectory hay ExecStart theo đúng thông tin server của các bạn nhé

    [Unit]
    Description=Puma HTTP Server for rails_server
    After=network.target [Service]
    Type=simple
    User=deploy
    WorkingDirectory=/var/www/rails_server/current
    ExecStart=/bin/bash -lc 'export PATH="$HOME/.rbenv/shims:$PATH"; RAILS_ENV=production bundle exec puma -C /var/www/rails_server/current/config/puma.rb'
    Restart=always [Install]
    WantedBy=multi-user.target
    
  • Sau khi config xong, hãy chạy 1 vài lệnh bên dưới để xác nhận lại xem puma đã chạy thành công hay chưa

    sudo systemctl daemon-reload
    sudo systemctl enable puma
    sudo systemctl start puma
    sudo systemctl status puma
    
  • Như vậy là puma đã chạy thành công

  • Trong trường hợp status của puma là failed, thì chúng ta có thể check log bằng cách chạy lệnh bên dưới

    journalctl -u puma --no-pager --lines=50
    

8. Tạo thư mục deploy

  • Tiếp theo chúng ta cần phải tạo thư mục deploy trên server, mục đích là sẽ deploy ứng dụng vào thư mục này

    cd /var/www
    mkdir rails-server
    sudo chown -R deploy:root rails-server
    cd rails-server
    mkdir shared
    mkdir shared/config
    
  • Chúng ta sẽ config database của mình ở đây, các bạn hãy chạy lệnh vi /var/www/rails-server/shared/config/database.yml và tham khảo nội dung bên dưới, ở đây mình dùng PostgreSQL, các bạn dùng MySQL thì hãy đổi về config tương ứng nhé

    production: adapter: postgresql encoding: unicode database: rails_app_production username: postgres password: Aa@123456
    
  • Tiếp theo, chúng ta cần phải config secret key base, trên local các bạn hãy tạo key bằng cách chạy RAILS_ENV=production rails secret rồi thêm vào trong file vi /var/www/rails-server/shared/config/application.yml

    SECRET_KEY_BASE: "<your_secret_key_base>"
    

9. Deploy

  • Trước khi deploy, chúng ta cần phải cài đặt puma, tuy nhiên do việc cài đặt này nó sẽ yêu cầu chạy ở quyền sudo, nên trước tiên chúng ta cần phải thêm config ko yêu cầu password khi chạy với quyền sudo. Các bạn hãy vào file /etc/sudoers và sửa lại như sau

    deploy ALL=(ALL) NOPASSWD:ALL
    

  • Sau đó hãy chạy lệnh bên dưới để cài đặt puma, sau khi cài đặt thành công thì các bạn hãy vào file /etc/sudoers và xóa phần NOPASSWD với user deploy đi nhé

    bundle exec cap production puma:install
    
  • Tiếp theo chúng ta sẽ chạy lệnh để precompile trên local trước khi deploy

    bundle exec cap production deploy --dry-run
    
  • Cuối cùng hãy chạy lệnh bên dưới để deploy

    bundle exec cap production
    
  • Sau khi deploy thành công, bạn hãy khởi động lại nginx, puma bằng câu lệnh bên dưới và truy cập vào IPv4 để xác nhận thành quả

    sudo systemctl restart puma nginx
    
  • Lưu ý có một số trường hợp làm mất file master.key thì các bạn phải thực hiện tạo lại master.key trên server bằng cách sau

    cd /var/www/rails-server/current
    rm config/credentials.yml.enc
    RAILS_ENV=production VISUAL="vim" bin/rails credentials:edit
    
  • Sau đó paste secret key base đã tạo trên local vào với cú pháp như sau:

    production: SECRET_KEY_BASE: "<your_secret_key_base>"
    

Trên đây mình đã giới thiệu về cách deploy ứng dụng Rails lên EC2 sử dụng Capistrano, Nginx, Puma. Bài viết có thể còn nhiều hạn chế, rất mong nhận được góp ý từ mọi người để mình cải thiện trong những bài sau. Cảm ơn các bạn đã theo dõi và ủng hộ!

Bình luận

Bài viết tương tự

- vừa được xem lúc

PDF Export, cẩn thận với những input có thể truyền vào

Giới thiệu. Dạo gần đây mình tình cờ gặp rất nhiều lỗi XSS, tuy nhiên trang đó lại có sử dụng dữ liệu người dùng input vào để export ra PDF.

0 0 75

- vừa được xem lúc

Giới thiệu về AWS Batch

Khi sử dụng hệ thống cloud service, điều chúng ta thường phải quan tâm đến không chỉ là hiệu suất hoạt động (performance) mà còn phải chú ý đến cả chi phí bỏ ra để duy trì hoạt động của hệ thống. Chắn hẳn là hệ thống lớn hay nhỏ nào cũng đã từng phải dùng đến những instance chuyên để chạy batch thực

0 0 148

- vừa được xem lúc

Tìm hiểu về AWS KMS

1. AWS KMS là gì. Ở KMS bạn có thể lựa chọn tạo symetric key (khóa đối xứng) hoặc asymetric key (khóa bất đối xứng) để làm CMK (Customer Master Key). Sau khi tạo key thì có thể thiết đặt key policy để control quyền access và sử dụng key.

0 0 71

- vừa được xem lúc

AWS VPC cho người mới bắt đầu

Tuần này, tôi trình bày lại những gì tôi đã học được về Virtual Private Cloud (VPC) của Amazon. Nếu bạn muốn xem những gì tôi đã học được về AWS, hãy xem Tổng quan về DynamoDB và Tổng quan về S3. VPC là gì. Những điều cần lưu ý:.

0 0 91

- vừa được xem lúc

AWS Essentials (Phần 6): Guildline SNS Basic trên AWS

Tiếp tục với chuỗi bài viết về Basic AWS Setting, chúng ta tiếp tục tìm hiểu tiếp tới SNS (Simple Notification Service). Đây là một service của AWS cho phép người dùng setting thực hiện gửi email, text message hay push notification tự động tới mobile device dựa trên event người dùng setting phía AWS

0 0 154

- vừa được xem lúc

Sử dụng Amazon CloudFront Content Delivery Network với Private S3 Bucket — Signing URLs

Trong nhiều trường hợp, thì việc sử dụng CDN là bắt buộc. Mình đã trải nghiệm với một số CDN nhưng cuối cùng mình lựa chọn sử dụng AWS CloudFront.

0 0 125