Provisioned IOPS とか言われるとベンチはしてみたいので

毎度々々の備忘ですが、ベンチ厨になるべくベンチを取りたいと思いました。IOPS を Provisioned とか言われたらベンチしたくなるのは人情です。なので、m2.4xlarge な EC2 インスタンスを EBS optimized で立ちあげて、更に block device mapping で EBS for PIOPS な volume を 2000 IOPS provision して、fio を make してベンチ取るというスクリプトを試しに作ってみました。

#! /bin/bash
export AWS_ACCESS_KEY=$1
export AWS_SECRET_KEY=$2

script="#!/bin/sh

yum -y install git gcc make libaio-devel xfsprogs
cd /tmp
git clone git://git.kernel.dk/fio.git
cd fio
make
make install

while true
do
  if [ -e /dev/sdf1 ]
  then
    mkfs.xfs /dev/sdf1 > /dev/console
    break
  fi
  sleep 10
done
mkdir -p /media/p_iops_vol0
mount -t xfs /dev/sdf1 /media/p_iops_vol0 2> /dev/console
mount > /dev/console

while true
do
  echo '[write start]' > /dev/console
  /usr/local/bin/fio --directory=/media/p_iops_vol0 --name fio_test_file --direct=1 --rw=randwrite --bs=16k --size=1G --numjobs=16 --time_based --runtime=180 --output /dev/console
  echo '[write done]' > /dev/console
  echo '[read start]' > /dev/console
  /usr/local/bin/fio --directory=/media/p_iops_vol0 --name fio_test_file --direct=1 --rw=randread --bs=16k --size=1G --numjobs=16 --time_based --runtime=180 --group_reporting --output /dev/console
  echo '[read done]' > /dev/console
done 
"
encoded_script=`echo "$script" | base64 -w 0`

result=`ec2-run-instances --region ap-northeast-1 \
  ami-4e6cd34f \
  -z ap-northeast-1c \
  --ebs-optimized True \
  -b /dev/sdf1=:200:true:io1:2000 \
  -t m2.4xlarge \
  --instance-initiated-shutdown-behavior terminate \
  --ebs-optimized True \
  -d $encoded_script`
instance_id=`echo "$result" | grep INSTANCE | awk '{print $2}'`

if [ x"$instance_id" = "x" ]
then
  exit 1
fi

echo "$instance_id"

while true
do
  vol_id=`ec2-describe-instances --region ap-northeast-1 $instance_id | grep /dev/sdf1 | awk '{print $3}'`
  if [ x"$vol_id" != "x" ]
  then
    break
  fi
done

while true
do
  clear
  echo $instance_id - $vol_id
  now_in_sec=`date +%s`
  one_min_ago_in_sec=`expr $now_in_sec - 300`
  one_min_ago=`date -d @$one_min_ago_in_sec +'%Y-%m-%dT%H:%M:%S.000Z'`
  mon-get-stats --region ap-northeast-1 \
    --namespace AWS/EBS \
    --statistics Average \
    --dimensions VolumeId=$vol_id \
    --metric-name VolumeWriteOps \
    -I $AWS_ACCESS_KEY \
    -S $AWS_SECRET_KEY \
    --start-time "$one_min_ago"
  sleep 60
done

何してるかっつーと fio で 3 分毎に write と read を繰り返しています。引数に各種 key を取る辺りがダサいんですが、まだ IAM role に mon-get-stats が対応してなくて。スクリプトの最後で mon-get-stats で metric を定期的に取ってますが、これが要らなけりゃ IAM role に任せて各種 key を設定する必要は無いんすよね。

で、多分これそうなんだけど

EBS volume ってこなれるの待たなきゃなんだな、dd しとくとか大切だな、と思いました。

SNI がまだそこまでポピュラーではないのでサーバ証明書を扱うには 1 枚に 1 つの IP address が要るのでお困りのそこのあなた!!

古い話になりますが、AWS では VPC 内の EC2 インスタンスのインターフェースに複数の IP address を割り当てることができるようになりました

http://aws.typepad.com/aws_japan/2012/07/multiple-ip-addresses-for-ec2-instances-in-a-virtual-private-cloud.html

まじでー。試そう、試しましょう。

http://docs.amazonwebservices.com/AWSEC2/latest/UserGuide/instance-types.html#AvailableIpPerENI

ドキュメントが追い付いてないみたいですが、VPC 内でも t1.micro が使えるようになり secondary IP address が 1 つ割り当てられるようです。

IP address を複数割り当てるぜ

