nginxとpythonとpyramid fabricでデプロイ
サムライファクトリーの平成コンビがお送りするWebサービスダイナシ
画像にコメントをつけて、ぜひ楽しんでください。
前回はnginxとuwsgiを連携してアプリを動作する方法を紹介しました。

前回までのエントリー
Pyramidのインストールまで
サーバーの起動まで
MySQLの設定
Nginxとuwsgi


ホームディレクトリ以下に保存されたアプリをそのままuwsgiで動かしていましたが、このままだと不便なことが多々あります。
・複数人で開発した場合
・本番環境と開発環境が違う場合
以上の問題をfabricで解決してみたいと思います。

fabricはpythonで記述できるデプロイツールです。
ssh経由でのコマンド実行やrsyncでのファイル同期など簡単な記述で実現できます。

今回は以下の構成を前提とします。
■開発環境
ホスト名:dev
ユーザー:yoshi
■本番環境
ホスト名:pro
ユーザー:web
yoshi@devからweb@proへsshでログインできること。

今回もFabricをsetup.pyに追記します。

requires = [
'pyramid',
'SQLAlchemy',
'transaction',
'pyramid_tm',
'pyramid_debugtoolbar',
'zope.sqlalchemy',
'waitress',
'mysql-python',
'uwsgi',
'Fabric', <-- 追記
]


「python setup.py develop」を実行すればFabricがインストールされます。
好みによりますがfabricはデプロイツールなので直接pipでインストールでも良いかもしれません。

インストールが成功すると「fab」コマンドが実行できるようになります。
fabコマンドはカレントディレクトリにあるfabfile.pyを実行してくれます。

fabricに変更するために各種設定ファイルを変更します。
※dev側で作業

vi production.ini
-----------------
[uwsgi]
virtualenv = /var/www/test.hoge.com/env
-----------------


fabfile.pyを用意します。

vi fabfile.py
-----------------
import os
from fabric.api import env, local, run, sudo
from fabric.contrib import project

env.user = 'web'
env.key_filename = os.environ['HOME'] + '/.ssh/id_rsa'
env.ignore = ['*.pyc', '.gitignore', '.git', 'sample.egg-info', 'env', 'dist']
env.sleep = 3

def production():
env.hosts = [
'pro',
]
env.app_path = '/var/www/test.hoge.com'

def rsync():
project.rsync_project(env.app_path, '../sample/', exclude=env.ignore, delete=True)

def start():
sudo('/etc/rc.d/init.d/test start')
local('sleep %(sleep)d' % env)
sudo('/etc/rc.d/init.d/nginx start')

def stop():
sudo('/etc/rc.d/init.d/nginx stop')
sudo('/etc/rc.d/init.d/test stop')

def deploy():
stop()
rsync()
start()
-----------------


pro側にデプロイ用ディレクトリを用意しておきます。

mkdir -p /var/www/test.hoge.com


「fab production rsync」を実行するとproにアプリがインストールされます。
fabの後にpythonの関数を並べた順番に処理が実行されます。

env変数はfabricで利用される環境変数になります。「env.user」「env.key_filename」「env.hosts」は予め決められた変数でそれぞれ「接続先のユーザー名」「ローカルの秘密鍵ファイルパス」「実行するホストリスト」を設定してます。
「env.hosts」に複数のホストを設定するとrsync関数が各ホストに対して実行されます。

「project.rsync_project」はrsyncを実行します。
第1引数にデプロイ先のディレクトリ、第2引数にローカルのディレクトリを指定します。「../sample/」と相対パスで指定しているのは実際デプロイされるディレクトリとローカルのプロジェクトのディレクトリが異なる場合に必要となります。「/」で終了しているのも意味があります。
あとは、excludeで同期しないファイルリスト、delete=Trueでローカルに存在しないファイルはproから削除するように設定しています。

pro側にもpythonbrewとpythonをインストールして新しい仮想環境を用意してアプリを構築します。

mkvirtualenv pyramid
cd /var/www/test.hoge.com
python setup.py develop
ln -s /home/web/.virtualenvs/pyramid/ env

setup.pyに依存ライブラリを記述しているので簡単に同一環境を用意することが出来ます。

前回用意したnginx、uwsgiの設定ファイルをすべてproにコピーして一部修正します。

