第9回 メンテナンスページへの切り替え
2008/06/03
今回は、Capistrano の deploy:web:disable
と deploy: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
タスクがやっているのは、要するに、メンテナンスページとして表示したい HTML 文書を ERB で生成して、それを #{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
に書き換えよ
という意味である。この正規表現はあらゆるパスに該当するので、要するにすべてのアクセスに対してメンテナンスページが表示されることになる。
この行の末尾についている [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
お、元に戻った!
めでたし、めでたし。