Rails勉強会@東京第23回

Rails勉強会@東京第23回 に行ってきた。2週間遅れだけどレポートする。

勉強会の形式は いつものごとく

ただ、今回は試験的に「昼食懇親会」を行なった。

  • そこで話しているうちにうち解けてセッションが弾むのでは?
  • セッションの時間を潰して長い自己紹介をしなくても、自然に相手を認識できるのでは?
  • セッション案も自然に出てくるのでは?
  • 夜の「飲み会懇親会」よりも安く済むのでは?

という趣旨だ。おおむね好評だった模様。ただ、私はどうも元気が出なくて遅れていったので懇親会は殆ど出てない。

前半

前半は3つのセッションに分かれた。

  • Rails 2.0を読む。
  • 初心者セッション - Scaffoldの半歩先に
  • ぐだぐだ喋る

初心者セッションは前回と同じ内容だそうだ。Scaffoldは試してみたけれどもその先へ進めないというRails初心者のために、Scaffoldで生成されたモデルやコントローラーを解説して、自力でコードを書くところまで持って行くという趣旨。 前回に引き続いてオーナーをやってくださってるYuumi3さんには乙! で、今回もScaffold結果の解説だけで時間切れみたい。このやり方はRailsの初心者向け解説としては理想的だと思うけど、時間は意外に掛かるのね。 masuidriveさんが言ってる けど、「自分でやるだけなら5-10分で終わること」が限界な訳か。

余った部屋に溜まってぐだぐだ雑談するセッションはなんか好例になってきたけど、この企画はとても良い。ぐだぐだ喋っているうちに色々とアイディアが湧いてきて、その場に集まってる人の知恵を結集してもの凄い勢いで解析が進んだり、プロダクトができあがったりする。

今回は昼食懇親会をやった関係上、懇親会とぐだぐだセッションは地続きだったらしい。その様子は shachiさんがレポートしてる 。 この手のイベントは結局、懇親会とかでする雑談が一番大切だったりするわけだよね。ぐだぐだセッションはそのメリットを勉強会時間内に取り入れる試み、とも言える。

Rails 2.0

さて、雑談セッションを褒めておいて何だけど、私はRails 2.0セッションのオーナーをやった。 現在Rails 2.0のPreview Releaseが出ているのでそれを眺めてみようというセッション。

私は2.0変更点を全然把握してないので、詳しいことは 諸橋さん たちに教えて貰いながらセッションを進めた。前にも書いたけど、Rails勉強会@東京ではこういうタイプのセッションオーナーは大歓迎なのだ。つまり、「これを知りたいから誰か教えてください」と言ってセッションを開いて、それで色々質問するいうやりかた。みんな恐れずにどんどんセッションを主催して欲しい。

で、結論としては、Rails 2.0はそれほど驚きはない。

  • ActiveResourceが入った
  • プロプライエタリDBMSへのドライバはプラグインに追い出した
  • acts_as系はプラグインに追い出した
  • テンプレートのファイル名規約が変わった。(古い規約も認識するみたい)

    • 〈テンプレート名〉.〈出力フォーマット拡張子〉.〈テンプレートエンジン拡張子〉
    • 例えば、今までの"list.rhtml"は"list.html.erb"になる。
  • Migrationが格好良くなった。

いくつかの変更点について該当部分のソースコードを呼んでみたけど、普通。なんというか、驚きがない。ま、順当に進化したということなんだろうね。

xibbarさんのスライド が非常に詳細なので、こちらを参照。セッションでもこのスライドをみんなで見ながら進めさせてもらった。 あとは id:faultierさんのレポート が詳しい。

詳細な資料があるので私はこれ以上は書かない。

後半

後半は4つのセッションに分かれた。

  • 初心者セッション - プロダクション環境の構築
  • engineからgeneratorへの移行
  • プロファイルの話
  • 開発環境の話

私は、「プロダクション環境」のオーナーになった。Railsアプリケーションの開発の仕方はスクリーンキャストやなんかで色々と出回ってるのに対して、実際にアプリケーションを運用する方法はそこまでは出回ってない(いや、探せばそれなりにあるけど)。これを1つ説明しましょう、というセッション。

予め自サーバーに仕込んでおいて、実際にサーバーの設定をいじくって見せながら解説した。

以下における仮定

また、次の知識を前提とする

  • Railsでscaffoldして中身を眺めるくらいはやったことがあること。
  • Apacheの設定をなんとなくは弄ったことがあること