sudo vi /etc/sysconfig/test
-----------------
UWSGI_USER=web
UWSGI=/var/www/test.hoge.com/env/bin/uwsgi
PROFILE=/var/www/test.hoge.com/production.ini
PIDFILE=/var/run/test/uwsgi.pid
LOCKFILE=/var/lock/subsys/test
-----------------

sudo vi /etc/nginx/conf.d/test.hoge.com.conf
-----------------
server {
listen 80;
server_name test.hoge.com;

location / {
uwsgi_pass unix:///var/run/test/uwsgi.sock;
include uwsgi_params;
client_max_body_size 10m;
client_body_buffer_size 128k;
}

location /static {
root /var/www/test.hoge.com/sample;
expires 30d;
add_header Cache-Control public;
access_log off;
}

}
-----------------


dev側から「fab production start」を実行するとuwsgi、nginxの順でサービスが起動されます。
fabricの「local」「run」「sudo」はそれぞれ「ローカルのコマンド実行」「ssh経由でコマンド実行」「ssh経由でsudoでコマンド実行」となっています。
デプロイ以外でも色々と利便性の高いツールです。

途中間が開いてしまいましたが、nginxとpythonとpyramidを利用したアプリ構築について記載してみました。

途中で環境やバージョンが変わってしまったので記載通りに動かない場合がありましたら、コメントやメールフォームでご指摘頂けると助かります。


2012/05/05 19:52 | Comments(0) | プログラム
nginxとpythonとpyramid nginxとuwsgi
サムライファクトリーの平成コンビがお送りするWebサービスダイナシ
画像にコメントをつけて、ぜひ楽しんでください。
今まではwaitress上でWebアプリケーションを動かしていました。
コマンドひとつですぐに利用出来るので開発時には便利ですが、本番環境ではnginxとuwsgiを連携して動かしてみたいと思います。

前回までのエントリー
Pyramidのインストールまで
サーバーの起動まで
MySQLの設定

waitressで動かしていた時はすべてのリクエストをuwsgiで処理していました。
そのためプログラムを必要としないリソースファイル(画像ファイル、スタイルシートなど)も処理対象となります。
特に処理が必要ないのであればnginxがそのままレスポンスを返して、処理が必要な場合だけuwsgiに流します。

イメージ

nginx(80port) -> uwsgi(unix socket)


前回のmysqlと同様にuwsgiをsetup.pyに追記します。

requires = [
'pyramid',
'SQLAlchemy',
'transaction',
'pyramid_tm',
'pyramid_debugtoolbar',
'zope.sqlalchemy',
'waitress',
'mysql-python',
'uwsgi', <-- 追記
]


追記した内容を反映するためにコマンドを実行します。

python setup.py develop

これだけでuwsgiがインストールできます。
正常にインストール出来ない場合はエラーメッセージを参考に依存ライブラリを別途インストールする必要があります。

設定ファイルの簡略化の為にアプリのトップディレクトリにvirtualenvのショートカットを作成しておきます。

ln -s /home/yoshi/apps/sample/env /home/yoshi/.virtualenvs/pyramid


uwsgiの起動パラメーターをproduction.iniに記述します。(変更点のみ抜粋)

[app:main]


# sqlalchemy.url = sqlite:///%(here)s/sample.db
sqlalchemy.url = mysql://user:user_pass@localhost:3306/sample?charset=utf8&use_unicode=1
sqlalchemy.pool_recycle = 3600

[uwsgi]
virtualenv = /home/yoshi/apps/sample/env
socket = /var/run/test/uwsgi.sock
daemonize = /var/log/test/uwsgi.log
master = true
no-orphans = true
uid = www
gid = www
processes = 4
harakiri = 60
harakiri-verbose = true
limit-post = 65536
post-buffering = 8192
listen = 256
max-requests = 1000
log-slow = true
disable-logging = false
log-date = %%Y%%m%%d-%%H%%M%%S

[server:main]セクションを削除して変わりに[uwsgi]セクションを記述します。

pidファイルやlogファイルようにディレクトリを用意します。

sudo mkdir -p /var/run/test
sudo chown yoshi:yoshi /var/run/test
sudo mkdir -p /var/log/test
sudo chown yoshi:yoshi /var/log/test


uwsgiコマンドでWSGIサーバーを起動します。