インスタンスタイプによって ENI に付与できる Private IP address の数は異なりますが、割り当て自体は AWS Management Console から簡単にできます。Amazon Linux でいってみました。東京リージョンの ami-4e6cd34f を使ってみます。eth0 に auto-assign で 2 つ IP address を割り当ててみました。そして login。

       __|  __|_  )
       _|  (     /   Amazon Linux AMI
      ___|\___|___|

https://aws.amazon.com/amazon-linux-ami/2012.09-release-notes/
[ec2-user@ip-10-0-2-67 ~]$

こんにちは、Amazon Linux! eth0 の 1 つ目の IP address は 10.0.2.67 になったようです。ifconfig とかしてみましょう。

[ec2-user@ip-10-0-2-67 ~]$ ifconfig -a
eth0      Link encap:Ethernet  HWaddr 02:4B:68:4E:C2:77
          inet addr:10.0.2.67  Bcast:10.0.2.255  Mask:255.255.255.0
(snip)

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
(snip)

eth0 があって 1 つしか IP address が割り当てられていません。でもね、

[ec2-user@ip-10-0-2-67 ~]$ ip addr list
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 02:4b:68:4e:c2:77 brd ff:ff:ff:ff:ff:ff
    inet 10.0.2.67/24 brd 10.0.2.255 scope global eth0
    inet 10.0.2.52/24 brd 10.0.2.255 scope global secondary eth0
    inet6 fe80::4b:68ff:fe4e:c277/64 scope link
       valid_lft forever preferred_lft forever

/sbin/ip で見ると割り当てられているんです。実際には /etc/sysconfig/network-scripts/ec2net-functions の中で /sbin/ip が呼ばれているみたいですが、良く分からない。どっから値を取ってきてるかっつーと、そらもちろん meta-data から取っています。

[ec2-user@ip-10-0-2-67 iproute]$ curl http://169.254.169.254/latest/meta-data/network/interfaces/macs/02:4b:68:4e:c2:77/local-ipv4s
10.0.2.67
10.0.2.52

/sbin/ip は AF_NETLINK な domain の socket を経由して device をごにょごにょするらしい。合ってるかな。もぉ ifconfig は古いらしいぜ! とにかく、ping を打つと

[ec2-user@ip-10-0-2-67 iproute]$ ping -c 3 10.0.2.52
PING 10.0.2.52 (10.0.2.52) 56(84) bytes of data.
64 bytes from 10.0.2.52: icmp_seq=1 ttl=64 time=0.027 ms
64 bytes from 10.0.2.52: icmp_seq=2 ttl=64 time=0.028 ms
64 bytes from 10.0.2.52: icmp_seq=3 ttl=64 time=0.022 ms

--- 10.0.2.52 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 1998ms
rtt min/avg/max/mdev = 0.022/0.025/0.028/0.006 ms

通ります。Amazon Linux でない AMI 使う場合でも、/sbin/ip 使ってもいいですし、良くある eth0:1 みたいなエイリアス使っても動かないことはないっつー感じです。

更に、この 2 つの Private IP address にそれぞれ EIP を紐づけておきましょう。

ApacheSSL するぜ

mod_ssl package をインストールします。

[ec2-user@ip-10-0-2-67 iproute]$ sudo yum install mod_ssl

証明書が欲しいのですがオレオレで十分なので適当に 2 枚作ります。

[ec2-user@ip-10-0-2-67 iproute]$ openssl req -new -x509 -newkey rsa:2048 -keyout 1.key -out 1.pem -nodes
[ec2-user@ip-10-0-2-67 iproute]$ openssl req -new -x509 -newkey rsa:2048 -keyout 2.key -out 2.pem -nodes

/etc/httpd/conf.d/ssl.conf ができてて

<VirtualHost _default_:443>

# General setup for the virtual host, inherited from global configuration
#DocumentRoot "/var/www/html"
#ServerName www.example.com:443

と VirtualHost が用意されているので、これをコピーして

  • の _default_ を Private IP address に
  • ServerName を適当に
  • SSLCertificateFile に上で作った証明書を
  • SSLCertificateKeyFile に上で作った秘密鍵

設定した VirtualHost を 2 つ作ります。そして

[ec2-user@ip-10-0-2-67 iproute]$ /etc/init.d/httpd start

ブラウザで接続して確認しよう

省略。それぞれの IP address に HTTPS で繋ぐともちろん警告が出ますが、証明書を確認すると異なる証明書が提示されてるはずです。

結論

Apache より nginx が好きです。ありがとう id:moriyoshi!