ちなみに、世間ではこの手のお手軽サーバーにはCentOSが人気だけど、偏見を承知で言うなら断然debianだ。私にはサーバーにCentOSとかましてFedoraを使う意味が分からない。yumって重いし機能もapt-get相当でしょ? Debian系なら更に楽なaptitudeがあるんよ!! 「枯れてる+サポート」でRedhatを取るなら分かるけど。でも、典型的な構成を作ってそのまま使うならともかく、あれこれと試すためのサーバーにはDebian系がいい。DebianUbuntuだ。

運用環境の選択肢

運用環境選択肢として今回は次を紹介した。

以下ではこれらの選択肢を順番に触れていく。

WEBrick, Mongrel

Railsの開発用サーバーとしてはWEBrickMongrelが主流である。個人のちょっとしたサービスならこの開発用サーバーをそのままdaemon化しても十分である。 セッションで聞いてみたら、開発にはWEBrickを使っている人が多かった。WEBrickRuby 1.8標準添付なのでどこでも動くし、便利だね。

でも、どうせならMongrelを使ったほうが起動が速くていい。Mongrelは主にRailsのために作られた簡易HTTPサーバーだ。一部のコードをC拡張ライブラリとして書いてるのと、機能を絞り込んである分だけWEBrickより速い。

Mongrelのインストールは

# gem install --include-dependencies mongrel

するだけ。Mongrelをインストールすると script/server はデフォルトでWEBrickの代わりにMongrelを使うようになる。Mongrelインストール後に敢えてWEBrickを使いたい場合は

$ ruby script/server webrick

とやる。

まあその辺は好みで。 -d オプションを渡せば script/serverdaemonになるので

# ruby script/server -p 80 -e production -d

とかやればそれだけで運用環境になる。WEBrickMongrelは、Rails呼び出し部分はシングルスレッドで処理するので限界はあるけれど、秒あたりのページビューが1桁ならまあ、使える。

詳しくは ruby script/server --help 参照。

mod_proxy_balancer + Mongrel

さて。Apacheのバージョンを2.2に上げられるなら mod_proxy_balancer は良い選択だ。2.2で導入されたApache標準のモジュールで、ApacheのProxy機構に簡易ロードバランサー機能を組み込んでくれる。

apache ──────(HTTP)───┬─ mongrel
(proxy_balancer)                  ├─ mongrel
                                  ├─ mongrel
                                  ├─ ...

この構成は

設定例:

<Proxy balancer://mongrel_cluster>
    BalancerMember http://127.0.0.1:8000
    BalancerMember http://127.0.0.1:8001
    BalancerMember http://127.0.0.1:8002

   Order allow,deny
    Allow from all
</Proxy>
<VirtualHost *>
    ServerAdmin webmaster@yugui.jp
    ServerName rails-tokyo-23.yugui.jp
    ServerSignature On

    DocumentRoot /var/rails-tokyo-23/current/public
    <Directory />
        Options FollowSymLinks
        AllowOverride None
    </Directory>
    <Directory /var/rails-tokyo-23/current/public/>
        Options Indexes FollowSymLinks MultiViews
        AllowOverride None
       Order allow,deny
        allow from all
    </Directory>

   # Possible values include: debug, info, notice, warn, error, crit,
   # alert, emerg.
    LogLevel warn
    CustomLog /var/log/apache2/rails-tokyo-23.access.log combined
    ErrorLog /var/log/apache2/rails-tokyo-23.error.log

    RewriteEngine on
    RewriteLog /var/log/apache2/rails-tokyo-23.rewrite.log
    RewriteLogLevel 1

   # on web_disable'd
    RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f
    RewriteCond %{SCRIPT_FILENAME} !maintenance.html
    RewriteRule ^.*$ /system/maintenance.html [L]

   # static index page
    RewriteCond %{DOCUMENT_ROOT}/index.html -f
    RewriteRule ^/$ /index.html [QSA]

   # Rails cached pages
    RewriteRule ^([^.]+)$ $1.html [QSA]

    RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
    RewriteRule ^/(.*)$ balancer://mongrel_cluster%{REQUEST_URI} [P,QSA,L]

    ErrorDocument 500 "<h2>Application error</h2>Rails application failed to start properly"
</VirtualHost>

ま、VirtualHostの一般的な設定部分はおいといて。

DocumentRoot /var/rails-tokyo-23/current/public

DocumentRootにはRailspublic ディレクトリを指定する。静的ファイルはApacheが取り扱うからだ。