uwsgi --ini-paste-logged production.ini --pidfile /var/run/test/uwsgi.pid

「ps -ef | grep uwsgi」コマンドで確認すると親プロセスとワーカー4プロセスが動いている事が確認できます。
終了するには親プロセスを指定して「kill -9 [親プロセスID]」を実行します。

サーバー起動時にWSGIサーバーを起動したい場合などを考慮して起動スクリプトを用意します。

sudo vi /etc/rc.d/init.d/test
---------------
#!/bin/sh
#
# test - this script starts and stops the test uwsgi daemon
#
# chkconfig: - 85 15
# processname: test
# config: /etc/sysconfig/test
# pidfile: /var/run/test/uwsgi.pid
# description: test is a WSGI server
#

# Source function library.
. /etc/rc.d/init.d/functions

if [ -f /etc/sysconfig/test ]; then
. /etc/sysconfig/test
fi

prog=uwsgi
uwsgi=${UWSGI-/usr/bin/uwsgi}
profile=${PROFILE-/var/www/test/production.ini}
pidfile=${PIDFILE-/var/run/test/uwsgi.pid}
lockfile=${LOCKFILE-/var/lock/subsys/uwsgi}
RETVAL=0

start() {
echo -n $"Starting $prog: "

su - "$UWSGI_USER" -c "${uwsgi} --ini-paste-logged ${profile} --pidfile ${pidfile}"
RETVAL=$?
echo
[ $RETVAL = 0 ] && touch ${lockfile}
return $RETVAL
}

stop() {
echo -n $"Stopping $prog: "
#killproc -p ${pidfile} ${prog} -INT
su - "$UWSGI_USER" -c "${uwsgi} --stop ${pidfile}"
RETVAL=$?
echo
[ $RETVAL = 0 ] && rm -f ${lockfile} ${pidfile}
}

# See how we were called.
case "$1" in
start)
start
;;
stop)
stop
;;
status)
status -p ${pidfile} ${uwsgi}
RETVAL=$?
;;
restart)
stop
start
;;
*)
echo $"Usage: $prog {start|stop|restart|status}"
RETVAL=2
esac

exit $RETVAL
---------------


環境設定用のファイルを用意して記述します。

sudo vi /etc/sysconfig/test
---------------
# Configuration file for the uwsgi service.
UWSGI_USER=yoshi
UWSGI=/home/yoshi/apps/sample/env/bin/uwsgi
PROFILE=/home/yoshi/apps/sample/production.ini
PIDFILE=/var/run/test/uwsgi.pid
LOCKFILE=/var/lock/subsys/test
---------------


「sudo /etc/rc.d/init.d/test start」「sudo /etc/rc.d/init.d/test stop」で起動・停止が出来るようになります。
以上でWSGIサーバーの用意は終わったので、次にnginxを用意します。

CentOS6のレポジトリーだと1.0.x系なので1.2.x系を利用するためにレポジトリーを追加してインストールします。

sudo vi /etc/yum.repos.d/nginx.repo
---------------
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/rhel/6/$basearch/
gpgcheck=0
enabled=0
---------------

sudo yum install --enablerepo=nginx nginx
sudo /etc/rc.d/init.d/nginx start


ブラウザーからサーバーにアクセスして「Welcome to nginx!」と表示されていればインストール成功です。

サンプルプロジェクトのリクエスト用に仮想ホストをnginxに設定を追加します。(仮想ホストをtest.hoge.comと仮定します)

cd /etc/nginx/conf.d
sudo vi test.hoge.com.conf
---------------
server {
listen 80;
server_name test.hoge.com;

location / {
uwsgi_pass unix:///var/run/test/uwsgi.sock;
include uwsgi_params;
client_max_body_size 10m;
client_body_buffer_size 128k;
}

location /static {
root /home/yoshi/apps/sample/sample;
expires 30d;
add_header Cache-Control public;
access_log off;
}

}
---------------


セキュリテリ上好ましくありませんが「/home/yoshi」のパーミッションを一時的に変更しました。
nginxを再起動すると80ポートでサンプルアプリにアクセス出来ると思います。

waitressに比べると設定が大変ですが受ける恩恵は大きいと思います。
次回はFabricを使ったデプロイについて記載したいと思います。

2012/05/05 16:56 | Comments(0) | プログラム

| HOME | 次のページ>>