• 注1:まだ本番にはデプロイしてませんが、確認テストでは使いました(単位テストでは使わない。あくまで本番さながらの形で動いているのを確認したい時だけ)。
  • 注2:以下スクリプトは開発者の労力を減らすためのスクリプトで、万全なデプロイ方法だとか言うわけではありません。
  • 注3:正直シェルスクリプトは素人です。

  • 追記:envdirはどうか、と言われた件。最初それを思い出せなくてcat ENVなんてしてたんだけど、設定値をもらって後からフックしたいところがあるからenvdirではそれを実現できない・・・気がする。ので、今回は以下で。
  • hirose31 さんが美しい スクリプトを提供してくれたので、それをベースにしてgithubにあげておけました。最新版はここです

ここ最近のPlackだとかStarmanとかを使ったWebアプリケーションのバンドル・デプロイについてちょっと固まりつつあるので、書いてみる

まず アプリケーションと、その依存関係。デプロイ側のサーバーにはlocal::libと必要なModule::Install系のモジュール、それにModule::Install::Bundle::LocalLibがインストールされている前提です。アプリケーションの依存関係は全部Makefile.PLに書きます。

use inc::Module::Install;

name 'MyApp';

..... # 必要な事色々 ....

# Plack stuff
requires 'Plack' => '0.9910'; # or 1.00 when the time comes
requires 'Starman';
requires 'Server::Starter';
requires 'Net::Server::SS::PreFork';

bundle_local_lib;

WriteAll;

こんな風にしておく。で、デプロイする際には
make bundle_local_lib
する。するとextlibというディレクトリに依存関係が全部入ります。このextlibは一旦安定稼働するのを確認したら、依存関係のアップグレード時には一旦別のところに待避させるとかコピーするとかしてからアップグレードを行ってみるという事ができる。万が一動かない場合はすぐ元のextlibに戻せば良いってわけだ。

ってなわけで、Plackを含めた全ての依存関係をextlib以下にある。

で、これをdaemontoolsで動かすのでrunファイルが欲しい。作る。今までdaemontoolsで運用してて開発→デプロイで面倒くさいなーと思ってたのがこのrunファイルの細かい設定を変えていくことなんだけど、今回はこれを分離してみた:
#!/bin/sh

# ENVというファイルが このファイルと同じディレクトリか
# pwdにあれば、それを読み込んで、そこから環境変数を広う。
# 例えば後で出てくる PSGI_FILEの場所を明示的に指定したければ
# PSGI_FILE=/path/to/app.psgi とかENVファイルに書いておく。
if [ -f `dirname $0`/ENV ]; then
    ENV_FILE=`dirname $0`/ENV
    export `cat $ENV_FILE`
elif [ -f ENV ]; then
    export `cat ENV`
fi

if [ -z $APP_HOME ]; then
    APP_HOME=`pwd`;
fi
export APP_HOME
if [ -z $CATALYST_HOME ]; then
    CATALYST_HOME=$APP_HOME
    export CATALYST_HOME
fi

if [ -z $CATALYST_CONFIG ]; then
    if [ -f "catalyst.yaml" ]; then
        CATALYST_CONFIG=catalyst.yaml
        export CATALYST_CONFIG
    fi
fi

if [ ! -z $DEBUG ]; then
    DBIC_TRACE=2
    export DBIC_TRACE
fi

if [ -z $PLACK_SERVER ]; then
    PLACK_SERVER=Starman
fi

if [ -z $PSGI_FILE ]; then
    PSGI_FILE=app.psgi
fi

if [ -z $PORT ]; then
    PORT=5000
fi

if [ -z $USER ]; then
    USER=www
fi

if [ -z $PERL ]; then
    PERL=`which perl`
fi

EXTLIB=$APP_HOME/extlib

# start_serverを通して plackupを実行するのだが、こいつらはextlibの中に
# あるので、それを指定して実行する(local::lib設定もつけないと依存関係が
# みつからない状態になってしまう)
exec setuidgid $USER \
    $PERL -Mlocal::lib=$EXTLIB \
    $EXTLIB/bin/start_server --port $PORT -- \
    $PERL -Mlocal::lib=$EXTLIB \
    $EXTLIB/bin/plackup -s $PLACK_SERVER -a $PSGI_FILE -p $PORT 2>&1

こんな感じ。これでENVの中身を変えてsvc -tするとその設定が反映される、と。

自分の場合はPSGIファイルの中にももう少し仕掛けを入れていく必要があったので、ENVから可変な情報をもらっていくようにした:
use strict;
use lib "$ENV{CATALYST_HOME}/lib"; # パスを通す
use local::lib "$ENV{CATALYST_HOME}/extlib"; # ついでにlocal::libのパスも通す

use MyApp;
use Plack::Builder;

MyApp->setup_engine('PSGI');

builder {
    # リバースプロキシ使う場合はenableしちゃう
    if ($ENV{USE_PROXY}) {
        enable "Plack::Middleware::ReverseProxy";
    }
    return sub { MyApp->run(@_) };
};
これをレポジトリに入れておき、デプロイするときにはdaemontoolsあたりからsymlinkしておいて動かす。開発時にもrunファイルを実行すれば本番さながらの感じでサーバーが立ち上がる(ただし、実際にはテストは全然違う方法で動かしてる)

誰かの役に立つなら幸い。なんか突っ込みがあればお願いします。