Ruby on Rails 終極部署方案 nginx+mina+puma

gameFu發表於2015-06-19

搭建工具介紹

Ruby on Rails作為一款十分優秀的web開發框架,在當前web領域中慢慢佔據了越來越重要,秉承rails快速開發的特點,很多快速部署rails的方案也越來越多。這篇文章中所選的方案是我個人認為十分優秀的部署方案。這套部署方案的結構是,nginx作為反向代理伺服器負責負載均衡,mina作為自動化部署工具,puma作為rails的web伺服器

nginx

nginx是一款優秀的代理伺服器,其高效的效能已經得到了業界的廣泛認可,相信作為web開發人員不會沒聽說過他的大名

mina

mina是一款由ruby開發的自動化部署工具,其目的是為了簡化每次rails程式碼提交時的部署,一鍵完成部署,杜絕了提交到git伺服器後,又去伺服器上git pull的情況

puma

puma是一款專門針對rails的併發伺服器,相對於passengerpuma可配置面更廣,而且效能比passenger更高,是rails web伺服器的不二之選

部署前言

由於這篇文章需要很多鋪墊,包括rails的安裝下載,git的配置等等,需要讀者自己去查閱資料或者查閱之前我寫過的一些文章,如果期間有什麼問題,請留言。。

mina

首先在你的rails專案的Gemfile中加上

rubygem mina

執行bundle 安裝 mina,接著在你的rails專案根目錄初始化mina

mina init

這是在你專案的config目錄下會有一個deploy.rb,配置deploy.rb,列出重點部分,每一行的解釋會附在程式碼的註釋裡

ruby
#伺服器地址,是使用ssh的方式登入伺服器 set :domain, `root@192.168.0.103` #伺服器中專案部署位置 set :deploy_to, `/var/www/ruby_sample` #git程式碼倉庫 set :repository, `https://github.com/gameFu/ruby_sample.git` #git分支 set :branch, `master` # 中括號裡的檔案 會出現在伺服器專案附錄的shared資料夾中,這裡加入了secrets.yml,環境金鑰無需跟開發計算機一樣 set :shared_paths, [`config/database.yml`, `log`, `config/secrets.yml`] # 這個塊裡面的程式碼表示執行 mina setup時執行的命令 task :setup => :environment do # 在伺服器專案目錄的shared中建立log資料夾 queue! %[mkdir -p "#{deploy_to}/#{shared_path}/log"] queue! %[chmod g+rx,u+rwx "#{deploy_to}/#{shared_path}/log"] # 在伺服器專案目錄的shared中建立config資料夾 下同 queue! %[mkdir -p "#{deploy_to}/#{shared_path}/config"] queue! %[chmod g+rx,u+rwx "#{deploy_to}/#{shared_path}/config"] queue! %[touch "#{deploy_to}/#{shared_path}/config/database.yml"] queue! %[touch "#{deploy_to}/#{shared_path}/config/secrets.yml"] # puma.rb 配置puma必須得資料夾及檔案 queue! %[mkdir -p "#{deploy_to}/shared/tmp/pids"] queue! %[chmod g+rx,u+rwx "#{deploy_to}/shared/tmp/pids"] queue! %[mkdir -p "#{deploy_to}/shared/tmp/sockets"] queue! %[chmod g+rx,u+rwx "#{deploy_to}/shared/tmp/sockets"] queue! %[touch "#{deploy_to}/shared/config/puma.rb"] queue %[echo "-----> Be sure to edit `shared/config/puma.rb`."] # tmp/sockets/puma.state queue! %[touch "#{deploy_to}/shared/tmp/sockets/puma.state"] queue %[echo "-----> Be sure to edit `shared/tmp/sockets/puma.state`."] # log/puma.stdout.log queue! %[touch "#{deploy_to}/shared/log/puma.stdout.log"] queue %[echo "-----> Be sure to edit `shared/log/puma.stdout.log`."] # log/puma.stdout.log queue! %[touch "#{deploy_to}/shared/log/puma.stderr.log"] queue %[echo "-----> Be sure to edit `shared/log/puma.stderr.log`."] queue %[echo "-----> Be sure to edit `#{deploy_to}/#{shared_path}/config/database.yml`."] end #這個程式碼塊表示執行 mina deploy時執行的命令 desc "Deploys the current version to the server." task :deploy => :environment do to :before_hook do end deploy do #重新拉git伺服器上的最新版本,即使沒有改變 invoke :`git:clone` #重新設定shared_path位置 invoke :`deploy:link_shared_paths` invoke :`bundle:install` invoke :`rails:db_migrate` invoke :`rails:assets_precompile` invoke :`deploy:cleanup` to :launch do queue "mkdir -p #{deploy_to}/#{current_path}/tmp/" # queue "chown -R www-data #{deploy_to}" queue "touch #{deploy_to}/#{current_path}/tmp/restart.txt" end end end

這樣一來mina的基本配置就完成,接下來只要將你開發環境的專案上傳到git伺服器,然後執行下面的命令就完成了

