Làm thế nào để thiết lập ứng dụng Rails với Puma và Nginx

Trong hướng dẫn này, tôi sẽ hướng dẫn bạn cách thiết lập ứng dụng Rails với Puma và Nginx trên CentOS và Ubuntu.

Concept

Nhiều người sử dụng Apache HTTPd thường hỏi tôi làm thế nào Reverse Proxy và Web server làm việc?

"It's different paradigm"

Reverse Proxy (như Varnish hoặc Nginx) sẽ hoạt động như một bộ cân bằng tải định tuyến tất cả các request từ bên ngoài tới một nhóm các ứng dụng web. Sơ đồ dưới đây mô tả đơn giản cách hoạt động của nó:

                                           +---> web app process 1 --> threads
                                           |
[requests] <------>  [reverse proxy server]  --+---> web app process 2 --> threads
                                           |
                                           +---> web app process 3 --> threads

Theo cách hiểu của Apache, được mô tả như sau:

                +--- web process fork
                |
[requests] ------>  +--- web process fork
                |
                +--- web process fork

Trong đó Apache HTTPd sẽ đóng vai trò là cả hai bộ cân bằng tải định tuyến yêu cầu chỉ có 1 ứng dụng web chuyên dụng và tự động nói với chính mình để phân tách nhiều quy trình hơn để đáp ứng nhu cầu.

Tôi sẽ không tập trung vào cách nào tốt hơn cách nào. Reverse Proxy + Web server cung cấp những lợi thế khác biệt về khả năng mở rộng trên kịch bản nhiều bên thuê. Trong đó bạn có thể tăng quy mô và giảm quy mô nhiều quy trình web theo yêu cầu mà không ảnh hưởng đến các ứng dụng khác. Nhược điểm là bạn phải đối phó với giám sát quy trình đòi hỏi sự hiểu biết về các quy trình UNIX.

Installation

Puma

Puma là một máy chủ web hiệu suất cao đa luồng được viết bằng Ruby. Nó có thể được sử dụng để lưu trữ bất kỳ ứng dụng web Ruby nào hỗ trợ Rack như Sinatra hoặc Ruby on Rails. Bạn có thể cài đặt puma qua RubyGems bằng thêm nó tới tệp Gemfile của bạn.

gem 'puma', '~> 3.4'

sau đó chạy bundle install.


Bây giờ bạn có thể bắt đầu ứng dụng của bạn với rails s. Bạn sẽ thấy:

Puma starting in single mode...
* Version 2.3.2, codename: Delicious Thin Mints
* Min threads: 0, max threads: 16
* Environment: development
...

Nginx

Nginx được sử dụng để làm Reverse Proxy để HttpProxyModule có thể thực hiện yêu cầu chuyển proxy đến nhiều máy chủ ảo.
Đầu tiên, chúng ta cần cài đặt trên máy chủ:

CentOS 5+

Tạo file etc/yum.repos.d/nginx.repo và điền nội dung sau:

