使用 RVM Ruby 搭配 Passenger 3
此頁面包含使用 RVM 搭配 Phusion Passenger 3 的說明。您真的應該升級到 Phusion Passenger 4 或更新版本,因為它提供了更好的 RVM 支援。請參閱 此頁面,取得 Phusion Passenger 4 說明。
Passenger 3
Passenger 基本上是 Nginx 和 Apache 的「mod_ruby」。您可以選擇 *僅一個* Ruby 來執行所有 Passenger 3 應用程式。如果您需要執行多個 Ruby 解譯器,則應該選擇最常見的一個。然後,您可以使用代理傳遞至外部應用程式伺服器,例如 Passenger Standalone、Unicorn、Thin、Mongrel、Mongrel2 等,以在不同的 Ruby 下執行不同的應用程式。如需完整說明(附上精美圖片!),請參閱 Phusion 部落格上的文章
安裝搭載 Passenger 的 Nginx/Apache
首先,有 passenger-install-apache2-module 和 passenger-install-nginx-module。在安裝結束時,它會輸出一個 PassengerRuby 組態片段供 Web 伺服器使用。其值設定為與用於執行安裝程式的 RVM Ruby 和 RVM gemset 相應的 RVM Ruby 包裝指令碼。這應該是您設定 Passenger 3 所需的一切!
如果您仍然遇到問題,而不是建立 .rvmrc 檔案,請使用其中一種新格式,例如 .ruby-version 或 .versions.conf
echo 1.9.3@my-app-name > .ruby-version
然後在 Rails 專案中,新增一個檔案 config/setup_load_paths.rb,並新增從 RVM 1.12.0 (或 head) 開始,RVM 以預設 gemset 中的 gem 安裝,不需要 unshift $LOAD_PATH,但需要設定 GEM_PATH。 config/setup_load_paths.rb。
if ENV['MY_RUBY_HOME'] && ENV['MY_RUBY_HOME'].include?('rvm') begin gems_path = ENV['MY_RUBY_HOME'].split(/@/)[0].sub(/rubies/,'gems') ENV['GEM_PATH'] = "#{gems_path}:#{gems_path}@global" require 'rvm' RVM.use_from_path! File.dirname(File.dirname(__FILE__)) rescue LoadError raise "RVM gem is currently unavailable." end end # If you're not using Bundler at all, remove lines bellow ENV['BUNDLE_GEMFILE'] = File.expand_path('../Gemfile', File.dirname(__FILE__)) require 'bundler/setup'
請注意,對於 Passenger 3,您現在直接使用 ruby wrapper 腳本,而不需要使用 passenger_ruby wrapper。
啟動 Passenger Standalone
然後是 Passenger Standalone,即「passenger start」。Passenger Standalone 內部使用 Nginx,並將 passenger_ruby 指令寫入 Nginx 設定檔。此指令指向 RVM Ruby wrapper 腳本,該腳本與用於執行「passenger start」指令的 RVM Ruby 和 RVM gemset 相符。
Bundler Gotcha
在專案中使用 Bundler 時,Passenger 會嘗試聰明地只將 Gemfile 中列出的 gem 新增到您的 $LOAD_PATH。這可能會導致未列出 gem 的「無法載入」錯誤(這只會在開發期間發生)。您可以透過新增
f = File.open('/tmp/load_path', 'w') f.write($:) f.close
到應用程式的 main 檔案(在「require」呼叫之前)來檢查執行時間載入路徑。您將無法載入不在該載入路徑中的任何 gem。
疑難排解
- 最常見的問題是忘記路徑的 /bin/ 部分以取得適當的 wrapper 腳本
-
下一個最常見的問題是聆聽 passenger 安裝腳本的輸出,以了解 passenger_ruby/PassengerRuby 的位置。請務必使用上述指定的 wrapper 腳本位置。為了更清楚,請參閱以下 nginx 範例
passenger_ruby /home/wayne/.rvm/bin/passenger_ruby; * NOTICE THE '.rvm/bin' DIR ^ ^ ^ * do NOT use the actual ruby binary in .rvm/rubies/{passenger_ruby}/bin/ruby * do not listen to passenger's output for passenger_ruby as passenger is not aware of rvm.
對於系統範圍(root)安裝,bin 目錄是 /usr/local/rvm/binpassenger_ruby /usr/local/rvm/bin/passenger_ruby;
常見問題
-
問:我可以讓多個專案在 passenger 下執行,每個專案使用不同的 ruby 版本嗎?
答:Passenger 3 只支援在 *一個* Ruby 下執行,但您可以使用 proxy pass 取得每個網站/專案行為。
-
問:如何在 passenger 下使用自訂 gemset?
答:沒有 bundler,您可以在 config.ru 中自行設定環境變數,例如
ENV["GEM_HOME"]=%x{"source ~/.bash_profile ; rvm ree@pancake ; rvm gemdir"}.strip
A:使用 bundler:在任何 gemset 外部安裝 bundler,切換回您要使用的 gemset 並執行 bundle install,然後重新啟動應用程式(透過觸碰 tmp/restart.txt)。這會運作,因為 bundler 會將絕對路徑儲存在 .bundle/environment.rb 中,而 bundler 會直接載入該檔案。如果這無法如預期運作,請嘗試執行 bundle install,如下所示
bundle install $BUNDLE_PATH
如何在與使用者安裝結合使用 passenger-status 等指令,但以 root 身分執行它們?這方面的關鍵主要是在 sudoers 檔案中使用萬用字元,如下列範例所示。
/usr/bin/env GEM_PATH=* GEM_HOME=* PATH=* passenger-status
這是 RVM 版本 1.12.0 以下的 config/setup_load_paths.rb。
if ENV['MY_RUBY_HOME'] && ENV['MY_RUBY_HOME'].include?('rvm') begin rvm_path = File.dirname(File.dirname(ENV['MY_RUBY_HOME'])) rvm_lib_path = File.join(rvm_path, 'lib') # $LOAD_PATH.unshift rvm_lib_path require 'rvm' RVM.use_from_path! File.dirname(File.dirname(__FILE__)) rescue LoadError # RVM is unavailable at this point. raise "RVM ruby lib is currently unavailable." end end # Pick the lines for your version of Bundler # If you're not using Bundler at all, remove all of them # Require Bundler 1.0 ENV['BUNDLE_GEMFILE'] = File.expand_path('../Gemfile', File.dirname(__FILE__)) require 'bundler/setup' # Require Bundler 0/9 # if File.exist?(".bundle/environment.rb") # require '.bundle/environment' # else # require 'rubygems' # require 'bundler' # Bundler.setup # end