mina deploy

完成部署後,你就可以在指定的伺服器目錄下看到你的專案,目錄結構如下

  • current -當前版本目錄也就是專案目錄
  • last_version -版本號
  • releases/ -過去的版本
  • scm/
  • shared/ 先前shared_path所設定另外拉出來的檔案都在這裡
  • tmp/

這裡需要注意的幾點
1.shared_path裡面的檔案不僅僅是表示這些檔案會在伺服器目錄中出現在另外的目錄裡,也表示這些檔案或者目錄不會受到git版本庫的控制,也就是說這些檔案的配置必須在你伺服器中手動去配置,這兩個檔案包括database.yml和secrets.yml,在shared/config目錄下
2.針對deploy最好在伺服器建立一個使用者,並針對他建立一個ssh authorized_keys,這裡直接使用了root身份,參考centos7 伺服器部署ssh證照授權登入,這樣做能避免每次部署的時候都需要輸入伺服器賬號密碼

可能會遇到的問題

由於生產環境一般會搭配類似於postgresql等成熟資料庫,這裡我就舉出一個搭建postgresql,首先是啟動資料庫時(centos 7下),如果遇到問題請使用下面的命令就能看到詳細的錯誤資訊

systemctl status postgresql-9.4.service -l 

然後在跑mina deploy時可能會報類似於這樣的一個錯誤

 Gem::LoadError: Specified `postgresql` for database adapter, but the gem is not loaded. Add `gem `pg`` to your Gemfile (and ensure its version is at the minimum required by ActiveRecord).

從錯誤資訊上能很明顯的看出是因為沒有安裝pg這個包導致的,但是有一種情況是明明在專案的Gemfile上寫上了pg但還是跑不過,造成這個的原因,可能是由於你的伺服器環境缺少了pg的標頭檔案導致的,如果是在centos下,只需要執行下面命令就能解決

yum install postgresql-libs
yum install postgresql-devel

Puma

首先在你的Gemfile里加上

ruby
gem puma

然後在config目錄下手動建立一個puma.rb檔案,配置puma.rb檔案

ruby
#!/usr/bin/env puma #rails的執行環境 environment `production` threads 2, 64 workers 4 #專案名 app_name = "ruby_sample" #專案路徑 application_path = "/var/www/#{app_name}" #這裡一定要配置為專案路徑下地current directory "#{application_path}/current" #下面都是 puma的配置項 pidfile "#{application_path}/shared/tmp/pids/puma.pid" state_path "#{application_path}/shared/tmp/sockets/puma.state" stdout_redirect "#{application_path}/shared/log/puma.stdout.log", "#{application_path}/shared/log/puma.stderr.log" bind "unix://#{application_path}/shared/tmp/sockets/#{app_name}.sock" activate_control_app "unix://#{application_path}/shared/tmp/sockets/pumactl.sock" #後臺執行 daemonize true on_restart do puts `On restart...` end preload_app!

這裡需要注意的地方

  • threadspuma的執行緒數,第一個引數是最小的執行緒數,第二個引數是最大執行緒數
  • bind – 這個指定的是puma執行時產生的socket,後面nginx會用到
  • 這裡所有對應的目錄是在deploy配置中配置的,如果需要更改配置目錄,deploy.rb也需要相應的更改

Nginx

下載安裝nginx後,開啟nginx的配置檔案nginx.conf進行配置

nginx  worker_processes  1;

      error_log  /var/log/nginx/error.log warn;
      pid        /var/run/nginx.pid;

      events {
          worker_connections  1024;
      }

      http {
          include       /etc/nginx/mime.types;
          default_type  application/octet-stream;

          log_format  main  `$remote_addr - $remote_user [$time_local] "$request" `
                            `$status $body_bytes_sent "$http_referer" `
                            `"$http_user_agent" "$http_x_forwarded_for"`;

          access_log  /var/log/nginx/access.log  main;

          sendfile        on;
          #tcp_nopush     on;

          keepalive_timeout  65;

          #gzip  on;

          #include /etc/nginx/conf.d/*.conf;
          upstream deploy {
                  server unix:///var/www/ruby_sample/shared/tmp/sockets/ruby_sample.sock;
          }

          server {
              listen 80;
              server_name your.server.domain.ip; # change to match your URL
              root /var/www/ruby_sample/current/public; # I assume your app is located at this location

              location / {
                  proxy_pass http://deploy; # 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;
              }
       }
      }

這裡只需要注意的是

  • upstream中 server 要配置成你在puma中bind的 socket就行了
  • root要設定成你伺服器專案的根目錄,也就是puma.rb中的 directory

接下里只需要重啟nginx伺服器,整個rails的環境就搭建完成了


nginx -s reload

如果完成了配置後訪問站點是504,那麼可能是兩種情況,一是伺服器防火牆問題,二是rails環境金鑰的問題,請在使用passenger在Centos7部署nginx+Ruby on Rails中尋找答案

相關文章