冒頭の部分が肝だ。ここで3つ並べたMongrelに適宜振り分けるように設定しておいて、で、あとでここの'balancer://mongrel_cluster'っていうところにmod_rewriteで飛ばすんだな。

mod_rewriteは、Apache内部でリクエスURIを書き換えて柔軟にリクエストを処理するための標準モジュールだ。まぁそのセッションに来ていた人はみんな知っていたみたいだけど じゃ、そのmod_rewrite部分を見ていこう。

# on web_disable'd
RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f
RewriteCond %{SCRIPT_FILENAME} !maintenance.html
RewriteRule ^.*$ /system/maintenance.html [L]

これは、public/system/maintenance.htmlというファイルが存在したら今サイトはメンテナンス中ということなのでmaintenance.htmlの内容を出力して終わり、という話。

# static index page
RewriteCond %{DOCUMENT_ROOT}/index.html -f
RewriteRule ^/$ /index.html [QSA]

それから、indexページのキャッシュが存在したらそれを使うとか。

# Rails cached pages
RewriteRule ^([^.]+)$ $1.html [QSA]

リクエストに拡張子が付いてなかったらHTML扱いするとか。

この辺はRails標準の public/.htaccess からコピーしてきてちょっと手を加えただけ。 rails コマンドでアプリケーションの雛形を作った時点で public/.htaccess っちゅうのが作られてるんだけど、何にしてもRailsの配備設定はこの public/.htaccess がとても参考になる。

さて、それで最後のところね。

RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
RewriteRule ^/(.*)$ balancer://mongrel_cluster%{REQUEST_URI} [P,QSA,L]

リクエストにマッチするファイルが存在したら、Railsがキャッシュを作っていると判断してそのファイルをそのまま返す。

この時点で、先の書き換えによって確実に拡張子が付いているので、Railsがページキャッシュを作っていれば public/controller_name/action_name.html とかいう名前で存在するはずで、 %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f によってキャッシュの有無を判別できるのだ。

ファイルが存在しなかったらこれは動的ページへのリクエストである可能性があると判断してmongrelに転送する。終わり。

バックグラウンドMongrel

じゃあ、バックグラウンドのMongrelプロセスはどうやって立ち上げるのか。私はセッションではcapistranoで立ち上げてしまった。

capistranoを使わないなら、バックグラウンドのmongrelの立ち上げにはmongrel_clusterがいいだろう。これもgemで入れられる。

# gem install --include-dependencies mongrel_cluster

設定とか詳しいことは バリケンさんとこ参照 !

capistrano

セッションで使ったcapistranoの設定は 公式サイトの記述 を参考にした。

こんな感じの script/spin を作って、

#!/bin/sh

`dirname $0`/process/spawner -a 127.0.0.1 -p 8000 -i 3

config/deploy.rb をこんな感じに編集して

set :application, "example"
set :repository,  "http://svn.yugui.jp/misc/trunk/example-app"

# If you aren't deploying to /u/apps/#{application} on the target
# servers (which is the default), you can specify the actual location
# via the :deploy_to variable:
set :deploy_to, "/var/rails-tokyo-23"

# If you aren't using Subversion to manage your source code, specify
# your SCM below:
# set :scm, :subversion

role :app, "rails-tokyo-23.yugui.jp"
role :web, "rails-tokyo-23.yugui.jp"
role :db,  "rails-tokyo-23.yugui.jp", :primary => true

set :ssh_options, :port => 422
set :use_sudo, false

namespace :deploy do
  task :restart, :roles => :app do
    stop
    start
  end
end

capistranoについては今回は深くは触れない。希望者がいたら次回の勉強会でセッションやろうかな。 以前のRails勉強会でやったセッションの記録 もあるので参照。

RailsによるアジャイルWebアプリケーション開発 第2版 』にも載ってるけど、最新版のcapistrano 2.0には対応していないので注意。まあ、1.1の設定でも基本的には動くからいいんだけど。

一度慣れてしまうと手でちまちまサーバー起こしたり止めたりメンテナンス画面出したりやってられないので私は今回もcapistrano使いました、というだけ。Railsアプリケーションのデプロイ自体は単にソースツリーをサーバーにコピーすればいいのでcapistranoを使わなくてもscpでも済む。

Apache + FastCGI

Mongrel以前に主流だった手法だ。今も愛用している人はいる。

構成はこんな感じ。apacheと、バックグラウンドのワーカープロセスをFastCGIプロトコルで繋ぐ。

