どうも、cloudpack の 夜の Player かっぱ(@inokara)です。
昨晩「Play2 アプリケーションをデプロイを fabric でやろうと思ったのでメモ」の続きです。リモートホストへのデプロイをやりたいと思います。
以下、手抜きの全文掲載。
from fabric.api import local, run, env, cd, execute, put, sudo
def default_path():
env.app = "app_name"
env.app_repo = "https://github.com/user/app_name.git"
env.snap_shot = "%(app)s-1.0-SNAPSHOT" % { 'app':env.app }
env.base_dir = "/path/to/prod"
env.deploy_dir = "/path/to/deploy"
env.current_path = "%(base_dir)s/current" % { 'base_dir':env.base_dir }
env.releases_path = "%(base_dir)s/releases" % { 'base_dir':env.base_dir }
def set_path():
execute(default_path)
env.releases = sorted(run('ls -x %(releases_path)s' % { 'releases_path':env.releases_path }).split())
if len(env.releases) >= 1:
env.current_revision = env.releases[-1]
env.current_release = "%(releases_path)s/%(current_revision)s" % { 'releases_path':env.releases_path, 'current_revision':env.current_revision }
if len(env.releases) > 1:
env.previous_revision = env.releases[-2]
env.previous_release = "%(releases_path)s/%(previous_revision)s" % { 'releases_path':env.releases_path, 'previous_revision':env.previous_revision }
def setup():
execute(default_path)
run('mkdir -p %(base_dir)s/releases' % { 'base_dir':env.base_dir} )
run('mkdir -p %(deploy_dir)s' % { 'deploy_dir':env.deploy_dir })
def dist_package():
execute(set_path)
with cd('%(deploy_dir)s/' % { 'deploy_dir':env.deploy_dir }):
run('if [ -d %(app)s ]; then rm -rf %(app)s ; fi' % { 'app':env.app })
run('git clone %(app_repo)s' % { 'app_repo': env.app_repo })
with cd('%(deploy_dir)s/%(app)s' % { 'deploy_dir':env.deploy_dir, 'app':env.app }):
run('play dist')
def deploy():
execute(set_path)
execute(dist_package)
from time import time
env.current_release = "%(releases_path)s/%(time).0f" % { 'releases_path':env.releases_path, 'time':time() }
run('cp %(deploy_dir)s/%(app)s/target/universal/%(snap_shot)s.zip %(base_dir)s/' % { 'deploy_dir':env.deploy_dir, 'app':env.app, 'base_dir':env.base_dir, 'snap_shot':env.snap_shot })
with cd ("%(base_dir)s/" % { 'base_dir':env.base_dir }):
run('unzip %(snap_shot)s.zip -d %(current_release)s/' % { 'current_release':env.current_release, 'snap_shot':env.snap_shot })
run('ln -nfs %(current_release)s %(current_path)s' % { 'current_release':env.current_release , 'current_path':env.current_path })
def app_status():
execute(set_path)
sudo('supervisorctl status %(app)s' % { 'app':env.app }, pty=True, shell=False)
def app_start():
execute(set_path)
with cd('%(current_path)s/%(snap_shot)s/' % { 'current_path':env.current_path, 'snap_shot':env.snap_shot }):
run('if [ -f RUNNING_PID ]; then rm RUNNING_PID ; fi')
sudo('supervisorctl start %(app)s' % { 'app':env.app }, pty=True, shell=False)
def app_stop():
execute(set_path)
sudo('supervisorctl stop %(app)s' % { 'app':env.app }, pty=True, shell=False)
def default_path() だけ弄れば良いようになっています。
図を書きながら気付いたのは play dist までの処理はデプロイ用のホストで実行、生成された zip ファイルを put するという流れでも良かったのかなってこと…。まあ、いいや。
def default_path() だけ弄れば良いようになっています(デプロイ先のパス、git のリポジトリ URL 等)sudo を実行させる場合には pty=True, shell=False を付ける必要があるapp_start)、停止(app_stop)、ステータス確認(app_status)は後述の通り supervisord 依存です(すいません)自分の実力では fabric 単体では実現することは出来ませんでした。
当初はバックグラウンドでアプリケーションを起動させる為に以下のように書いていましたがリモートホストでは正常に起動しませんでした。
def app_start():
execute(set_path)
with cd('%(current_path)s/%(snap_shot)s/' % { 'current_path':env.current_path, 'snap_shot':env.snap_shot }):
run('if [ -f RUNNING_PID ]; then rm RUNNING_PID ; fi')
with lcd('%(current_path)s/%(snap_shot)s/bin/' % { 'current_path':env.current_path, 'snap_shot':env.snap_shot }):
run('./hoge &')
Fabric ドキュメントでも以下のように言及されています。
Fabric はリモート側で run や sudo (see also) の呼び出しでそれぞれシェルを起動します。run or sudo (see also)。シェルを通してのバックグランドプロセスは期待通りに動きません。バックグランドプロセスが終了するまで呼び出されたシェルから抜けられないかもしれません。これでは Fabric が順番に実行することができません。
うう、そうなんですな…ってことで、supervisord 等のプロセスマネージャを利用を推奨されているので supervisord を利用してみたいと思います。
sudo pip install supervisor
以前「朝の 3 分ハッキング(1) Supervisor で Sinatra アプリケーションをデーモン閣下する」に supervisor の設定については書いているのでそちらを参考にします。アプリケーションの起動設定については以下のように設定します。
[program:play-test-app] command = /path/to/current/play-test-app-1.0-SNAPSHOT/bin/play-test-app process_name = play-test-app user = app-user autostart = true autorestart = true
設定したら /etc/init.d/supervisord start を実行して supervisord を起動しておきましょう。
アプリケーション用のユーザーが supervisorctl を実行する必要があるので /etc/sudoers.d/ の下に以下のように設定したファイルを置きます。
app-user ALL=(ALL) NOPASSWD:/usr/bin/supervisorctl
とりあえず静止画で…。
fab -H ${APP_HOST} -u ${APP_USER} -f remote_deploy.py deploy
play dist が終わったら zip を展開して最新のリリースディレクトリを current ディレクトリとして設定(シンボリックリンクを設定)。
fab -H ${APP_HOST} -u ${APP_USER} -f remote_deploy.py app_start
fab -H ${APP_HOST} -u ${APP_USER} -f remote_deploy.py app_status
fab -H ${APP_HOST} -u ${APP_USER} -f remote_deploy.py app_stop
fabric を利用して play2 のアプリケーションをリモートホストへのデプロイをひと通り試してみました。基本的にはコマンドの羅列なので悩むことはなかったのですが、アプリケーションの起動に関してはバックグラウンドで起動させるのが fabric 単体ではちょっと実現出来なかった(実現方法を見つけることが出来なかった)のがちょい残念でしたが、実際の運用を想定するとアプリケーションのプロセス管理を何らかの方法で必要となるので、supervisord を fabric から利用するのも悪くはないのかなって考えています。
ということで、おやすみなさい。
元記事はこちらです。
「Play2 アプリケーションをデプロイを fabric でやろうと思ったのでメモ(2)」