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 ポートを許可、ロギング設定など。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | # 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 で実行される。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | #!/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 として配備。
1 2 3 4 5 6 7 8 9 | /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 のファイアウォール設定もこのスクリプトに含めているが、分離させた方がいいかもしれない。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 | # -*- 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_SHOGI_SERVER = \ 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 件のコメント:
コメントを投稿