apache ──(Fast CGI)─┬─ worker
                       ├─ worker
                       ├─ worker
                       ├─ ...

FastCGIを使うにはまず、ApacheFastCGI用のモジュールを用意する必要がある。Apache用のFastCGIモジュールにはmod_fastcgiとmod_fcgidがあるが、ここでは mod_fcgid を使用する。mod_fastcgiはなんか開発止まってるらしい?

ワーカープロセスは予め立ち上げておくパターンと、apacheに管理させるパターンがある。私はapacheに任せるのが楽で好き。ワーカーが死ぬと適当に立ち上げてくれたりもするしね。ま、そのへんは本来は daemontools や本式な死活監視システム使えという話かも知れないけど。

Debianならインストールはapt-getするだけ。

# apt-get install libapache2-mod-fcgid

設定例

<VirtualHost *>
    ServerAdmin webmaster@yugui.jp
    ServerName rails-tokyo-23.yugui.jp
    ServerSignature On

    DocumentRoot /var/rails-tokyo-23/current/public
    <Directory />
        Options FollowSymLinks
        AllowOverride None
    </Directory>
    <Directory /var/rails-tokyo-23/current/public/>
        Options Indexes FollowSymLinks MultiViews ExecCGI
        AllowOverride None
       Order allow,deny
        allow from all
        FCGIWrapper "/var/rails-tokyo-23/current/public/dispatch.fcgi" .fcgi

        RewriteEngine On
        RewriteRule ^$ index.html [QSA]
        RewriteRule ^([^.]+)$ $1.html [QSA]
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteRule ^(.*)$ dispatch.fcgi [QSA,L]
    </Directory>

    Addhandler fcgid-script .fcgi
    DefaultInitEnv RAILS_ENV production

   # Possible values include: debug, info, notice, warn, error, crit,
   # alert, emerg.
    LogLevel warn
    CustomLog /var/log/apache2/rails-tokyo-23.access.log combined
    ErrorLog /var/log/apache2/rails-tokyo-23.error.log

    RewriteEngine on
    RewriteLog /var/log/apache2/rails-tokyo-23.rewrite.log
    RewriteLogLevel 9

   # on web_disable'd
    RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f
    RewriteCond %{SCRIPT_FILENAME} !maintenance.html
    RewriteRule ^.*$ /system/maintenance.html [L]

   # static index page
    RewriteCond %{DOCUMENT_ROOT}/index.html -f
    RewriteRule ^/$ /index.html [QSA,L]

    ErrorDocument 500 "<h2>Application error</h2>Rails application failed to start properly"
</VirtualHost>

が消えた以外はmongrelのときと、おおまかには変わってないね。特に静的コンテンツ周りのmod_rewrite設定は。

変わったのは内のこの部分だな。

FCGIWrapper "/var/rails-tokyo-23/current/public/dispatch.fcgi" .fcgi

RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ dispatch.fcgi [QSA,L]

mongrelへのプロキシの代わりにワーカープロセスにリクエストを回すようにしたんだな。ワーカープロセスの実体である dispatch.fcgirailsコマンドが最初に public/ 内に生成してくれてる筈。

Lighttpd + FastCGI

もう1つ人気のある構成例としては Lighttpd を使うものがある。

LighttpdというのはApacheよりも軽量なwebサーバー実装で、LLなwebアプリケーションの配備環境としては結構有力だ。"Lighttpd"(らいとえいちてぃーてぃーぴーでぃー)は発音しづらいのでみんなLighty(らいてぃー)と呼ぶ。

LighttpdApacheよりは機能が少ないが、その分だけ軽量で配信も速い。mongrelがあちこち実装をさぼっているのとは違って本式のwebサーバーだ。高負荷時の安定性ではApacheに劣るという意見もあるが、まぁ、通常は大丈夫だ。

LighttpdFastCGIモジュールが標準で付いている上に、活発にメンテナンスされている。これがRailsやなんかのデプロイ環境として人気を集める理由だろう。

多くのLinuxディストリビューションではパッケージ化されていて、Debianでも

# apt-get install lighttpd

だけで入る。

設定例

設定というか、Lighty + FastCGI を走らせる一番簡単な方法はRailsアプリケーションのディレクトリで

# ruby script/server lighttpd -p 80 -e prouction -d

とかやることだ。自動的に config/lighttpd.conf が生成されて、これを読み込んでLighttpdが立ち上がる。FastCGIのワーカープロセスはLighttpdが管理してくれる。