[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=0
enabled=1

Bây giờ chúng ta có thể cài đặt Nginx với lệnh:

sudo yum install nginx

và máy chủ có thể được bắt đầu với:

sudo /etc/init.d/nginx start

Ubuntu

Phiên bản Nginx trong repo Ubuntu khá cũ (ví dụ: 1.2.6), bạn có thể cài đặt phiên bản mới hơn bằng cách thêm repo chính thức nginx.org:

sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys ABF5BD827BD9BF62

sau đó thêm dòng sau vào cuối file /etc/apt/sources.list:

deb http://nginx.org/packages/ubuntu/ precise nginx

Lưu ý: Nếu bạn đã cài đặt Nginx trước đó, hãy đảm bảo bạn xóa nó trước:

sudo apt-get purge nginx*

sau đó bạn có thể cài đặt gói với:

sudo apt-get update
sudo apt-get install nginx

Sau khi cài đặt thành công, bạn có thể xác minh bằng:

nginx -v
# nginx version: nginx/1.10.3 (Ubuntu)

bạn có thể khởi động daemon bằng cách sử dụng Upstart:

sudo service nginx start

Configuration

Trước khi tiếp tục, có một vài yêu cầu cho hệ thống của bạn:

  • Ruby 1.9.3 hoặc mới hơn
  • Rails 3.x hoặc mới hơn
  • Ứng dụng của bạn đang chạy dưới RAILS_ENV=production
  • Ứng dụng Rails của bạn nên được đặt trong thư mục /var/www
  • Bạn đã thiết lập chính xác tất cả các quyền và cài đặt tường lửa cho môi trường của bạn

Nginx configuration

CentOS

Việc đầu tiên tôi thường làm là xóa tất cả các tệp máy chủ ảo mặc định:

sudo rm /etc/nginx/conf.d/default.conf

Tiếp theo, hãy tạo một tệp cấu hình máy chủ mới /etc/nginx/conf.d/my_app.conf và điền vào nội dung sau:

upstream my_app {
  server unix:///var/run/my_app.sock;
}

server {
  listen 80;
  server_name my_app_url.com; # change to match your URL
  root /var/www/my_app/public; # I assume your app is located at this location

  location / {
    proxy_pass http://my_app; # match the name of upstream directive which is defined above
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }

  location ~* ^/assets/ {
    # Per RFC2616 - 1 year maximum expiry
    expires 1y;
    add_header Cache-Control public;

    # Some browsers still send conditional-GET requests if there's a
    # Last-Modified header or an ETag header even if they haven't
    # reached the expiry date sent in the Expires header.
    add_header Last-Modified "";
    add_header ETag "";
    break;
  }
}

sau đó bạn có thể khởi động lại máy chủ Nginx của mình:

sudo /etc/init.id/nginx restart

Ubuntu

Điều đầu tiên tôi thường làm là vô hiệu hóa trang mặc định bằng cách xóa symlink:

sudo rm /etc/nginx/conf.d/sites-enabled/default

Tiếp theo, hãy tạo một tệp cấu hình máy chủ mới /etc/nginx/sites-available/my_app.conf và điền vào nội dung sau:

upstream my_app {
  server unix:///var/run/my_app.sock;
}

server {
  listen 80;
  server_name my_app_url.com; # change to match your URL
  root /var/www/my_app/public; # I assume your app is located at that location

  location / {
    proxy_pass http://my_app; # match the name of upstream directive which is defined above
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }

  location ~* ^/assets/ {
    # Per RFC2616 - 1 year maximum expiry
    expires 1y;
    add_header Cache-Control public;

    # Some browsers still send conditional-GET requests if there's a
    # Last-Modified header or an ETag header even if they haven't
    # reached the expiry date sent in the Expires header.
    add_header Last-Modified "";
    add_header ETag "";
    break;
  }
}

và chúng ta cần kích hoạt nó bằng cách tạo symlink trong /etc/nginx/sites-enabled

sudo ln -sf /etc/nginx/sites-available/my_app.conf /etc/nginx/sites-enabled/my_app.conf

sau đó bạn có thể khởi động lại máy chủ Nginx của mình:

sudo service nginx restart

Start your app server

Bây giờ chúng ta cần nói với puma để khởi động ứng dụng của mình và liên kết nó với Unix socket:

cd /var/www/my_app
bundle exec puma -e production -b unix:///var/run/my_app.sock

Nếu không có gì sai, bạn sẽ thấy điều này:

Puma starting in single mode...
* Version 2.3.2, codename: Delicious Thin Mints
* Min threads: 0, max threads: 16
* Environment: development
* Listening on unix:///var/run/my_app.sock
Use Ctrl-C to stop


Bạn có thể chạy máy chủ Puma dưới dạng daemon bằng cách thêm tham số -d như sau:

bundle exec puma -e production -d -b unix:///var/run/my_app.sock

Kiểm tra xem Puma có đang chạy hay không bằng lệnh:

ps aux | grep puma
# 9594 92.8  1.4 496844 117280 ?       Rl   17:25   0:25 ruby /usr/lib/ruby/1.9.1/bin/puma -e production -d -b unix:///var/run/my_app.sock

Restart/Stop your daemon Puma server

Để khởi động lại máy chủ, sử dụng lệnh kill để gửi tính hiệu SIGUSR2 với PID, trong trường hợp này PID là 9594:

kill -s SIGUSR2 9594

Nếu bạn muốn dừng máy chủ, chỉ cần gửi tín hiệu SIGTERM:

kill -s SIGTERM 9594

bạn có thể xác minh lại xem process đã được kill hay chưa bằng ps.


Nếu bạn muốn Unix tìm nạp cho bạn PID, khi khởi động máy chủ Puma bạn thêm tham số --pidfile:

bundle exec puma -e production -d -b unix:///var/run/my_app.sock --pidfile /var/run/puma.pid

PID sẽ được lưu in /var/run/puma.pid và bạn có thể dễ dàng lấy PID bằng lệnh cat:
Để khởi động lại:

kill -s SIGUSR2 `cat /var/run/puma.pid`

Để dừng:

kill -s SIGTERM `cat /var/run/puma.pid`

Capistrano deployment

Bây giờ bạn đã biết cách mà máy chủ Puma làm việc, bạn có thể điều chỉnh những gì bạn đã học cho việc triển khai của mình. Nếu bạn sử dụng capistrano, bạn có thể sử dụng các tác vụ puma/capistrano bằng cách thêm vào config/deploy.rb:

require 'puma/capistrano`

và sau đó:

bundle exec cap puma:start
bundle exec cap puma:restart
bundle exec cap puma:stop


Bài viết được dịch từ http://ruby-journal.com, How to Setup Rails App With Puma and NGINX của tác giả Trung Lê.