Amazon SDKを介して複数のElasticIPを単一のインスタンスに関連付ける方法を知っている人はいますか? Rubyでは、aws-sdkとfog gemの両方を使用しようとしました。これらは単一のアドレスでは正常に機能しますが、複数のアドレスを割り当てようとするとエラーになります。
Web UIを介して、これはプライベートIPを追加し、パブリックIPをネットワークインターフェイス+プライベートIPに割り当てることによって行われますが、私はSDKのプライベートIPパラメーターではありません。
Elastic IPが機能しています
デフォルトでは、VPCのインスタンスは、VPC内のプライベートサブネット(通常は10.0.0.0/8サブネットのどこか)からのみIPを取得します。つまり、これらのインスタンスは同じサブネット内の他のインスタンスにアクセスできますが、より広いインターネットに接続することはできません。
すべてのマシンにアクセスを許可する1つの方法は、すべてのマシンがトラフィックのルーティングに使用するNATマシンをセットアップすることです。このオプションについてはこれ以上詳しく説明しません。
別の方法は、すべてのマシンに独自のワールドルーティング可能なElasticIPアドレスを与えることです。 Amazonは、トラフィックをエラスティックIPから内部IPにルーティングします。これにより、ネットワークトポロジの観点からこのセットアップが簡単になります。
VPCでのルーティングは、サブネットごとに設定されたルーティングテーブルを介して機能します。 AWSコンソールの[VPC]タブでルーティングテーブルを表示できます。デフォルトでは、サブネット内のリクエストはローカルにルーティングされ、その範囲外のリクエストは「インターネットゲートウェイ」を介してルーティングされます。
たとえば、IP10.0.0.1のインスタンスがあるとします。 Elastic IPが関連付けられています。たとえば、1.2.3.4です。これで、10.0.0.0/8サブネット上の他の内部マシンにアクセスするときはいつでも、リクエストはプライベートIPから発信され、トラフィックには何も起こりません。
サブネット外のマシンにアクセスすると、パケットはインターネットゲートウェイ(igw-9d7534f2などの名前のVPCデバイス)を介してルーティングされます。ゲートウェイ(実際のEC2インスタンスではなく、不透明なAWSシステム)はリクエストを受け入れ、リクエストの発信元である内部IPを検索し、このIPがElasticIPに関連付けられているかどうかを確認します。その場合、オリジンがエラスティックIPであるかのように表示されるように要求が書き換えられ、インターネット経由で送信されます。パッケージがエラスティックIPを宛先としてゲートウェイに戻ると、ゲートウェイはエラスティックIPが内部IPに関連付けられているかどうかを確認し、関連付けられている場合はパッケージをそのIPに書き換えます。その後、パッケージはプライベートサブネットに転送されます。
これが、エラスティックIPの1対1 NATの仕組みです。このアプローチの利点は、サブネット内のマシンがエラスティックIPの知識を持っている必要がないことです。更新する必要があるのはインターネットゲートウェイのマッピングテーブルだけなので、これにより、実行中のインスタンスのエラスティックIPを簡単に切り替えることができます。外部IPは何度も変更される可能性があります。パッケージはインスタンスに到着する前に内部IPを使用するように書き直されるため、インスタンスはこれを認識しません。
複数のネットワークインターフェース
過去に、AmazonはVPCインスタンスに複数のネットワークインターフェースを追加するオプションを追加しました。これらのインターフェイスは、マシン上では個別のイーサネットカードとして表示され、個別の内部IPを持ちます。個別のインターフェースは、これらのインターフェース間のルーティングを正しく設定する必要があることも意味します。間違ったインターフェースを介してパケットを送信すると、パケットは単にドロップされます。
これらのネットワークインターフェースは、異なるサブネットを相互に接続するオプションを提供するために導入されました。各サブネットに1つのインターフェースを設定し、必要に応じてそれらの間でトラフィックをルーティングできます。各サブネットには独自のIP範囲があるため、トラフィックを適切なネットワークインターフェイスに簡単にルーティングできます。
内部IPごとに、外部ElasticIPを関連付けることができます。これは可能ですが、今は少しトリッキーなルーティング状況に陥ります。両方の内部IP(eth0とeth1)には外部IPが関連付けられており、インターネットゲートウェイに内部IPをElastic IPに変換させることで、より広いインターネットにリクエストを送信できる必要があります。ただし、これを正しく行うには、リクエストを正しいインターフェイスを介して送信する必要があります。 Amazon自体は、これが単純ではないことを認めています。
デフォルトでは、Linuxには、ローカルサブネット外のすべてのトラフィックを単一のインターフェイスにルーティングするルーティングテーブルがあります。あなたはルートでこれを調べることができます:
# route
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
default 10.0.0.1 0.0.0.0 UG 0 0 0 eth0
default 10.0.0.1 0.0.0.0 UG 100 0 0 eth0
10.0.0.0 * 255.255.255.0 U 0 0 0 eth0
10.0.0.0 * 255.255.255.0 U 0 0 0 eth1
ここでは、すべてのインターネット全体のトラフィックがインターフェイスeth0を介して送信されます。 eth1インターフェースの送信元IPを持つパケットでさえ、eth0を介して送信され、適切なエラスティックIPにNATされる代わりに、サイレントに破棄されます。これを修正するためにソースベースのルーティングを行うことは可能ですが、これを設定するのは簡単ではありません(マシンに別のインターフェイスを追加した後、dhclientを実行する必要があることに注意してください)。
# ifconfig | grep eth\\\|inet\
eth0 Link encap:Ethernet HWaddr 02:86:10:77:7f:fe
inet addr:10.0.0.76 Bcast:10.0.0.255 Mask:255.255.255.0
eth1 Link encap:Ethernet HWaddr 02:86:10:65:fd:31
inet addr:10.0.0.226 Bcast:10.0.0.255 Mask:255.255.255.0
# curl --interface 10.0.0.76 ifconfig.me
116.x.x.x
# curl --interface 10.0.0.226 ifconfig.me
<< TIMEOUT >>>
# ip rule add from 10.0.0.226 table out2
# ip route add default via 10.0.0.1 dev eth1 table 2
# ip route flush cache
# curl --interface 10.0.0.226 ifconfig.me
116.x.x.x
# curl --interface 10.0.0.76 ifconfig.me
116.x.x.x
複数のIPアドレス
このようにして、上からのルーティングの厄介な問題の一部を回避できます。どのIPを使用しているかに関係なく、すべてのパケットがeth0を介して送信されます。パブリックアドレスとプライベートアドレスは1対1でマッピングされるため、最初にインスタンスの1つに新しいプライベートアドレスを追加する必要があります。
AmazonのAPIは、セカンダリプライベートIPの割り当てをサポートするように更新されましたが、この例では、AWSコンソールに移動する方が簡単です。 [EC2]タブで、[インスタンス]に移動します。更新するインスタンスを見つけて右クリックし、「プライベートIPアドレスの管理」を選択します。
これで、インスタンスのサブネットに2つのプライベートIPがあることがわかります(インターフェースは特定のサブネットにロックされているため、そのインターフェース上のすべてのIPは同じサブネット内にある必要があります)。いいね!ただし、インスタンスを確認すると、次のようになります。
# ifconfig eth0
eth0 Link encap:Ethernet HWaddr 02:86:10:7b:e4:f5
inet addr:10.0.0.34 Bcast:10.0.0.255 Mask:255.255.255.0
新しいIPはまだありません。 DHCP経由で取得してみましょう。
root@ip-10-0-0-34:/# dhclient -d eth0
Listening on LPF/eth0/02:86:10:7b:e4:f5
Sending on LPF/eth0/02:86:10:7b:e4:f5
DHCPDISCOVER on eth0 to 255.255.255.255 port 67 interval 3
DHCPREQUEST of 10.0.0.34 on eth0 to 255.255.255.255 port 67
DHCPOFFER of 10.0.0.34 from 10.0.0.1
DHCPACK of 10.0.0.34 from 10.0.0.1
いいえ、プライマリプライベートIPのみを取得します! DHCPを使用すると、単一のアドレスしか取得できません。将来的には、Amazonがクライアント識別子または別のメカニズムを使用して複数のIPのサポートを追加する可能性がありますが、今のところ、アドレスを手動で追加する必要があります。うまくいけば、Ubuntuのcloud-initが将来これのサポートを追加するので、自分でサポートする必要はありません。
Amazonは、新しい仮想インターフェイスを作成してからそれを起動することを提案しています。それは機能しますが、インターフェースの状態をハードドライブに保存し、AWSで行った変更をこれらのファイルに伝達する必要があることを意味します。
テストのために、もっと簡単なことをすることができます:
MAC_ADDR=$(ifconfig eth0 | sed -n 's/.*HWaddr \([a-f0-9:]*\).*/\1/p')
IP=($(curl http://169.x.x.x/latest/meta-data/network/interfaces/macs/$MAC_ADDR/local-ipv4s))
for ip in ${IP[@]:1}; do
echo "Adding IP: $ip"
ip addr add dev eth0 $ip/24
done
これにより、eth0に関連付けられているすべての内部IPのEC2インスタンスメタデータがチェックされ、すべてのセカンダリIPが追加されます。
AWSコンソールで別のエラスティックIPをセカンダリIPに関連付けることができるようになりました。
そして今、あなたは複数の外部IPを持っています!
root@ip-10-0-0-34:/# curl --interface 10.0.0.58 ifconfig.me
116.x.x.x
root@ip-10-0-0-34:/# curl --interface 10.0.0.34 ifconfig.me
116.x.x.x
これはテストでは機能しますが、再起動後も持続しません。 upstartまたはcloud-initスクリプトを作成して、それを行うことができます。それでも、EC2を介してIPアドレスを追加しても、IPアドレスは自動的に追加されません。それを行う良い方法があるかどうかはわかりません。最後に、このスクリプトは、その間に削除した可能性のあるローカルアドレスも削除しません。
これがお役に立てば幸いです。