capistrano是目前最为流行的Rails部署工具,不过一旦进入产品阶段,我们可能希望在部署时显示一个“站点正在维护中”的页面,而不是正在升级中的应用,当前版本(2.5)的capistrano提供了两个内置任务来完成这一工作,它们就是deploy:web:disable和 deploy:web:enable,如果你仔细查看capistrano的部署目录,会在current/public目录下发现一个system目录,它是一个指向shared/system的链接,因此我们首先需要在shared目录下建立system目录,capistrano使用它来存放维护页面。
server$ mkdir deploy/shared
现在如果我们执行cap deploy:web:disable,capistrano会通过sftp上传一个默认的站点维护页面到shared/system /maintenance.html,而deploy:web:enable则会将这个页面删除,但是这个任务本身并不能将应用屏蔽掉,我们需要修改前端服务器的rewrite规则。
如果你使用nginx,那么加入下面几行到你的nginx.conf:
server {
root /current/deploy/path/public;
if (-f $document_root/system/maintenance.html) {
set $maintenance 1;
}
if ($request_uri ~* (jpg|jpeg|gif|js|css)$) {
set $maintenance 0;
}
if ($maintenance) {
rewrite ^(.*)$ /system/maintenance.html last;
break;
}
location / {
....
这样nginx会首先判断维护页面是否存在,如果存在,则将所有清除都转向维护页面,如果使用apache,则需要修改.htaccess(未验证):
RewriteCond %{REQUEST_URI} !\.(css|jpg|js|gif|png)$
RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f
RewriteCond %{SCRIPT_FILENAME} !maintenance.html
RewriteRule ^.*$ /system/maintenance.html [L]
如果你想要这一切自动进行,那么你可以将这两个任务加入deploy任务:
namespace :deploy do
desc "Default deploy will update the code without migrate the database and restart the servers"
task :default do
# put up the maintenance screen
web.disable
transaction do
update_code
symlink
copy_configs
end
restart
# remove the maintenance screen
web.enable
end
end
如果你想要自定义维护页面,可以通过覆盖默认的deploy:web:disable任务实现:
namespace :deploy do
namespace :web do
task :disable do
on_rollback { delete "#{shared_path}/system/maintenance.html" }
require 'rubygems'
require 'haml'
template = File.read("./app/views/layouts/maintenance.html.haml")
haml = Haml::Engine.new(template)
maintenance = haml.render(Object.new,
:deadline => ENV['UNTIL'],
:reason => ENV['REASON'])
put maintenance, "#{shared_path}/system/maintenance.html",
:mode => 0644
end
end
end
这段代码渲染了layouts/maintenance.html.haml,你可以根据自己的需要定义它,这里我们传入了两个变量,一个指定原因,一个指定恢复时间:
%h1
We're currently down for
= reason ? reason : "maintenance"
as of
= Time.now.strftime("%H:%M %Z")
%p
Sorry for the inconvenience. We'll be back
= deadline ? "by #{deadline}" : "shortly"
Please email us if you need to get in touch.
你可以在执行deploy:web:disable之前设定这两个变量:
UNTIL=”16:00 MST” REASON=”a database upgrade” cap disable_web
参考:

