Catalyst::Manual::Cookbook::Deployment
Cookbook長いので分割。
デプロイについてのレシピ。Webサーバーエンジンとアプリケーションの効率化も含む。
http://search.cpan.org/~jrockway/Catalyst-Manual-5.700701/lib/Catalyst/Manual/Cookbook.pod#Deployment
mod_perl Deployment
mod_perlは多くのアプリケーションに対しての最適解だけど利点と欠点を述べる。他の方法としてはFastCGIがある。
Pros
- Speed
mod_perlはとても高速で、それぞれのApacheプロセスのメモリにアプリケーションをロードすることによって恩恵を受けられる。
- Shared memory for multiple apps
Cons
- Memory usage
アプリケーションはすべてメモリにロードされるのでそれぞれのApacheプロセスが大きくなってしまう。これは静的ファイルや大きいファイル、速度の遅いクライアントなどに束縛され得るということを意味する。そのため、構造を分割して軽量なフロントエンドが動的なリクエストをバックエンドのmod_perlサーバーに渡すようにした方がいい。
- Reloading
アプリケーションを変更するとApacheを再起動する必要がある。CatalystはApache::ReloadやStatINCをサポートしていない。これはフロントにWebサーバーを置くいい理由になり、そこにErrorDocument 502を設定してメンテナンスによってダウンしていることを通知できる。
- Cannot run multiple versions of the same app
名前空間が衝突するので同じアプリケーションの違うバージョンを同じApacheインスタンスで実行できない。
- Setup
Catalystアプリケーションを実行するためにmod_perlをセットアップしよう。
1. Install Catalyst::Engine::Apache
最新バージョンのCatalystとCatalyst::Engine::Apacheをインストールする。バージョン5.50からApacheエンジンがCatalystから分割されて個別に更新できるようになった。
2. Install Apache with mod_perl
Apache 1.3と2を両方ともサポートしてるけど2を強く推奨する。Apache2ではworker MPMではなくpreform MPMを使用できる。これは多くのPerlモジュールがスレッドセーフじゃないので、スレッドワーカー環境で問題が起きる可能性があるため。でも、Catalystはスレッドセーフなのでちゃんとわかってる人なら別にいい。
Debianでは次のコマンドでインストールできる。
apt-get install apache2-mpm-prefork apt-get install libapache2-mod-perl2
3. Configure your application
すべてのCatalystアプリケーションはmod_perlで実行すると自動的にmod_perlハンドラになる。だから設定はラクチン。Apache2での基本的な設定はこうなる。
PerlSwitches -I/var/www/MyApp/lib PerlModule MyApp <Location /> SetHandler modperl PerlResponseHandler MyApp </Location>
一番大事な行はPerlModule MyAppだ。これはmod_perlにアプリケーション(コントローラ、モデル、ビュークラスと設定を含む)を共有メモリにpreloadするように指示する。-Debugモードが有効になってると最初にapacheを起動したときに起動メッセージが表示されるだろう。
Apache1.3の例はCatalyst::Engine::Apache::MP13を見てください。
Test It
これでおk。http://your.server.com/にアクセスして確認してみよう。
Other Options
- Non-root location
サーバーやバーチャルホストのルートで実行するとは限らない。
<Location /myapp> SetHandler modperl PerlResponseHandler MyApp </Location>
この方法で起動するとuri_forメソッドが役に立ち、正しいリンクを作ってくれる。
- Static file handling
静的ファイルをApacheで直接受ける場合。
DocumentRoot /var/www/MyApp/root <Location /static> SetHandler default-handler </Location>
これはroot/staticのすべてのファイルをApacheが直接処理するようにする。2段構成の場合はフロントのサーバーが静的ファイルを処理する。
Catalyst on shared hosting
FastCGIとシェルが使える共有サーバーがあれば、Catalystアプリケーションをローカルディレクトリにインストールできる。まずは
perl -MCPAN -e shell
を実行し、CPANの設定プロセスを行ってから何もインストールしないで終了する。次に.bashrcを開いて
export PATH=$HOME/local/bin:$HOME/local/script:$PATH perlversion=`perl -v | grep 'built for' | awk '{print $4}' | sed -e 's/v//;'` export PERL5LIB=$HOME/local/share/perl/$perlversion:$HOME/local/lib/perl/$perlversion:$HOME/local/lib:$PERL5LIB
を追加し、一旦ログアウトしてから再度ログインする。最後に.cpan/CPAN/MyConfig.pmを開いて以下を追加する。
'make_install_arg' => qq[SITEPREFIX=$ENV{HOME}/local], 'makepl_arg' => qq[INSTALLDIRS=site install_base=$ENV{HOME}/local],
これでいつも通りCPANモジュールをインストールできる。モジュールはローカルディレクトリにインストールされ、Perlはそれを参照してくれる。最後に、あなたほバーチャルホストのルートに移動してアプリケーションのスクリプトディレクトリへのシンボリックリンクを作る。
cd path/to/mydomain.com ln -s ~/lib/MyApp/script script
で、.htaccessに以下の設定を追加する(これはサーバーが.plをfcgiとして扱うようになっている場合。そうじゃない場合はスクリプト名をmyapp_fastcgi.fcgiなどにリネームするか、SetHandlerで設定する必要がある)。
RewriteEngine On RewriteCond %{REQUEST_URI} !^/?script/myapp_fastcgi.pl RewriteRule ^(.*)$ script/myapp_fastcgi.pl/$1 [PT,L]
これでhttp://mydomain.com/はちゃんと動く。
FastCGI Deployment
FastCGIはCGIに対する拡張で高いパフォーマンスを発揮する。製品環境(production environments)に最適だ。
Pros
- Speed
FastCGIはmod_perlと同等の性能を発揮する。CGIという言葉に惑わされてはいけない。アプリケーションは複数の永続プロセスとしてWebサーバーからの接続を待機する。
- App Server
外部FastCGIサーバーを使用する場合、アプリケーションはスタンドアローンのアプリケーションサーバーとして動作する。これはWebサーバーとは別々に再起動できる。そのためより堅牢な環境となり、アプリケーションの変更を素早く適用できる。フロントのサーバーではアプリケーションが再起動している間にメンテナンスページを表示することもできる。
- Load-balancing
アプリケーションを複数のバックエンドサーバーで起動してフロントのWebサーバーからロードバランスすることもできる。この場合は1つが落ちてもアプリケーションは無事だ。
- Multiple versions of the same app
それぞれのFastCGIアプリケーションは異なるプロセスなので1つのサーバーで同じアプリケーションの違うバージョンを実行できる。
- Can run with threaded Apache
アプリケーションはApacheの内部で実行されないので、スレッドセーフかどうかを気にせずに、より高速なmpm_workerを使用できる。
Setup
1. Install Apache with mod_fastcgi
mod_fastcgiはサードパーティのモジュールでhttp://www.fastcgi.com/にある。多くのディストリビューションではパケージがあるだろう。Debianではlibapache2-mod-fastcgiだ。
2. Configure your application
# Serve static content directly DocumentRoot /var/www/MyApp/root Alias /static /var/www/MyApp/root/static FastCgiServer /var/www/MyApp/script/myapp_fastcgi.pl -processes 3 Alias /myapp/ /var/www/MyApp/script/myapp_fastcgi.pl/ # Or, run at the root Alias / /var/www/MyApp/script/myapp_fastcgi.pl/
この設定は3つのアプリケーションプロセスを起動し、/myapp/でアプリケーションにアクセスする。
Standalone server mode
さきほどの例ほど簡単ではないが、アプリケーションをexternal serverで実行するともっと柔軟になる。
最初に、アプリケーションをソケットをリッスンするスタンドアローンのサーバーとして起動する。
script/myapp_fastcgi.pl -l /tmp/myapp.socket -n 5 -p /tmp/myapp.pid -d
または、Webサーバーを同じマシンで実行していない場合はTCPポートをリッスンすることもできる。
script/myapp_fastcgi.pl -l :8080 -n 5 -p /tmp/myapp.pid -d
pidファイルを使って起動/停止を行うinitスクリプトを書いたほうがいいかもしれない。
で、Apacheを実行中のサーバーに接続する設定をする。
# 502 is a Bad Gateway error, and will occur if the backend server is down # This allows us to display a friendly static page that says "down for # maintenance" Alias /_errors /var/www/MyApp/root/error-pages ErrorDocument 502 /_errors/502.html FastCgiExternalServer /tmp/myapp.fcgi -socket /tmp/myapp.socket Alias /myapp/ /tmp/myapp.fcgi/ # Or, run at the root Alias / /tmp/myapp.fcgi/
Development server deployment
開発用のサーバーはPerlで書かれたミニWebサーバーです。もしアクセス数が少なくmod_perlやFastCGIを必要としないなら、開発用のサーバーをフロントの軽量なプロキシWebサーバーと一緒にアプリケーションサーバーとして使用できます。でも、特にInternet Explorerで既知の問題があるので注意すること。多くの問題はサーバーを-k(keepalive)オプションで実行した場合に発生するが、より複雑なアプリケーションには当てはまらないので注意すること。Catalyst::Engine::HTTP::POEを使うことを検討すること。このレシピはPOEにも適用できる。
Setup
- Start up the development server
script/myapp_server.pl -p 8080 -k -f -pidfile=/tmp/myapp.pid -daemon
initスクリプトを書いた方がいいでしょう。
- Configuring Apache
mod_proxyを有効にして以下を追加する。
# Serve static content directly DocumentRoot /var/www/MyApp/root Alias /static /var/www/MyApp/root/static ProxyRequests Off <Proxy *> Order deny,allow Allow from all </Proxy> ProxyPass / http://localhost:8080/ ProxyPassReverse / http://localhost:8080/
同じホストで異なるアプリケーションを実行したい場合はこの設定をVitualHostで行えばいい。
Quick deployment: Building PAR Packages
開発環境で動くアプリケーションはあるが、デモ/デプロイ/テストなどのためにそれと同じものを素早く作りたい場合。
PARパッケージで多くのトラブルを回避できる。これはblibツリーを含んだZipファイルだ。フラグを指定してprereqとperlインタープリタを含めることもできる。
Follow these few points to try it out!
1. CatalystとPARの0.89以降をインストールする。
% perl -MCPAN -e 'install Catalyst' ... % perl -MCPAN -e 'install PAR' ...
2. アプリケーションを作る
% catalyst.pl MyApp ... % cd MyApp
Catalystの5.62以降はModule::Install::Catalystを含んでいるので、プロセスを大幅に簡単にできる。アプリケーションディレクトリで
% perl Makefile.PL % make catalyst_par
これでmyapp.parが出来上がる。あとのステップはオプション。
3. "par"(typoじゃないよ)でPARパッケージをテストする。
% parl myapp.par Usage: [parl] myapp[.par] [script] [arguments] Examples: parl myapp.par myapp_server.pl -r myapp myapp_cgi.pl Available scripts: myapp_cgi.pl myapp_create.pl myapp_fastcgi.pl myapp_server.pl myapp_test.pl % parl myapp.par myapp_server.pl You can connect to your server at http://localhost:3000
4. Perlインタープリタを含んだバイナリを作成するには?
% pp -o myapp myapp.par % ./myapp myapp_server.pl You can connect to your server at http://localhost:3000
Serving static content
Catalystで静的コンテンツを扱うのは少しトリッキーだ。Catalyst::Plugin::Static::Simpleはすべてを簡単にしてくれる。このプラグインは開発中に静的コンテンツを自動的に扱い、製品環境では簡単にApacheなどに切り替えることができる。
Introduction to Static::Simple
Static::Simpleはアプリケーションで静的コンテンツを扱うためのプラグインだ。デフォルトで、rootディレクトリの外のTemplate Toolkitの拡張子を除いたほとんどのタイプのファイルを扱える。すべてのファイルはパスで受け付けるので、images/me.jpgがリクエストされるとroot/images/me.jpgが返される。
Configuring
静的コンテンツはrootディレクトリ内のディレクトリの1つから供給される。root/cssやroot/imagesなどを使用していると追加設定が必要となり、root/jsなどのディレクトリを追加することになったときにめんどくさいので、root/staticにサブディレクトリを作ってこうするのがいい。
root/ root/content.tt root/controller/stuff.tt root/header.tt root/static/ root/static/css/main.css root/static/images/logo.jpg root/static/js/code.js
静的ファイルはroot/staticに配置し、それ以外にTemplate Toolkitのファイルを置く。
- Include Path
デフォルトのロケーションを変更する場合にはStatic::Simpleがそこを見れるように設定する。
MyApp->config->{static}->{include_path} = [ MyApp->config->{root}, '/path/to/my/files' ];
include_pathを上書きすると通常のrootパスは自動的に追加されないので自分で追加する必要がある。サーチパスは並んだ順番になり、最初に見つかったファイルが使われる。
- Static directories
ディレクトリをstatic専用にする場合は相対パスか正規表現を使ってこうする。
MyApp->config->{static}->{dirs} = [ 'static', qr/^(images|css)/, ];
- File extensions
デフォルトでは以下の拡張子は供給されない(これらはCatalystが処理する)。このリストは簡単に置き換え可能である。
MyApp->config->{static}->{ignore_extensions} = [ qw/tmpl tt tt2 html xhtml/ ];
- Ignoring directories
ディレクトリを無視するようにできる。include_pathを使ってる場合、include_pathへの相対ディレクトリが無視される。
MyApp->config->{static}->{ignore_dirs} = [ qw/tmpl css/ ];
More information
Serving manually with the Static plugin with HTTP::Daemon (myapp_server.pl)
Catalyst::Plugin::Staticを使ってもっと直接的に制御したい場合。
メインのアプリケーションクラス(MyApp.pm)でプラグインをロードする。
use Catalyst qw/-Debug FormValidator Static OtherPlugin/;
endメソッドで静的コンテンツをビューにフォワードしないようにする必要がある場合。
sub end : Private { my ( $self, $c ) = @_; $c->forward( 'MyApp::View::TT' ) unless ( $c->res->body || !$c->stash->{template} ); }
このコードはテンプレートがコントローラによってセットされている場合と、$c->res->{body}にデータがない場合にのみ、ビューにフォワードする。
次に、/staticパスのリクエストをハンドルするコントローラを作成する。ヘルパーを使ってlib/MyApp/Controller/Static.pmを作成する。
$ script/myapp_create.pl controller Static
ファイルを編集して次のコードを追加する。
# serve all files under /static as static files sub default : Path('/static') { my ( $self, $c ) = @_; # Optional, allow the browser to cache the content $c->res->headers->header( 'Cache-Control' => 'max-age=86400' ); $c->serve_static; # from Catalyst::Plugin::Static } # also handle requests for /favicon.ico sub favicon : Path('/favicon.ico') { my ( $self, $c ) = @_; $c->serve_static; }
以下のコードをHTMLのヘッダに書いてfavicon.ico以外のアイコンを使用することもできる。
<link rel="icon" href="/static/myapp.ico" type="image/x-icon" />
Common problems with the Static plugin
StaticプラグインはMIMEタイプを自動判定するのにshared-mime-infoパッケージを使用している。このパッケージは特にwin32とOS Xでインストールするのが難しいことで有名だ。OS Xの場合はFinkをインストールしてapt-get install shared-mime-infoを使うことができる。
最適な結果を得るために最新バージョン(0.16以上)を使用していることを確認しよう。CSSファイルの取り扱いにエラーが発生したり、text/cssじゃなくてtext/plainになってしまう場合はshared-mime-infoが古いかもしれない。Staticコントローラに以下のコードを追加することもできる。
if ($c->req->path =~ /css$/i) { $c->serve_static( "text/css" ); } else { $c->serve_static; }
Serving Static Files with Apache
Apacheを使ってるならroot/staticへのリクエストをサーバーレベルで処理してCatalystとStaticプラグイン、コントローラをバイパスできる。必要なのはDocumentRootを定義して静的コンテンツのために別々のLocationブロックを使用することだ。これはmod_perl 1.xでの完全な例。
<Perl> use lib qw(/var/www/MyApp/lib); </Perl> PerlModule MyApp <VirtualHost *> ServerName myapp.example.com DocumentRoot /var/www/MyApp/root <Location /> SetHandler perl-script PerlHandler MyApp </Location> <LocationMatch "/(static|favicon.ico)"> SetHandler default-handler </LocationMatch> </VirtualHost>
簡単な例はこちら。
Alias /static/ "/my/static/files/" <Location "/static"> SetHandler none </Location>
(ていうか、さっきデプロイのところでこの話でてきた気がするな・・・)
Caching
Catalystはアプリケーションの高速かのためにいろんな種類のキャッシングを簡単に使用できる。
Cache Plugins
CPANのキャッシュモジュール(Cache::FastMmap, Cache::FileCache, Cache::Memcached)をラップする3つのプラグインがある。遅い処理の結果をキャッシュするのに使用できる。
CPANのページはPODドキュメントのXHTMLバージョンをキャッシュするのにFileCacheを使用できる。これは元のドキュメントはあまり更新されないが参照は多いからため、キャッシュを使用するのに典型的な例となる。
use Catalyst qw/Cache::FileCache/; ... use File::stat; sub render_pod : Local { my ( self, $c ) = @_; # the cache is keyed on the filename and the modification time # to check for updates to the file. my $file = $c->path_to( 'root', '2005', '11.pod' ); my $mtime = ( stat $file )->mtime; my $cached_pod = $c->cache->get("$file $mtime"); if ( !$cached_pod ) { $cached_pod = do_slow_pod_rendering(); # cache the result for 12 hours $c->cache->set( "$file $mtime", $cached_pod, '12h' ); } $c->stash->{pod} = $cached_pod; }
永久にキャッシュすることもできるけど、必要なくなったときに自動的に破棄されるようにしている。
Page Caching
キャッシングのもう1つの方法はHTMLページ全体をキャッシュすることだ。これはSquidのようなフロントエンドのプロキシサーバーが昔からやってることであり、CatalystのPageCacheプラグインを使って頻繁に参照される遅いページ全体を簡単にキャッシュできる。
多くのサイトでこのようなコンテンツがいっぱい詰め込まれたページをもってるだろう。これは処理に時間がかかり、すべてのユーザーに対して同じことをやっている。
sub front_page : Path('/') { my ( $self, $c ) = @_; $c->forward( 'get_news_articles' ); $c->forward( 'build_lots_of_boxes' ); $c->forward( 'more_slow_stuff' ); $c->stash->{template} = 'index.tt'; }
速度を改善するためにPageCacheを追加する。
use Catalyst qw/Cache::FileCache PageCache/; sub front_page : Path ('/') { my ( $self, $c ) = @_; $c->cache_page( 300 ); # same processing as above }
これでフロントページ全体が5分間キャッシュされ、5分経ったらページを新しく作ってまたキャッシュする。
ページキャッシュはページのURIとすべてのパラメータをキーにするので、/へのリクエストと/?foo=barは別々のキャッシュになる。また、プラグインではGETリクエストのみがキャッシュされる。
キャッシュされたページのHTTPヘッダに追加することでフロントエンドのSquidを使うこともできる。
MyApp->config->{page_cache}->{set_http_headers} = 1;
これで次のヘッダがセットされ、プロキシとブラウザはコンテンツを自分自身でキャッシュする。
Cache-Control: max-age=($expire_time - time) Expires: $expire_time Last-Modified: $cache_created_time
Template Caching
Template Toolkitはコンパイルされたテンプレートをキャッシュすることができる。Catalystでこれを有効にするには次の設定を行う。TTはファイルの更新時間をキーにしてコンパイルされたテンプレートをキャッシュするので、変更は自動的に検出される。
package MyApp::View::TT; use strict; use warnings; use base 'Catalyst::View::TT'; __PACKAGE__->config( COMPILE_DIR => '/tmp/template_cache', ); 1;
More Info
キャッシュプラグインの詳細と設定オプションについてはそれぞれのドキュメントを参照のこと。
Catalyst::Plugin::Cache::FastMmap - DEPRECATED FastMmap cache - metacpan.org
Catalyst::Plugin::Cache::FileCache - (DEPRECATED) File cache - metacpan.org
Catalyst::Plugin::Cache::Memcached - Distributed cache - metacpan.org
Catalyst::Plugin::PageCache - Cache the output of entire pages - metacpan.org
Template::Manual::Config - Configuration options - metacpan.org