icon Capistrano 入门

第9章 切换至维护页面

此章对 Capistrano 的 deploy:web:disabledeploy:web:enable 任务进行说明


根据 cap -T 表示的说明,各种任务的目的如下:

  • deploy:web:disable -- 使访问者看到维护页面。
  • deploy:web:enable -- 可以再次通过web搜索应用程序。

嗯,看起来似乎很便利,但是接下来会变成什么却毫无头绪。让我们来看看源代码(省略一部分)。

namespace :deploy do
  namespace :web do
    task :disable, :roles => :web, :except => { :no_release => true } do
      require 'erb'
      on_rollback { run "rm #{shared_path}/system/maintenance.html" }

      reason = ENV['REASON']
      deadline = ENV['UNTIL']

      template = File.read(File.join(File.dirname(__FILE__), "templates", "maintenance.rhtml"))
      result = ERB.new(template).result(binding)

      put result, "#{shared_path}/system/maintenance.html", :mode => 0644
    end
    
    task :enable, :roles => :web, :except => { :no_release => true } do
      run "rm #{shared_path}/system/maintenance.html"
    end
  end
end

deploy:web:disable 任务的内容,一句话,就是用 ERB 生成希望作为维护页面显示的 HTML 文件,并把这个写入 #{shared_path}/system/maintenance.html 文件。

作为维护页面的模板 maintenance.rhtml 已存在。因为 File.dirname(__FILE__) 是这个源代码的某个目录,便成了 Capistrano 的安装目录(根据环境不同,/usr/lib/ruby/gems/1.8/gems/capistrano-2.3.0/等等)下的lib/capistrano/recipes/templates/maintenance.rhtml 。因为还没有指定模板的变量,所以想准备好单独的维护页面的话(这个当然是想准备的),参考此代码,自己写任务,添加至 config/deploy.rb

然后,deploy:web:enable 任务删除这个文件。

通常,shared_path 是变量 :deploy_to 指定目录下的 shared 目录。也就是说,在 /var/rails/ballad 部署的话,/var/rails/ballad/shared/system/maintenance.html 这个文件便会有问题。


这个文件如果存在的话,可以只凭这个让访问者看到维护页面这样的话说起来很简单,其实并非如此。

还有必要同 Apache 的 mod_rewrite 指令进行一些斗争。

我看见 mod_rewrite 就会变得有些郁闷。mod_rewrite 是瑞士军刀,也是黑魔术(voodoo)(Apache module mod_rewrite)。它能够灵活的进行任何设定,这种奇妙的语法真让我着迷。

好啦。


不管怎样,在 httpd.conf 做如下输入的话,deploy:web:disable 任务便可执行了。

<VirtualHost *:80>
  ServerName ballad.example.com
  DocumentRoot /var/rails/ballad/current/public
  ErrorLog /var/log/httpd/ballad-error_log
  CustomLog /var/log/httpd/ballad-access_log combined env=!nolog

  <Directory /var/rails/ballad/current/public>
     Order Deny,Allow
     Allow from All
  </Directory>

  RewriteEngine On
  RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f
  RewriteCond %{REQUEST_URI} !^/images/
  RewriteCond %{REQUEST_URI} !^/javascripts/
  RewriteCond %{REQUEST_URI} !^/stylesheets/
  RewriteRule ^.*$ /system/maintenance.html [L]

  RewriteRule ^/(images|javascripts|stylesheets)/(.*)$ /$1/$2 [L]

  ProxyRequests Off
  ProxyPass / balancer://ballad_cluster/

  <Proxy balancer://ballad_cluster/>
    BalancerMember http://127.0.0.1:3000
    BalancerMember http://127.0.0.1:3001
    BalancerMember http://127.0.0.1:3002
    BalancerMember http://127.0.0.1:3003
  </Proxy>
</VirtualHost>


让我们来尝试一下黑魔法的说明吧。

首先,使用 RewriteEngine On 让 mod_rewrite 有效。

接下来,在RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f 上,设定

如果 %{DOCUMENT_ROOT}/system/maintenance.html 文件存在

这样的条件。在%{DOCUMENT_ROOT} 中,嵌入以上声明的值 /var/rails/ballad/current/public

接下来3行的 RewriteCond 设定

如果不是到 /images 或 /javascripts 或 /stylesheets 目录的文件的搜索

这样的条件。处于URI路径模式之前的! 表示否定。

接下来的 RewriteRule ^.*$ /system/maintenance.html [L] 是,
通过正则表达式将匹配 ^.*$ 的路径改写成 /system/maintenance.html
</blockquote>
的意思。这个正则表达式匹配所有路径,所以实际上对于所有的搜索,维护页面都会显示。

这行末尾的 [L] 是“仅做此 URL 的改写”的意思。顺便说一下,“L”是“Last rule”的略语。

接下来的 RewriteRule ^/(images|javascripts|stylesheets)/(.*)$ /$1/$2 [L] 是,

搜索/images 或 /javascripts 或 /stylesheets 目录中的文件,则返回原样

的意思。这里也添加了 [L] 标志,所以这样的对目录中文件的搜索,通常(无论是否在维护中)由 Apache 自己处理。这是为了在维护页面中也能显示图像等,但也有减轻 Rails 应用程序负荷的效果。

这样说明的话,会感觉很简单。但是,读取 mod_rewrite 的文档却相当困难。只推荐给以“吃苦耐劳”为座右铭的人士。

ProxyRequests Off 以下的记述,是为了将 Apache 作为负载平衡器(反向代理)使用。这和这一章的内容没有太大的关系,是向在本地主机的 3000 号至 3003 号端口中运行的Rails程序转送了请求。maintenance.html 不存在(即一般状态)的状态下,这种设定便运行,使 Rails 程序在网站访问者中可见。


那么,尝试执行 deploy:web:disable 任务。

% cap deploy:web:disable
  * executing `deploy:web:disable'
    servers: ["alpha.oiax.jp"]
 ** sftp upload #<StringIO:0xb7855b6c> -> /var/rails/ballad/shared/system/maintenance.html
    [alpha.oiax.jp] /var/rails/ballad/shared/system/maintenance.html
    [alpha.oiax.jp] done
  * sftp upload complete

在浏览器中打开 http://ballad.example.com/(实际不存在),即显示出维护页面。

在屏幕上显示的信息中可以看到 sftp 这个文字。这是因为维护页面在本地主机(你自己的电脑)上生成后被发送到远程主机上了。

接下来执行 deploy:web:enable 任务。

% cap deploy:web:enable
  * executing `deploy:web:enable'
  * executing "rm /var/rails/ballad/shared/system/maintenance.html"
    servers: ["alpha.oiax.jp"]
    [alpha.oiax.jp] executing command
    command finished

啊,回复原状了!!

真让人兴奋。

(2008/06/03)