Hatak::Techlog

Verba volant, scripta manent.

PSGI アプリを Supervisord + Server::Starter で動作させる

PSGI で動作する Perl の Web アプリをデプロイする環境をどのように作ろうかと思って試してみたので、その手順をまとめてみます。 記事を書きかけて放置してしまっていたので、diff が古かったりするのはご愛敬で。。

構成の概要

今回構築しようと思う構成は次の通りです。

  • PSGI を用いた簡単な Web アプリ
  • アプリを動作させる Perl とそのモジュール群は perlbrew + Carton で管理
    • 複数のシステムを同一サーバで動かす可能性もあるため分離しておきたい
    • Carton 使ってみたい
  • アプリケーションサーバには Server::Starter + Starman を利用
    • Hotdeploy できるようにするため
  • Server::Starter のプロセスは Supervisord で管理

supervisord の導入

スーパーサーバーSupervisorの導入手順メモ – Glide Note – グライドノート を参考に supervisord を導入します。
今回は CentOS 6 系のサーバで system python に pip 経由でインストールします。 pythonbrew などを利用してシステムと切り離すことも検討したのですが、supervisord を使う目的が OS とアプリの間でプロセス管理をすることなので system python で問題ないと考えました。

# setuptools + pip + supervisord のインストール
sudo yum install python-setuptools
sudo easy_install pip
sudo pip install supervisord

# ログ保存用ディレクトリ作成
sudo mkdir /var/log/supervisord/

# 個別設定を格納するディレクトリを作成
sudo mkdir /etc/supervisord.d/

# ベースとなる conf を生成
sudo su - root -c "echo_supervisord_conf > /etc/supervisord.conf"

supervisord.conf も前述の記事とほぼ同じですが、umask を CentOS 風にしたいために 002 にしています。
そして、下記のような /etc/init/supervisord.conf を作成した後に initctl start supervisord で起動します。

description "supervisord"
start on runlevel [2345]
stop on runlevel [!2345]
respawn exec /usr/bin/supervisord -n

supervisord のプロセスが正常に起動していて、ログファイル (/var/log/supervisord/supervisord.log) に正常に出力されていれば OK です。

supervisord 用の設定を用意する

PSGI アプリを supervisord で管理するための設定を用意します。 ここで、環境変数が必要となるのでコマンドラインで調べておきます。

まずは、carton 利用時の perl のサーチパス (@INC) を調べておきます。

$ carton exec -I./lib/ -- perl -e "print join(q/:/,@INC)"
./lib/:local/lib/perl5/x86_64-linux:local/lib/perl5:.:/home/hatak/perl5/perlbrew/perls/perl-5.16.0/lib/5.16.0:/home/hatak/perl5/perlbrew/perls/perl-5.16.0/lib/5.16.0/x86_64-linux

同様に、今度は $PATH を調べておきます。

$ carton exec -I./lib/ -- echo $PATH
/home/hatak/.perlbrew/libs/perl-5.16.0@carton/bin:/home/hatak/perl5/perlbrew/bin:/home/hatak/perl5/perlbrew/perls/perl-5.16.0/bin:/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/home/hatak/bin:/home/hatak/bin

これらの環境変数を使って、/etc/supervisord.d/sample.ini という設定を書いていきます。 $PATH に加えて、@INC の中身を $PERL5LIB として設定し、直接 supervisord が server_start するようにします。 (server_start する部分を別のスクリプトにしてしまうと、supervisord で restart などの処理を行ってもプロセスが切り離されてしまい、管理から外れてしまう状態になってしまいます)

1
2
3
4
5
6
7
8
9
10
11
12
13
[program:hatak]
user=hatak
umask=002
environment=PERL5LIB="/home/hatak/www/sample/lib:/home/hatak/www/sample/local/lib/perl5/x86_64-linux:/home/hatak/www/sample/local/lib/perl5:/home/hatak/.perlbrew/libs/perl-5.16.0@carton/lib/perl5/x86_64-linux:/home/hatak/.perlbrew/libs/perl-5.16.0@carton/lib/perl5",PATH="/home/hatak/www/sample/local/bin/:/home/hatak/.perlbrew/libs/perl-5.16.0@carton/bin:/home/hatak/perl5/perlbrew/bin:/home/hatak/perl5/perlbrew/perls/perl-5.16.0/bin/"
command=/home/hatak/.perlbrew/libs/perl-5.16.0@carton/bin/carton exec -- /home/hatak/www/sample/local/bin/start_server --port=8080 --path=/tmp/sample.sock --interval=10 --pid-file=/tmp/sample.pid -- /home/hatak/www/sample/local/bin/plackup -s Starman -E deployment --workers=3 --backlog=1024 --max-requests=10000 --preload-app /home/hatak/www/sample/app.psgi directory=/home/hatak/www/sample
redirect_stderr=true
stdout_logfile=/var/log/supervisord/sample.log
stdout_logfile_maxbytes=5MB
stderr_logfile=/var/log/supervisord/sample.err
stderr_logfile_maxbytes=5MB
stdout_logfile_backups=5
autorestart=true
startsecs=5

これで準備は完了です。あとは、supervisord で起動すればおしまいです。

sudo supervisorctl add sample

少し回りくどい構成のようにも思えますが、ソースをアップロードして server_start のプロセスに -HUP を送ることで Server::Starter がいい感じにプロセスを置き換えてくれます。また、サーバプロセスがなくなったときやサーバ再起動時などには supervisord がサーバプロセスを立ち上げてくれるので、管理も簡単です。

外部からのリクエストは、一度 Nginx などのリバースプロキシで受けて、動的なものだけを PSGI に送りレスポンスを返す形にすると様々な恩恵が受けられそうです。 ただ、今回試した範囲では Nginx から直接 socket に送ることができなかったのでここは今後の課題でした。