Amazon EC2をコマンドラインで複数起動し、同時に処理させる


DSCN7186.JPG一か月半ぶりの更新になりますね。

最近お仕事でアクセスログの解析をやっていて、Amazon EC2上で解析しようかなーなんて思っているのですが、解析するのにわざわざコンソール開いてインスタンスを自分で立ち上げて・・・なんてやるのは煩わしいしそんなの自動化しろよ!的な話なので、EC2のインスタンスをコマンドラインで複数起動させる方法を探してみました。アクセス解析もするので、ついでに複数起動後、各インスタンスにSSH接続、同時にインスタンスにコマンドを発行してみたいと思います。

のっけから申し訳ないですけれど、これからの話はAWS EC2-API-TOOLSがサーバにインストールされていることが前提です。このEC2-API-TOOLSのインストール方法については後日記事にしたいと思います。

Creative Commons License photo credit: Osamu Iwasaki

複数起動させるコマンドは EC2-API-TOOLS の以下のコマンドでOK。

1
2
3
4
5
6
[root@hogehoge ~]# export EC2_PRIVATE_KEY=/root/hogehoge/pk-******.pem # キーを読み込む
[root@hogehoge ~]# export EC2_CERT=/root/hogehoge/cert-******.pem
[root@hogehoge ~]# ec2-run-instances -n 4 ami-12345678  # コマンド実行
RESERVATION r-xxxxxxxx      xxxxxxxxx  default
INSTANCE    i-xxxxxxxx      ami-12345678  pending
...

とまあこんな感じで起動ができるのですが、起動しただけで、まだEC2上の状態がpending、ようは「起動しています…」ってわけです。今回はインスタンスを同時に立ち上げた後、そのインスタンスにSSH接続をしなければいけないため、EC2上の状態がrunning、つまりは「起動中」になるまで待たなければいけません。

やりたいことのフローとすれば、以下の通り。

  1. インスタンスを同時起動、起動後のインスタンス名(i-xxxxxxxx)を記憶しておく
  2. 起動後のインスタンス名を使って ec2-describe-instances コマンドで、インスタンスの状態をチェック
  3. runningになるまで ec2-describe-instances
  4. runningになったらSSH

起動後のインスタンス名は上記、ec2-run-instances の結果の中に含まれています。コマンドライン(シェルスクリプト)で i-xxxxxxxx が抜き出せればいいわけです。その辺はシェルスクリプトの配列で問題解決。

1
2
3
4
ARY_TEST=("aaa bbb ccc ddd")
echo ${ARY_TEST[0]}
echo ${ARY_TEST[1]}
echo ${#ARY_TEST[*]}  # 配列の数を表示

上記のような値の代入方法でシェルが自動的に配列にしてくれます。そう考えると、ec2-run-instances の結果もスペースで区切られた値なので、これと同じことをやればひとつひとつの要素を配列に入れることが可能です。

半ば強引ですけど・・・。

ということでこんなスクリプトを作ってみました。

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
[root@hogehoge ~]# vi ./test.sh
#!/bin/bash

AMI_RUN=4  # インスタンス起動数
AMI_RESULT=""
AMI_INSTANCES=""
AMI_DNSNAME=""

# キーを読み込む
export EC2_PRIVATE_KEY=/root/hogehoge/pk-******.pem
export EC2_CERT=/root/hogehoge/cert-******.pem

# インスタンス起動
AMI_RESULT=(`ec2-run-instances -n $AMI_RUN ami-xxxxxxxx`)

# インスタンス名を取得
cnt=0 # インスタンス名番号
i=0
while [ $i -ne ${#AMI_RESULT[*]} ] ;
do
  if [ "#{AMI_RESULT[$i]}" = "INSTANCE" ] ; then
    AMI_INSTANCES[$cnt] = ${AMI_RESULT[$(( i + 1 ))]}
    cnt=$(( cnt + 1 ))
  fi
  i=$(( i + 1 ))
done

# インスタンス状態チェック
i=0
while :  # 無限ループ
do
  cnt=0 # DNS番号つまり起動した数
  j=0
  while [ $j -ne ${#AMI_INSTANCES[*]} ] ;
  do
    echo -n "${AMI_INSTANCE[$j]} check..."
    if [ "$AMI_DNSNAME[$j]" = "" ] ; then
      AMI_RESULT=(`ec2-describe-instances ${AMI_INSTANCES[$j]}`) # 状態を取得->配列へ
      if [ "${AMI_RESULT[9]}" = "running" ] ; then
      AMI_DNSNAME[$j]=$AMI_RESULT[7]
      echo "yes."
      cnt=$(( cnt + 1 ))
    else
      echo "no."
    fi
    else
      echo "skipping."
    fi
    j=$(( j + 1 ))
  done
  # すべて起動した?
  if [ $cnt -eq $AMI_RUN ] ; then
    echo "All instances is started."
    break 1  # 終了
  fi
  # 終わっていなければ10秒待ってもう一回チェック
  echo "please wait 10 seconds..."
  sleep 10
done

これでインスタンス起動から、DNS取得までができます。

あとはDNSリストを作って pssh とかの複数同時接続ツールを使えばOKなのですが、まだ試せてないので今日はここまで。すみませんがまた後日にします。