AWS: shogi-server を Fabric で構築する
目的
コンピュータ将棋のネット対局用サーバ shogi-server を AWS の EC2 インスタンス上に構築する。
このとき、全ての設定作業を Fabric で完結させたい。
前提
- ローカルマシン(Macを想定)に Python (できれば 2.7以上) をインストール
- ローカルマシンに Fabric をインストール
Fabric — Fabric 1.6.1 documentation - EC2 インスタンスを構築
mog project: Getting Started with Amazon Web Services - ローカルマシンに AWS CLI をインストール、接続設定
mog project: Settings for AWS Command Line Interface - EC2 インスタンスでタイムゾーンを設定
mog project: AWS: EC2 Settings for System Time
準備するもの
iptables
shogi-server (CSAプロトコル) で使う 4081 ポートを許可、ロギング設定など。
# Firewall configuration written by system-config-firewall # Manual customization of this file is not recommended. *filter :INPUT DROP [0:0] :FORWARD DROP [0:0] :OUTPUT ACCEPT [0:0] -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT -A INPUT -p icmp -j ACCEPT -A INPUT -i lo -j ACCEPT -A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT -A INPUT -m state --state NEW -m tcp -p tcp --dport 4081 -j ACCEPT -N LOGGING -A INPUT -j LOGGING -A LOGGING -j LOG --log-level warning --log-prefix "DROP:" -m limit -A LOGGING -j DROP COMMIT
sudoers
sudo の際に環境変数 PATH を引き継ぐようにしないと、なぜか Ruby のインストールに失敗してしまう。
env_keep に PATH を追記した sudoers ファイルをあらかじめ用意しておく。
# diff -u ./sudoers.20130707 ./sudoers --- ./sudoers.20130707 2013-05-10 03:53:29.636195742 +0900 +++ ./sudoers 2013-07-07 11:47:48.647961526 +0900 @@ -76,6 +76,7 @@ Defaults env_keep += "LC_COLLATE LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES" Defaults env_keep += "LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE" Defaults env_keep += "LC_TIME LC_ALL LANGUAGE LINGUAS _XKB_CHARSET XAUTHORITY" +Defaults env_keep += "PATH" # # Adding HOME to env_keep may enable a user to run unrestricted
起動スクリプト
shogi-server をサービスとして登録し、起動/停止を行うためのスクリプト。
/etc/init.d/shogi-server として配備。
PIDファイルを /var/run、ログを /var/log/shogi-server 配下に作成している。
サービスは専用ユーザ shogi で実行される。
#!/bin/bash # # Start/Stop shogi-server daemon # # chkconfig: 2345 85 15 # description: shogi-server daemon mode PROC_NAME=shogi-server PROC_USER=shogi PROC_GROUP=shogi PROC_BIN=/opt/shogi-server/shogi-server PID_FILE=/var/run/shogi-server.pid DAEMON_LOG_DIR=/var/log/shogi-server PLAYER_LOG_DIR=$DAEMON_LOG_DIR/player-logs CONSOLE_LOG=$DAEMON_LOG_DIR/console.log EVENT_NAME=event1 PORT_NUMBER=4081 # Sanity checks [ -x $PROC_BIN ] || exit 1 # Source function library & LSB routines . /etc/rc.d/init.d/functions RETVAL=0 start() { echo -n $"Starting $PROC_NAME: " mkdir -p $DAEMON_LOG_DIR $PLAYER_LOG_DIR touch $PID_FILE chown $PROC_USER:$PROC_GROUP $DAEMON_LOG_DIR $PLAYER_LOG_DIR $PID_FILE su - $PROC_USER -c \ "ruby $PROC_BIN --daemon $DAEMON_LOG_DIR --pid-file $PID_FILE \ --player-log-dir $PLAYER_LOG_DIR $EVENT_NAME $PORT_NUMBER \ > $CONSOLE_LOG 2>&1" RETVAL=$? if [ $RETVAL -eq 0 ]; then success else rm -f $PID_FILE failure fi echo } stop() { echo -n $"Stopping $PROC_NAME:" if [ -f $PID_FILE ]; then killproc -p $PID_FILE $PROC_NAME -TERM rm -f $PID_FILE fi RETVAL=$? [ $RETVAL -eq 0 ] && success || failure echo } case "$1" in start) start RETVAL=$? ;; stop) stop RETVAL=$? ;; status) status -p $PID_FILE $PROC_BIN RETVAL=$? ;; restart) stop start ;; *) echo $"Usage: $0 {start|stop|status|restart}" RETVAL=2 ;; esac exit $RETVAL
logrotate 定義ファイル
ログファイルの洗い替えは logrotate を利用する。
/etc/logrotate.d/shogi-server として配備。
/var/log/shogi-server/shogi-server.log /var/log/shogi-server/player-logs/*.log { weekly rotate 4 missingok notifempty copytruncate compress }
Fabric 用スクリプト
Fabric で使う Python スクリプト。
env.hosts はハードコーディングして使ってもよい。
標準APIの put 関数にも sudo 機能があるものの、SELinux 対応やバックアップ作成などが物足りなかったので
独自の _put という関数でラップしている。
EC2 のファイアウォール設定もこのスクリプトに含めているが、分離させた方がいいかもしれない。
# -*- coding: utf-8 -*- """ Installing shogi-server and its dependencies. """ import os import json from fabric.api import * from fabric.decorators import runs_once, roles, task env.user = 'ec2-user' # env.hosts = [] env.use_ssh_config = True WORK_DIR = os.path.dirname(os.path.abspath(__file__)) APL_USER = 'shogi' APL_GROUP = 'shogi' APL_HOME = '/home/%s' % APL_USER GIT_RBENV = 'git://github.com/sstephenson/rbenv.git' GIT_RUBY_BUILD = 'git://github.com/sstephenson/ruby-build.git' GIT_SHOGI_SERVER = \ 'git://git.sourceforge.jp/gitroot/shogi-server/shogi-server.git' RUBY_VERSION = '1.9.3-p448' EC2_SECURITY_GROUP = 'quick-start-1' @task def setup(): """Setup tasks for shogi-server.""" setup_os_user() setup_firewall() install_ruby() install_shogi_server() @task def setup_os_user(): """Add 'shogi' user and 'shogi' group.""" if sudo('id %s' % APL_USER, quiet=True).succeeded: return # Add user and group. sudo('groupadd -g 501 %s' % APL_GROUP) sudo('useradd -u 501 -g %s %s' % (APL_GROUP, APL_USER)) # Copy sudoers. _put('%s/sudoers' % WORK_DIR, '/etc/sudoers', '440', 'root', 'root') @task def setup_firewall(): """Configure linux and EC2 firewall. AWS CLI and its connection settings are required.""" # Linux iptables _put('%s/iptables' % WORK_DIR, '/etc/sysconfig/iptables', '600', 'root', 'root') sudo('service iptables restart') # EC2 firewall port = 4081 cidr = '0.0.0.0/0' old = local('aws ec2 describe-security-groups', capture=True) j = json.loads(old) found = (EC2_SECURITY_GROUP, port, cidr) in ( (a['GroupName'], b['FromPort'], c['CidrIp']) for a in j['SecurityGroups'] for b in a['IpPermissions'] for c in b['IpRanges']) if not found: opts = '--group-name %s --ip-protocol tcp ' % EC2_SECURITY_GROUP opts += '--from-port %d --to-port %d --cidr-ip %s' % (port, port, cidr) local('aws ec2 authorize-security-group-ingress %s' % opts) @task def install_ruby(): """Install git, rbenv, ruby-build and ruby.""" # Install git. sudo('yum -y install git') # Install rbenv. with cd('/usr/local'): sudo('git clone %s %s' % (GIT_RBENV, 'rbenv')) sudo('mkdir rbenv/shims rbenv/versions') # Install ruby-build. with cd('/usr/local'): sudo('git clone %s %s' % (GIT_RUBY_BUILD, 'ruby-build')) with cd('/usr/local/ruby-build'): sudo('./install.sh') # Create system-level profile. profile = '/etc/profile.d/rbenv.sh' sudo("""echo 'export RBENV_ROOT="/usr/local/rbenv"' > %s""" % profile) sudo("""echo 'export PATH="/usr/local/rbenv/bin:$PATH"' >> %s""" % profile) sudo("""echo 'eval "$(rbenv init -)"' >> %s""" % profile) # Install requirements. sudo('yum -y groupinstall "Development Tools"') sudo('yum -y install openssl-devel readline-devel zlib-devel') # Install ruby. sudo('su - -c "rbenv install 1.9.3-p448"') sudo('su - -c "rbenv global 1.9.3-p448"') sudo('su - -c "rbenv rehash"') @task def install_shogi_server(): """Install and start shogi-server as a service.""" shogi_path = '/opt/shogi-server' if sudo('test -d %s' % shogi_path, quiet=True).succeeded: return # Clone from repository. sudo('git clone %s %s' % (GIT_SHOGI_SERVER, shogi_path)) sudo('chown -R %s:%s %s' % (APL_USER, APL_GROUP, shogi_path)) # Copy init script. _put('%s/shogi-server.init' % WORK_DIR, '/etc/init.d/shogi-server', '755', 'root', 'root') # Add and start service. sudo('chkconfig --add shogi-server') sudo('service shogi-server start') # Copy logrotate setting. _put('%s/shogi-server.logrotate' % WORK_DIR, '/etc/logrotate.d/shogi-server', '644', 'root', 'root') def _put(src, dst, mode, owner, group): tmp = '/tmp/%s.tmp' % src.split('/')[-1] backup_opts = '--backup=simple --suffix=.`date +%Y%m%d`' permission_opts = '-m %s -o %s -g %s' % (mode, owner, group) put(local_path=src, remote_path=tmp) sudo('install %s %s %s %s' % (backup_opts, permission_opts, tmp, dst)) sudo('rm -f %s' % tmp)
実行方法
fab コマンドで実行。Microインスタンスで20分弱で完了。
$ fab -f ./shogi-server.py --list $ fab -f ./shogi-server.py -H 対象サーバ setup
0 件のコメント:
コメントを投稿