【Passenger的安裝與卸載管理】
===========================================================
推薦方式是使用Pushion Passenger和Nginx的綁定install方式,這種方式可以分為:交互式和非交互式
交互式的方式下會顯示并提示安裝過程中輸入各種參數。非交互式的方式可以運行:
sudo passenger-install-nginx-module --help
查看各種靜默安裝的參數。其中有幾個是比較關鍵的:
--auto 自動確認"按下Enter鍵繼續"
--prefix=DIR 設置Nginx安裝目錄(默認是/opt/nginx)
--auto-download 自動下載和安裝Nginx
另外一種是通過手工配置和便宜Nginx。在下載Nginx的源代碼后進行編譯時,添加如下的參數
./configure -add-module=/path-to-passenger-root/ext/nginx
這里path-to-passenger-root是Passenger的根目錄。有兩種方式可以獲得這路徑:如果是通過gem方
式安裝的。可以簡單運行如下命令獲得Passenger的根目錄:passenger-config --root 如果是通過源碼
安裝的,那么指定源代碼解壓后的根目錄就可以了。
在編譯完成后,修改Nginix的配置文件(/opt/nginx/conf/nginx.conf),在HTTP模塊內添加如下一行后
重啟Nginix即可
passenger_root /path-to-passenger-root;
如果是升級或者降級Nginx或者Passenger,也是同樣的步驟。
如果要臨時去除Passenger的支持又不想完全卸載Passenger的話,只要把Nginx中所有關于Passenger
的配置參數全部注釋掉(通常都是以passenger-xxx打頭的),并重啟Nginx就可以了。
要徹底刪除Passenger,首先把Nginx配置文件中所有關于Passenger的配置選項全部刪除。接下來如果
是通過gem方式安裝的,執行:gem uninstall passenger 或者直接刪除Passenger的安裝目錄。然后重
新編譯和安裝Nginx即可。
===========================================================
【為Passenger指定Ruby的運行目錄】
===========================================================
如果系統安裝了多個Ruby解析器,需要指定一個Ruby運行目錄。如果是通過RVM來安裝Ruby解析器的,
那么RVM會將默認使用的Ruby解析器添加到PATH環境變量下。可以運行echo $PATH檢測,如果沒有的
話則手工添加到$PATH的最前面。
administrator@RoR-PRD:~$ rvm list
rvm rubies
ruby-1.9.2-p290 [ i686 ]
=> ree-1.8.7-2011.03 [ i686 ]
administrator@RoR-PRD:~$ echo $PATH
/home/administrator/.rvm/gems/ree-1.8.7-2011.03@release/bin: \
/home/administrator/.rvm/gems/ree-1.8.7-2011.03@global/bin: \
/home/administrator/.rvm/rubies/ree-1.8.7-2011.03/bin: \
/home/administrator/.rvm/bin: \
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
===========================================================
【重新發布一個Rails應用】
===========================================================
重新發布一個Rails應用,只需要再次上傳文件后,通知Passenger重啟應用就可以。這里有兩種方式:
第一種是重啟Nginx。另外一種是每次在發布之前,通過如下命令新建或者更新一個名為restart.txt的文
件,讓Nginx檢測到文件更新(timestamp改變)而自動在下次請求到來時重啟應用。
touch /webapps/mycook/tmp/restart.txt
必須注意的是:Passenger并不會自動為部署的應用創建好DB的環境,依然需要在發布新的應用之后,
手工執行:rake db:migrate RAILS_ENV=production
===========================================================
【Nginx中配置項的覆蓋問題】
===========================================================
server {
listen 80;
server_name localhost;
root /home/administrator/deploy/demo/public/; # <--- be sure to point to 'public'!
passenger_enabled on;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root html;
index index.html index.htm;
}
}
上面的配置選項中,一開始將root指定為對應的Rails應用的public目錄,但是在下面的location / {...}中
又將root指定為當前目錄下的index.html或者index.htm,所以會覆蓋前面的root配置,當在瀏覽器下
輸入:http://localhost/時,顯示的不是應用的根目錄,而是Nginx的歡迎頁面。
不過不建議這樣配置,因為這樣會令到當站點無法訪問時,無法判斷是Nginx的問題還是應用的問題。如
果要在本機再配置,可以這些寫:
server {
listen 80;
server_name 127.0.0.1;
root /home/administrator/deploy/demo/public/; # <--- be sure to point to 'public'!
passenger_enabled on;
}
但是URL就要變成這樣:http://127.0.0.1:80/,如果使用localhost,則Nginx會默認使用server_name
+ port 來分派請求,所以當輸入:http://localhost:80/時依然會被Nginx默認的服務器攔截,返回Nginx
的默認頁面
===========================================================
【部署為一個URI】
===========================================================
假設現在已經有了一個server配置:
server {
listen 80;
server_name www.phusion.nl;
root /websites/phusion;
}
我想將新的應用部署在這個sever下面,并且請求的URL是這樣的:http://www.phusion.nl/rails。
首先在現有的root下面創建一個soft link,指向改Rails應用:
sudo ln -s /home/administrator/deploy/demo/public /opt/nginx/html/demo
然后在原有的sever下添加如下配置:
server {
listen 80;
server_name localhost;
passenger_enabled on; # 新添加的
passenger_base_uri /demo; # 新添加的
}
然后重啟Nginx: sudo /etc/init.d/nginx restart。重新訪問:http://localhost/demo
通過這一點,我可以實現將多個Rails應用部署在同一臺機器下面的問題:只要指定不同的passenger_base_uri
===========================================================
【Passenger的配置選項】
===========================================================
>> passenger_root <directory>
指定Passenger的安裝根目錄
>> passenger_ruby <filename>
指定Passenger使用的Ruby解析器的目錄(按照安裝過程中推薦的值即可)
>> passenger_enabled on|off
可以定義在http/server/location/if ,默認off
>> passenger_base_uri <uri>
可以定義在http/server/location/if 中多次定義,為同一VPS配置多個應用
>> passenger_use_global_queue <on|off>
默認情況下Passenger使用一個全局隊列(Global queue)來存放請求。當有請求到來時會首先看后端的處
理進程是否有空閑的,有的話將該請求轉發給請求進程。沒有的話則存儲在自己的隊列里面。當該功能被
關閉時,會在各個后臺進程的內部自己維護一個獨立的隊列,而不是全局共享的。這樣會出現一個情況:
假如某個后臺進程因為掛起的request數量比較少,那么Passenger會把新的請求都分配到該進程。如果新
的請求都是屬于比較耗時的請求,那么會造成該進程壓力非常大,響應速度變慢。但其它已經處理完請求
的空閑進程卻無法派上用場。
默認情況下這個參數的值是on
>> passenger_buffer_response <on|off>
當這個參數被配置為on時,Passenger會對頁面的輸出進行緩存。也就是將response緩存到Passenger
中,然后逐步發送到客戶端。這樣做的目的是為了避免在response的內容比較大時,整個應用的實例被
鎖住,直到所有的內容都被完全發送到客戶端為止。
默認情況下這個參數的值是on
>> passenger_friendly_error_pages on|off
可以讓passenger在錯誤發生時以一種友好的形式來顯示錯誤信息(包括堆棧調用,啟動信息,建議等)。
強烈建議在生產環境下關閉該參數
默認情況下這個參數的值是on
>> passenger_max_pool_size <integer>
這個參數用于配置Passenger同一時刻可以并行的RoR/Rack應用實例的數量(注意是所有Rails應用)。推薦
的參數值至少等于CPU(內核的數目)。如果有2G的RAM,那么可以配置為30個。如果是只有256M內存
的VPS則建議配置為2
這個參數只能在http block中定義,默認值是6
>> passenger_min_instances <integer>
這個參數用于指定Passenger應該保留的Rails應用的數目。它會在應用第一次被訪問時,讓Passenger啟
動等于這個數目的實例并一直保持在內存中。即便是一直處于空閑狀態或者到了清除時間。
注意這個參數并不會pre-start應用!也即是說只有在應用第一次被訪問時,才會創建對應數目的實例,而
不會在Nginx啟動時就預先加載。所以第一次訪問時有可能會比較慢。如果需要需要預加載,需要配合另外
一個參數passenger_pre_start
這個參數的默認值是1
>> passenger_max_instances_per_app <integer>
這個參數和上面max_pool_size的區別是,max_pool_size是限定Passenger可以同時啟動的所有Rails/
Rack應用的數目(可以是多個app instance的總和),而這個參數是用于單獨指定某個app instance的數量
的。這個參數可以限制某個app instance占用了所有的pool和CPU時間片。
這個參數的值必須小于passenger_max_pool_size,0代表單個應用的實例數量沒有限制(最大值等于
max_pool_size)。
這個參數只能在http block中定義,默認值是0
>> passenger_pool_idle_time <integer>
這個參數指定了每個app instance最長的空閑時間。當一個應用在指定的時間內都沒有接收到請求而處于
空閑狀態的時候,它將會被銷毀而回收所占用的內存。
推薦的配置時間是應用頁面平均訪問時間 * 2。如果設置的值過小意味著應用會經常被實例化和銷毀,這
個過程比較耗時。如果是在非共享的主機環境下,或者需要7*24小時的響應,應該設置為0
當時設置為0不意味著永遠不會被銷毀。當另外一個app instance需要啟動一個worker process但Pass-
enger已經沒有工作線程了時,會強制將一個空閑狀態的app instance回收以空出worker process
這個參數只能在http block中定義,默認值是300秒
>> passenger_pre_start <url>
這個參數可以讓Passenger在Nginx啟動時,預先加載指定的應用。但要注意的是即便是預先加載的應用
在passenger_pool_idel_time 到達時,也會被銷毀。如果需要繼續保留在內存中,就要搭配前面提到的
passenger_min_instances。
URL支持完整的server_name,也可以是sub-URI
這個參數只能在http block中定義,可以被定義無限次。
>> passenger_log_level <integer>
這個參數可以指定Passenger如何往Nginx的日志文件中寫日志。參數值越大寫入的內容越詳細。總共
分為4級:0 僅顯示錯誤和異常;1 顯示有用的調試信息(供管理員定位錯誤用);2 顯示更加詳細的信息
(供開發過程使用);3 顯示所有日志信息。
這個參數只能在http block中定義,默認的級別是0
>> passenger_debug_log_file <filename>
這個參數可以指定Passenger將錯誤和調試信息寫到何處。
這個參數只能在http block中定義,默認情況下日志會寫到Nginx的全局日志文件
>> rails_env <string>
這個參數允許針對不同的應用,設置不同的環境。可以在http/server/block/if block中定義,每處一次
這個參數的默認值是production
===========================================================
【分析工具】
===========================================================
>> passenger-memory-stats
這個命令需要在root用戶下執行。可以使用 rvmsudo passenger-memory-stats 來查看所有的內存情況
>> passenger-status
這個命令同樣需要在root用戶下執行。可以使用 rvmsudo passenger-status 來查看Passenger的情況
----------- General information -----------
max = 6 # 等同于passenger_pool_max_size
count = 0 # 當前存活的用例,小于等于max值
active = 0 # 當前活躍的用例,小于等于count值
inactive = 0 # 當前空閑的用例,等于count-active
Waiting on global queue: 0
----------- Domains -----------
/var/www/projects/app1-foobar:
PID: 9617 Sessions: 0 Processed: 7 Uptime: 2m 23s
Sessions: 0 # 當前應用有多少客戶端連接等待處理
Processed:7 # 截至當前為止總共處理了多少個請求
----------- Application groups -----------
如果應用是基于Ruby on Rails的,當進程被kill掉時,日志會寫在應用自身的日志文件中,而不是Nginx
的日志文件。所以先檢查production.log,如果沒有異常信息再檢查Nginx的error.log文件
===========================================================
【其它】
===========================================================
假設在Rails應用下有Gemfile,那么Passenger會自動執行Bundle.setup()方法
當應用部署為Sub-uri的形式時,由于根路徑發生了變化,所以靜態資源(圖片,CSS,JS)的相對路徑都會
發生變化。這個時候如果使用靜態路徑那么所有靜態資源都將找不到文件,所以無論在何種部署情況下,
都推薦使用Rails提供的幫助方法:image_tag、stylesheet_link_tag、javascript_include_tag 來創建
相對的資源路徑。
===========================================================
===========================================================
推薦方式是使用Pushion Passenger和Nginx的綁定install方式,這種方式可以分為:交互式和非交互式
交互式的方式下會顯示并提示安裝過程中輸入各種參數。非交互式的方式可以運行:
sudo passenger-install-nginx-module --help
查看各種靜默安裝的參數。其中有幾個是比較關鍵的:
--auto 自動確認"按下Enter鍵繼續"
--prefix=DIR 設置Nginx安裝目錄(默認是/opt/nginx)
--auto-download 自動下載和安裝Nginx
另外一種是通過手工配置和便宜Nginx。在下載Nginx的源代碼后進行編譯時,添加如下的參數
./configure -add-module=/path-to-passenger-root/ext/nginx
這里path-to-passenger-root是Passenger的根目錄。有兩種方式可以獲得這路徑:如果是通過gem方
式安裝的。可以簡單運行如下命令獲得Passenger的根目錄:passenger-config --root 如果是通過源碼
安裝的,那么指定源代碼解壓后的根目錄就可以了。
在編譯完成后,修改Nginix的配置文件(/opt/nginx/conf/nginx.conf),在HTTP模塊內添加如下一行后
重啟Nginix即可
passenger_root /path-to-passenger-root;
如果是升級或者降級Nginx或者Passenger,也是同樣的步驟。
如果要臨時去除Passenger的支持又不想完全卸載Passenger的話,只要把Nginx中所有關于Passenger
的配置參數全部注釋掉(通常都是以passenger-xxx打頭的),并重啟Nginx就可以了。
要徹底刪除Passenger,首先把Nginx配置文件中所有關于Passenger的配置選項全部刪除。接下來如果
是通過gem方式安裝的,執行:gem uninstall passenger 或者直接刪除Passenger的安裝目錄。然后重
新編譯和安裝Nginx即可。
===========================================================
【為Passenger指定Ruby的運行目錄】
===========================================================
如果系統安裝了多個Ruby解析器,需要指定一個Ruby運行目錄。如果是通過RVM來安裝Ruby解析器的,
那么RVM會將默認使用的Ruby解析器添加到PATH環境變量下。可以運行echo $PATH檢測,如果沒有的
話則手工添加到$PATH的最前面。
administrator@RoR-PRD:~$ rvm list
rvm rubies
ruby-1.9.2-p290 [ i686 ]
=> ree-1.8.7-2011.03 [ i686 ]
administrator@RoR-PRD:~$ echo $PATH
/home/administrator/.rvm/gems/ree-1.8.7-2011.03@release/bin: \
/home/administrator/.rvm/gems/ree-1.8.7-2011.03@global/bin: \
/home/administrator/.rvm/rubies/ree-1.8.7-2011.03/bin: \
/home/administrator/.rvm/bin: \
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
===========================================================
【重新發布一個Rails應用】
===========================================================
重新發布一個Rails應用,只需要再次上傳文件后,通知Passenger重啟應用就可以。這里有兩種方式:
第一種是重啟Nginx。另外一種是每次在發布之前,通過如下命令新建或者更新一個名為restart.txt的文
件,讓Nginx檢測到文件更新(timestamp改變)而自動在下次請求到來時重啟應用。
touch /webapps/mycook/tmp/restart.txt
必須注意的是:Passenger并不會自動為部署的應用創建好DB的環境,依然需要在發布新的應用之后,
手工執行:rake db:migrate RAILS_ENV=production
===========================================================
【Nginx中配置項的覆蓋問題】
===========================================================
server {
listen 80;
server_name localhost;
root /home/administrator/deploy/demo/public/; # <--- be sure to point to 'public'!
passenger_enabled on;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root html;
index index.html index.htm;
}
}
上面的配置選項中,一開始將root指定為對應的Rails應用的public目錄,但是在下面的location / {...}中
又將root指定為當前目錄下的index.html或者index.htm,所以會覆蓋前面的root配置,當在瀏覽器下
輸入:http://localhost/時,顯示的不是應用的根目錄,而是Nginx的歡迎頁面。
不過不建議這樣配置,因為這樣會令到當站點無法訪問時,無法判斷是Nginx的問題還是應用的問題。如
果要在本機再配置,可以這些寫:
server {
listen 80;
server_name 127.0.0.1;
root /home/administrator/deploy/demo/public/; # <--- be sure to point to 'public'!
passenger_enabled on;
}
但是URL就要變成這樣:http://127.0.0.1:80/,如果使用localhost,則Nginx會默認使用server_name
+ port 來分派請求,所以當輸入:http://localhost:80/時依然會被Nginx默認的服務器攔截,返回Nginx
的默認頁面
===========================================================
【部署為一個URI】
===========================================================
假設現在已經有了一個server配置:
server {
listen 80;
server_name www.phusion.nl;
root /websites/phusion;
}
我想將新的應用部署在這個sever下面,并且請求的URL是這樣的:http://www.phusion.nl/rails。
首先在現有的root下面創建一個soft link,指向改Rails應用:
sudo ln -s /home/administrator/deploy/demo/public /opt/nginx/html/demo
然后在原有的sever下添加如下配置:
server {
listen 80;
server_name localhost;
passenger_enabled on; # 新添加的
passenger_base_uri /demo; # 新添加的
}
然后重啟Nginx: sudo /etc/init.d/nginx restart。重新訪問:http://localhost/demo
通過這一點,我可以實現將多個Rails應用部署在同一臺機器下面的問題:只要指定不同的passenger_base_uri
===========================================================
【Passenger的配置選項】
===========================================================
>> passenger_root <directory>
指定Passenger的安裝根目錄
>> passenger_ruby <filename>
指定Passenger使用的Ruby解析器的目錄(按照安裝過程中推薦的值即可)
>> passenger_enabled on|off
可以定義在http/server/location/if ,默認off
>> passenger_base_uri <uri>
可以定義在http/server/location/if 中多次定義,為同一VPS配置多個應用
>> passenger_use_global_queue <on|off>
默認情況下Passenger使用一個全局隊列(Global queue)來存放請求。當有請求到來時會首先看后端的處
理進程是否有空閑的,有的話將該請求轉發給請求進程。沒有的話則存儲在自己的隊列里面。當該功能被
關閉時,會在各個后臺進程的內部自己維護一個獨立的隊列,而不是全局共享的。這樣會出現一個情況:
假如某個后臺進程因為掛起的request數量比較少,那么Passenger會把新的請求都分配到該進程。如果新
的請求都是屬于比較耗時的請求,那么會造成該進程壓力非常大,響應速度變慢。但其它已經處理完請求
的空閑進程卻無法派上用場。
默認情況下這個參數的值是on
>> passenger_buffer_response <on|off>
當這個參數被配置為on時,Passenger會對頁面的輸出進行緩存。也就是將response緩存到Passenger
中,然后逐步發送到客戶端。這樣做的目的是為了避免在response的內容比較大時,整個應用的實例被
鎖住,直到所有的內容都被完全發送到客戶端為止。
默認情況下這個參數的值是on
>> passenger_friendly_error_pages on|off
可以讓passenger在錯誤發生時以一種友好的形式來顯示錯誤信息(包括堆棧調用,啟動信息,建議等)。
強烈建議在生產環境下關閉該參數
默認情況下這個參數的值是on
>> passenger_max_pool_size <integer>
這個參數用于配置Passenger同一時刻可以并行的RoR/Rack應用實例的數量(注意是所有Rails應用)。推薦
的參數值至少等于CPU(內核的數目)。如果有2G的RAM,那么可以配置為30個。如果是只有256M內存
的VPS則建議配置為2
這個參數只能在http block中定義,默認值是6
>> passenger_min_instances <integer>
這個參數用于指定Passenger應該保留的Rails應用的數目。它會在應用第一次被訪問時,讓Passenger啟
動等于這個數目的實例并一直保持在內存中。即便是一直處于空閑狀態或者到了清除時間。
注意這個參數并不會pre-start應用!也即是說只有在應用第一次被訪問時,才會創建對應數目的實例,而
不會在Nginx啟動時就預先加載。所以第一次訪問時有可能會比較慢。如果需要需要預加載,需要配合另外
一個參數passenger_pre_start
這個參數的默認值是1
>> passenger_max_instances_per_app <integer>
這個參數和上面max_pool_size的區別是,max_pool_size是限定Passenger可以同時啟動的所有Rails/
Rack應用的數目(可以是多個app instance的總和),而這個參數是用于單獨指定某個app instance的數量
的。這個參數可以限制某個app instance占用了所有的pool和CPU時間片。
這個參數的值必須小于passenger_max_pool_size,0代表單個應用的實例數量沒有限制(最大值等于
max_pool_size)。
這個參數只能在http block中定義,默認值是0
>> passenger_pool_idle_time <integer>
這個參數指定了每個app instance最長的空閑時間。當一個應用在指定的時間內都沒有接收到請求而處于
空閑狀態的時候,它將會被銷毀而回收所占用的內存。
推薦的配置時間是應用頁面平均訪問時間 * 2。如果設置的值過小意味著應用會經常被實例化和銷毀,這
個過程比較耗時。如果是在非共享的主機環境下,或者需要7*24小時的響應,應該設置為0
當時設置為0不意味著永遠不會被銷毀。當另外一個app instance需要啟動一個worker process但Pass-
enger已經沒有工作線程了時,會強制將一個空閑狀態的app instance回收以空出worker process
這個參數只能在http block中定義,默認值是300秒
>> passenger_pre_start <url>
這個參數可以讓Passenger在Nginx啟動時,預先加載指定的應用。但要注意的是即便是預先加載的應用
在passenger_pool_idel_time 到達時,也會被銷毀。如果需要繼續保留在內存中,就要搭配前面提到的
passenger_min_instances。
URL支持完整的server_name,也可以是sub-URI
這個參數只能在http block中定義,可以被定義無限次。
>> passenger_log_level <integer>
這個參數可以指定Passenger如何往Nginx的日志文件中寫日志。參數值越大寫入的內容越詳細。總共
分為4級:0 僅顯示錯誤和異常;1 顯示有用的調試信息(供管理員定位錯誤用);2 顯示更加詳細的信息
(供開發過程使用);3 顯示所有日志信息。
這個參數只能在http block中定義,默認的級別是0
>> passenger_debug_log_file <filename>
這個參數可以指定Passenger將錯誤和調試信息寫到何處。
這個參數只能在http block中定義,默認情況下日志會寫到Nginx的全局日志文件
>> rails_env <string>
這個參數允許針對不同的應用,設置不同的環境。可以在http/server/block/if block中定義,每處一次
這個參數的默認值是production
===========================================================
【分析工具】
===========================================================
>> passenger-memory-stats
這個命令需要在root用戶下執行。可以使用 rvmsudo passenger-memory-stats 來查看所有的內存情況
>> passenger-status
這個命令同樣需要在root用戶下執行。可以使用 rvmsudo passenger-status 來查看Passenger的情況
----------- General information -----------
max = 6 # 等同于passenger_pool_max_size
count = 0 # 當前存活的用例,小于等于max值
active = 0 # 當前活躍的用例,小于等于count值
inactive = 0 # 當前空閑的用例,等于count-active
Waiting on global queue: 0
----------- Domains -----------
/var/www/projects/app1-foobar:
PID: 9617 Sessions: 0 Processed: 7 Uptime: 2m 23s
Sessions: 0 # 當前應用有多少客戶端連接等待處理
Processed:7 # 截至當前為止總共處理了多少個請求
----------- Application groups -----------
如果應用是基于Ruby on Rails的,當進程被kill掉時,日志會寫在應用自身的日志文件中,而不是Nginx
的日志文件。所以先檢查production.log,如果沒有異常信息再檢查Nginx的error.log文件
===========================================================
【其它】
===========================================================
假設在Rails應用下有Gemfile,那么Passenger會自動執行Bundle.setup()方法
當應用部署為Sub-uri的形式時,由于根路徑發生了變化,所以靜態資源(圖片,CSS,JS)的相對路徑都會
發生變化。這個時候如果使用靜態路徑那么所有靜態資源都將找不到文件,所以無論在何種部署情況下,
都推薦使用Rails提供的幫助方法:image_tag、stylesheet_link_tag、javascript_include_tag 來創建
相對的資源路徑。
===========================================================
-------------------------------------------------------------
生活就像打牌,不是要抓一手好牌,而是要盡力打好一手爛牌。