この要領で開発用サーバーにもLighttpdを使っている人もいる。何しろ、Railsの場合はdevelopment環境ではアプリケーションサーバーの再起動が必要になることは希だし、困らないんだな。もし再起動が必要になってもLighttpdは起動もApacheより速いし。

それでもまあ、自動生成されるのと同様の設定を/etc/lighttpd.confにしてやっても良い。 Apacheの設定とは文法がかなり異質だけど、条件節を書けたりしてプログラム的でちょっと面白い。

$HTTP["useragent"] =~ "^(.*MSIE.*)|(.*AppleWebKit.*)$" {
  server.max-keep-alive-requests = 0
}

$HTTP["url"] =~ "^/doc/|^/images/" {
    dir-listing.activate = "enable"
}

初期状態の設定ファイルからrailsアプリケーションに対応してやるなら、以下のような感じ。

  1. server.modulesの読み込みリストにmod_fastcgiを足す。

  2. FastCGIの設定として次を追記。

server.error-handler-404 = "dispatch.fcgi"
fastcgi.server =  (
    ".fcgi" => (
        (
            "min-procs" => 1,
            "max-procs" => 3,
            "socket"    => "/var/run/lighttpd/rails.sock",
            "bin-path" => "/var/rails-tokyo-23/current/public/dispatch.fcgi",
            "bin-environment" => ( "RAILS_ENV" => "production" )
        )
    )
)

ポイントは"404 Not Found"のハンドラとしてFastCGIを設定してやることだな。これはApacheのときに「キャッシュファイルがなかったらmongrelに転送」とか書いたのと同じこと。

他の選択肢

Pound

Pound + Apache + Mongrelというのもあるが、どうも微妙だと思うので時間の都合もあって紹介しなかった。Poundっていうのは軽量のロードバランス・ソフトウェア実装。この場合は構成は次のようになる。

Pound ─┬─ Apache
         ├  mongrel
         ├  mongrel
         ├  mongrel
         ├  ...

Poundを使うパターンは『 RailsによるアジャイルWebアプリケーション開発 第2版 』に載ってるので必要ならそっちを参照。

微妙というのは、つまりロードバランスをPoundに追い出すほどの負荷がApacheに掛かることはあるのかな、ということ。RailsアプリケーションでApacheボトルネックになることは少ないんじゃなかろうか。だとすると、ロードバランサはmod_proxy_balancerでいいじゃないかと思う。

まあ、Apachetが2.1だったり1.x系統だったりしても使えるという利点はあるかも知れない。でも、2.1ならもう潔く2.2に上げちゃいなYO!

SCGI

SCGIというWebサーバー - アプリケーションサーバー間通信のためのプロトコルがある。FastCGImod_jkと位置づけとしては同じだ。これのruby版サーバーライブラリとかrails対応というのもある。

けれども、これの作者のZed Shawが結局、mongrelを作ってそっちに移行してしまった。 作者としてmongrelのほうがいいという判断でそっちをメインにやるのであるなら、今後のメンテナンスが不安だ。おすすめしない。

AJP

AJPというプロトコルもある。Apacheモジュールの実装であるmod_jkの名前でも知られている。FastCGIやSCGIと同じ位置づけだ。ApacheJava Servletコンテナを繋ぐのによく使われている。これのruby版サーバーライブラリとrails対応は私が書いた。

でも、まだ不安定だし、速度も出ないし、そんな状態で放置しているのでおすすめしない。でもApacheサイドでJavaの知見を活かせる技術であるわけだし、私としてはAJPの逆襲をやるつもりはある。そのうちおすすめできるようになったらまた記事を書く。

飲み会

今回は懇親会を昼にやったので、飲み会はとくに呼びかけなかった模様。それでも行きたい人はそれぞれ飲みに行ったみたいだけど。

私は、なんか不安症状とか疲労感がひどかったので早々に帰ってしまった。というわけで飲み会での雑談&与太話は無し。

なんか、勉強会の途中からどうしようもなく疲れを感じて、いつにもましてボソボソと喋ってたと思う。聞きづらくてすんません。

参考資料

Official Documents:

  • Apache 2.2

    Apache設定の資料としては何を置いてもまず公式のドキュメントだ。丁寧だし、主なところは日本語版があるし。

  • Lighttpd

    こちらも設定に必要な一通りのことは公式ドキュメントで十分。(英語)

  • Capistrano

    Capistranoは本記事執筆時点では公式サイトのドキュメントはあんまり充実してない。(英語)

Books:

Reports: