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 件のコメント:
コメントを投稿