VPC内のEC2に複数のEIP(Global IP)を付与してみます。
もっとも、VPC内のEC2には 直接EIPを付与することが出来ないため、実際にはENIへEIPを付与し、ENIをEC2へアタッチすることになります。



・ENIコマンドを探す

ENI が必要なことは分かっているので、そのコマンドを確認してみます。
$ ls -1 /opt/aws/bin/*network*interface*
/opt/aws/bin/ec2-attach-network-interface
/opt/aws/bin/ec2-create-network-interface
/opt/aws/bin/ec2-delete-network-interface
/opt/aws/bin/ec2-describe-network-interface-attribute
/opt/aws/bin/ec2-describe-network-interfaces
/opt/aws/bin/ec2-detach-network-interface
/opt/aws/bin/ec2-modify-network-interface-attribute
/opt/aws/bin/ec2-reset-network-interface-attribute
作って、アタッチして…という流れは、他のモノと変わらないようです。
しかし、ec2-create-network-interface --help、ec2-modify-network-interface-attribute --help どちらのの説明を見てみても、後から Private IP address を変更する方法が記載されていません。
きっと、専用のコマンドがあるのでしょう…。
$ ls -1 /opt/aws/bin/*private*address*
/opt/aws/bin/ec2-assign-private-ip-addresses
/opt/aws/bin/ec2-unassign-private-ip-addresses
そのままズバリのものがありますね。
これで複数の Private IP address を ENI に付与できるはずです。



・VPC環境の作成
ENIは VPC環境でしか使えないようなので、先に VPC環境を作成します。
$ ec2-create-vpc 192.168.1.0/24
VPC     vpc-baabadd3    pending 192.168.1.0/24  dopt-ecc9f785   default

$ ec2-create-subnet \
     --vpc vpc-baabadd3  \
     --cidr 192.168.1.0/24

SUBNET  subnet-8dabade4 pending vpc-baabadd3    192.168.1.0/24  251     ap-northeast-1a
前回作ったのと同じように、192.168.1.0/24 (サブネットも同じで1つだけ)のVPC環境になります。



・Internet GateWay の作成
VPC環境が外部と通信するためには Internet GateWay が必要なので、ソレを作成し、VPC環境にアタッチしておきます。
$ ec2-create-internet-gateway
INTERNETGATEWAY igw-d22a2abb

$ ec2-attach-internet-gateway \
     igw-d22a2abb \
     --vpc vpc-baabadd3

ATTACHMENT      vpc-baabadd3    attaching


・Routing Table の作成
VPC作成時にAWSが標準で作成したRoutingTableがあるはずなので、ソレを確認してみます。
$ ec2-describe-route-tables  --filter='vpc-id=vpc-baabadd3'
ROUTETABLE      rtb-bcabadd5    vpc-baabadd3
ROUTE   local           active  192.168.1.0/24          CreateRouteTable
ASSOCIATION     rtbassoc-bfabadd6       main
内向けの経路しか登録されていないようなので、外向けの経路を登録します。
$ ec2-create-route  \
     rtb-bcabadd5  \
     --cidr 0.0.0.0/0  \
     --gateway  igw-d22a2abb

ROUTE   igw-d22a2abb                    0.0.0.0/0

$ ec2-describe-route-tables rtb-bcabadd5
ROUTETABLE      rtb-bcabadd5    vpc-baabadd3
ROUTE   local           active  192.168.1.0/24          CreateRouteTable
ROUTE   igw-d22a2abb            active  0.0.0.0/0               CreateRoute
ASSOCIATION     rtbassoc-bfabadd6       main
外向けのパケットがIGWを通して外部に流れるような経路が出来ました。



・セキュリティグループの作成
httpd(web)、smtpd(mail) 、sshd(ssh) が利用できる EC2インスタンスを起動する前提で、VPC用セキュリティグループを作成します。特に名前に意味があるわけではありませんが、ここでは standalone という名前にしておきます。

$ ec2-create-group \
     vpc_standalone \
     --vpc vpc-baabadd3  \
     --description 'standalone in VPC'

GROUP   sg-fbd3cd97     vpc_standalone  standalone in VPC

$ ec2-authorize  \
     sg-fbd3cd97  \
     --protocol tcp  \
     --port-range 22  \
     --cidr '0.0.0.0/0'

GROUP   sg-fbd3cd97
PERMISSION                      ALLOWS  tcp     22      22      FROM    CIDR    0.0.0.0/0       ingress

$ ec2-authorize sg-fbd3cd97 \
     --protocol tcp  \
     --port-range 25  \
     --cidr '0.0.0.0/0'

GROUP   sg-fbd3cd97
PERMISSION                      ALLOWS  tcp     25      25      FROM    CIDR    0.0.0.0/0       ingress

$ ec2-authorize  \
     sg-fbd3cd97  \
     --protocol tcp  \
     --port-range 80  \
     --cidr '0.0.0.0/0'

GROUP   sg-fbd3cd97
PERMISSION                      ALLOWS  tcp     80      80      FROM    CIDR    0.0.0.0/0       ingress

$ ec2-describe-group sg-fbd3cd97
GROUP   sg-fbd3cd97     488224276535    vpc_standalone  standalone in VPC       vpc-baabadd3
PERMISSION      488224276535    vpc_standalone  ALLOWS  tcp     22      22      FROM    CIDR    0.0.0.0/0       ingress
PERMISSION      488224276535    vpc_standalone  ALLOWS  tcp     25      25      FROM    CIDR    0.0.0.0/0       ingress
PERMISSION      488224276535    vpc_standalone  ALLOWS  tcp     80      80      FROM    CIDR    0.0.0.0/0       ingress
PERMISSION      488224276535    vpc_standalone  ALLOWS  all                     TO      CIDR    0.0.0.0/0       egress


・ENIの作成
EC2インスタンス起動時に ENI を指定する必要があるため、先にENIを作成します。ENIにはセキュリティグループも必要なので、同時に指定しておきます。

$ ec2-create-network-interface \
     --description 'ENI-01 for standalone'  \
     --private-ip-address 192.168.1.100  \
     --group sg-fbd3cd97  \
     subnet-8dabade4
NETWORKINTERFACE        eni-b7b0b6de    ENI-01 for standalone   subnet-8dabade4 vpc-baabadd3    ap-northeast-1a 488224276535     false   pending 06:16:62:3a:1c:a1       192.168.1.100           true
GROUP   sg-fbd3cd97     vpc_standalone
PRIVATEIPADDRESS        192.168.1.100
ENIが作成できたので、セカンダリの Private IP を追加します。
$ ec2-assign-private-ip-addresses  \
     --network-interface eni-b7b0b6de \
     --secondary-private-ip-address 192.168.1.101

RETURN  true
ホントに二つのPrivate IP address が付与されたかどうか、確認してみます。
$ ec2-describe-network-interfaces eni-b7b0b6de
NETWORKINTERFACE        eni-b7b0b6de    ENI-01 for standalone   subnet-8dabade4 vpc-baabadd3    ap-northeast-1a 488224276535     false   available       06:16:62:3a:1c:a1       192.168.1.100           true
GROUP   sg-fbd3cd97     vpc_standalone
PRIVATEIPADDRESS        192.168.1.100
PRIVATEIPADDRESS        192.168.1.101

バッチリですね。



・EIP の確保と、ENIへの割り当て
EIP (Global IP)を確保して、作成済みのENIに割り当てます。
Private IP address 1つごとに1つのEIPを割り当てできるので、2つのEIPが使用できます。

Private IP address でそうしたように、キレイに二つ並んだモノが欲しいのですが…。ec2-allocate-address には そのようなオプションは無いですね…。
仕方ないので、二回取得することにします。
$ ec2-allocate-address --domain vpc
ADDRESS 54.249.94.148           vpc     eipalloc-9d2828f4

$ ec2-allocate-address --domain vpc
ADDRESS 54.249.94.173           vpc     eipalloc-912828f8
確保したEIPを 「192.168.1.100→54.249.94.148」「192.168.1.101→54.249.94.173」の組み合わせでENIに割り当てしてみます。
$ ec2-associate-address \
     --allocation-id eipalloc-9d2828f4  \
     --network-interface eni-b7b0b6de  \
     --private-ip-address 192.168.1.100
ADDRESS                 eipalloc-9d2828f4       eipassoc-9e2b2bf7       eni-b7b0b6de    192.168.1.100

$ ec2-associate-address \
     --allocation-id eipalloc-912828f8 \
     --network-interface eni-b7b0b6de  \
     --private-ip-address 192.168.1.101

ADDRESS                 eipalloc-912828f8       eipassoc-7f2c2c16       eni-b7b0b6de    192.168.1.101

$ ec2-describe-network-interfaces eni-b7b0b6de
NETWORKINTERFACE        eni-b7b0b6de    ENI-01 for standalone   subnet-8dabade4 vpc-baabadd3    ap-northeast-1a 488224276535     false   available       06:16:62:3a:1c:a1       192.168.1.100           true
GROUP   sg-fbd3cd97     vpc_standalone
ASSOCIATION     54.249.94.148   488224276535    eipassoc-9e2b2bf7       192.168.1.100
ASSOCIATION     54.249.94.173   488224276535    eipassoc-7f2c2c16       192.168.1.101

PRIVATEIPADDRESS        192.168.1.100
PRIVATEIPADDRESS        192.168.1.101
期待通りに割り当てられているようです。



・EC2インスタンスの起動
OSはいつも通り Ubuntu12 で、マイクロインスタンスを使用します。
ec2-run-instances で EC2を起動するのですが、その際 ENI を指定する方法が不明です。
公式のWEBページだと --network-interface オプションを利用することになっていますが、--help オプションで表示される説明だと --network-attachment となっています。省略形はどちらも -a になっているので、どちらでも使えるのかもしれませんが…。ちなみに、利用しているEC2コマンドのバージョンは1.6.7.1 (2013-02-01) です(ec2-version コマンドで確かめました)。
$ ec2-run-instances  ami-20ad1221  \
     --key innerkey  \
     --instance-count 1  \
     --instance-type t1.micro  \
     --instance-initiated-shutdown-behavior stop  \
     --group sg-fbd3cd97  \
     --subnet subnet-8dabade4  \
     --network-interface eni-b7b0b6de:0

Unrecognized option: --network-interface (use -h for usage)
げげ! まさかの公式ページが間違っているオチ...。--network-attachment が正解らしいです。
$ ec2-run-instances  ami-20ad1221  \
     --key innerkey  \
     --instance-count 1  \
     --instance-type t1.micro  \
     --instance-initiated-shutdown-behavior stop  \
    --group sg-fbd3cd97  \
    --subnet subnet-8dabade4  \
    --network-attachment eni-b7b0b6de:0
Client.InvalidParameterCombination: Network interfaces and an instance-level subnet ID may not be specified on the same request
--subnet 指定と、--network-attachment は同居できないようです。というか、よく考えたら必要ないですよね…。
$ ec2-run-instances  ami-20ad1221  \
     --key innerkey  \
     --instance-count 1  \
     --instance-type t1.micro  \
     --instance-initiated-shutdown-behavior stop  \
    --group sg-fbd3cd97  \
    --network-attachment eni-b7b0b6de:0
Client.InvalidParameterCombination: Network interfaces and an instance-level security groups may not be specified on the same request
今度はセキュリティグループが指定できない…と。たしかに、既にENIで指定してあるのでセキュリティグループ(--group)も不要ですよね。
$ ec2-run-instances  ami-20ad1221  \
     --key innerkey  \
     --instance-count 1  \
     --instance-type t1.micro  \
     --instance-initiated-shutdown-behavior stop  \
     --network-attachment eni-b7b0b6de:0

RESERVATION     r-9e32769d      488224276535
INSTANCE        i-4fce234d      ami-20ad1221            ip-192-168-1-100.ap-northeast-1.compute.internal        pending innerkey 0               t1.micro        2013-03-28T13:15:11+0000        ap-northeast-1a aki-ec5df7ed                    monitoring-disabled      54.249.94.148   192.168.1.100   vpc-baabadd3    subnet-8dabade4 ebs                                     paravirtual     xen              sg-fbd3cd97     default false
NIC     eni-b7b0b6de    subnet-8dabade4 vpc-baabadd3    488224276535    in-use  192.168.1.100           true
NICATTACHMENT   eni-attach-5e921337     0       attaching       2013-03-28T13:15:11+0000        false
NICASSOCIATION  54.249.94.148   488224276535    192.168.1.100
NICASSOCIATION  54.249.94.173   488224276535    192.168.1.101
GROUP   sg-fbd3cd97
PRIVATEIPADDRESS        192.168.1.100
PRIVATEIPADDRESS        192.168.1.101
ようやくEC2インスタンスが起動できました!



・EC2側でのENI+EIPの認識状態

プライマリ側の EIP を使って ssh で接続してみましょう。
$ ssh -i ~/.ssh/innerkey.pem -l ubuntu 54.249.94.148
なお、セカンダリのEIPでは接続できないので注意してください。
$ ssh -i ~/.ssh/innerkey.pem -l ubuntu 54.249.94.173
ssh: connect to host 54.249.94.173 port 22: Connection timed out
sshログインできたら、ネットワーク設定を確認してみます。
ubuntu$ ifconfig -a
eth0      Link encap:Ethernet  HWaddr 06:16:62:3a:1c:a1
          inet addr:192.168.1.100  Bcast:192.168.1.255  Mask:255.255.255.0
          inet6 addr: fe80::416:62ff:fe3a:1ca1/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:349 errors:0 dropped:0 overruns:0 frame:0
          TX packets:345 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:35751 (35.7 KB)  TX bytes:37538 (37.5 KB)
          Interrupt:25

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:16436  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
んー。二つ設定したはずの Private IP は、1つだけしか認識されていませんね。つまり、それと結び付けられている セカンダリのEIPも使用できないワケで…。AWS側で設定しても、OS側に自動設定してくれるわけではないようです…。

設定を確認してみましょう…
$ cat /etc/network/interfaces

# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).

# The loopback network interface
auto lo
iface lo inet loopback

# The primary network interface
auto eth0
iface eth0 inet dhcp
まさかのDHCP設定...。static(固定IP)じゃないんだ…。
まぁ、割り当てられたプライマリPrivateIPが変更された場合を考慮すると、DHCPの方が良いのでしょうね。

ちなみに、/etc/network/interfaces の末尾に iface eth0:1 inet dhcp を追記して再起動しても eth0:1 は利用可能になりませんでした。恐らく、eth0 と eth0:1 は物理的に同じNICなので MACアドレスも同一で…そのために DHCP サーバから同じPrivateIPが付与されたので使えなくなっているのかと思われます。iface行の下に hwaddress ether xx:xx:xx:xx:xx~ とか指定して MACアドレスを偽装すれば DHCP から異なる Private IP を貰えるかもしれないですが、クラウド環境下で MACアドレス偽装とか怖すぎるのでやめておきます…(x_x;

他に、ec2-run-instances に --network-attachment :0:subnet-8dabade4:"NewOne":192.168.1.20:"sg-fbd3cd97":true:1」とか指定して、AWS自身に 新しい2つの Private IP を持つENIを自動生成させた場合でも、やはり 二つ目の Private IP はOSに認識されていませんでした…。

結局、プライマリの Private IP 以外は 自力で設定する必要がありそうです。
メンドクサイので自動化する手段が欲しい...(^^;

仕方ないので、/etc/network/interfaces に以下のように追記します。
# The loopback network interface
auto lo
iface lo inet loopback

# The primary network interface / eth0
auto eth0
iface eth0 inet dhcp

# The primary network interface / eth0:1
auto eth0:1
iface eth0:1 inet static
address 192.168.1.101
netmask 255.255.255.0

この設定では、metric がすべて1になってしまいますが…。
⇒ ifmetric パッケージを導入して eth0:1 側に metric 2 等の設定を追加しても、反応してくれませんでした。正直、metric の設定方法が良く分からない…。


ちなみに、eth0:1 を追加した直後から sudo を実行すると「sudo: unable to resolve host ip-192-168-1-100」とか怒られてしまうので、/etc/hosts に以下のような行を追記しておきます。
127.0.1.1   localhost.localdomain   ip-192-168-1-100
ホスト名は sudo のエラーと合わせておいてください。IPアドレスは 127.0.1.1 です。
これで名前が解決できるようになって、sudo がエラーを出さなくなります。
⇒ 127.0.1.1 というのは debian 系(Ubuntuもその一派)が勝手に設定するIPアドレスらしいです。今回のサーバだと 192.168.1.100 がプライマリのPrivateIPなのでその値を記載するのが本来の使い方のような気もしますが(x_x;

取りあえず、2つのIPアドレスで通信できるのかどうか、curl で確認してみます。利用する IPアドレス(=リクエスト発行元となるIPアドレス/ネットワークインターフェース)変更するには --interface オプションを使用します。

$ curl \
       --interface eth0 \
       'http://www.axisnetworks.biz/tools/gip/' 2>&1 \
   | egrep --only-matching \
       'name="ip">[^<]*<'

name="ip">54.249.94.148  <

$ curl \
       --interface eth0:1 \
       'http://www.axisnetworks.biz/tools/gip/' 2>&1
   | egrep --only-matching
       'name="ip">[^<]*<'

name="ip">54.249.94.173  <
期待通りに動作していますね。
http://www.axisnetworks.biz/tools/gip/ はブラウザでアクセスした際、利用しているグローバルIPを教えてくれるサービスらしいです。


では外部からの接続はどうでしょうか?

まず、port 80 で待ち受ける設定をします。待ち受けには nc (netcat)コマンドを利用します。
$ sudo nc -l 192.168.1.100 80
この状態で待ち受け(listen)が始まるので、別のサーバから「telnet 54.249.94.148 80」とか「curl 'http://54.249.94.148'」とか入力して、nc 側に接続させます。ちなみに、nc で待ち受けしているサーバでは(ネットワーク設定にもよりますが)自分自身に接続できないので、他のサーバを用意してください。
同じように「sudo nc -l 192.168.1.101 80」として待ち受けた場合には、「telnet 54.249.94.173 80」とか「curl 'http://54.249.94.173'」として接続できます。
もちろん、EIP (54.249.94.148と54.249.94.173)は ご自身で確保したものと置き換えてくださいね。

これで、二つの Global IP Address が利用できることを確認できました☆

⇒ もっとも、このような「同一subnetにIPアドレスを二つ持つ」というのが必要な状況は、あんまりありませんが…。
⇒ 今回は、「メイルサーバ用に複数IPを持ったサーバが欲しかった」のでこのような実験をしています。


文字数が足りなくなったので、今回はここまで。
破棄手順は、次回になります。