マネージドサービス部 佐竹です。
新機能としてリリースされた Multi-VPC ENI アタッチメントを検証してみましたので、ついでに PrivateLink あたりと比較していきたいと思います。
- はじめに
- VPC を跨ぐためのサービスを簡単に整理する
- Multi-VPC ENI アタッチメント動作検証
- Multi-VPC ENI アタッチメントと PrivateLink の比較
- まとめ
はじめに
Multi-VPC ENI アタッチメントが2023年10月26日にリリースされました。
これは1つの EC2 インスタンスに、異なる VPC に存在する ENI (NIC) をアタッチすることが可能となったという新機能です。
これまでは同 VPC 内からのみ指定が可能だった
本機能がリリースされるまで、セカンダリとしてアタッチ可能な ENI は、同じ VPC 内である必要がありました。
これは以下の公式ドキュメントに One or more secondary private IPv4 addresses from the IPv4 address range of your VPC
と記載があります。
今後は別 VPC の ENI も指定が可能に
新機能「Multi-VPC ENI アタッチメント」により、別 VPC からも ENI がアタッチ可能となりました。
このように、別々の VPC の ENI がアタッチされている EC2 インスタンスは、AWS 公式ドキュメントにおいては「dual-homed インスタンス」と呼ばれています。
Multi-VPC ENI アタッチメントの機能上の制限
ただし、いくつか機能上の制限が存在します。それは「同じ Availability Zone (AZ) であること」と「同じ AWS アカウント内であること」です。
本制限の原文は以下の引用の通りです。
You can launch an EC2 instance in one VPC and attach a secondary ENI from another VPC (but in the same Availability Zone) to the instance. This enables you to create multi-homed instances across VPCs with different networking and security configurations. You cannot create multi-homed instances across VPCs across different AWS accounts.
https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/scenarios-enis.html
設計フェーズにおいて、これらの制限事項には十分に注意ください。
VPC を跨ぐためのサービスを簡単に整理する
本機能を加えると、AWS の機能を用いて VPC を跨ぐことが可能となる機能が5つに増えた認識です。
- VPC Peering
- AWS PrivateLink
- AWS Transit Gateway
- Amazon VPC Lattice
- Multi-VPC ENI Attachments
これらのうち、Protocol が規定されている「Amazon VPC Lattice」を除いて以下で表形式にして比較してみます。
機能名 | AWS アカウントの制限 | Availability Zone の制限 | VPC CIDR の制限 | その他 |
---|---|---|---|---|
VPC Peering | 別アカウントと接続可 | AZ の制限なし | CIDR の重複不可 | Subnet のルートテーブルの設定が必要 |
AWS PrivateLink | 別アカウントと接続可 | 設定により AZ が異なる通信も可能*1 | 考慮する必要がない | NLB の追加構築が必要 |
AWS Transit Gateway | 別アカウントと接続可*2 | AZ の制限なし*3 | CIDR の重複不可 | アタッチメントの分利用料が高額 |
Multi-VPC ENI Attachments | 同アカウント内のみ | アタッチ自体は同 AZ のみ | CIDR の重複は回避可能*4 | OS のルートテーブルの設定が必要 |
簡単に比較が終わったところで、以下で実際に動作検証を行った結果を構成図と共にご紹介します。
Multi-VPC ENI アタッチメント動作検証
今回、検証を行うにあたりまずは AWS 環境構成図を使って解説します。
前提となる AWS 環境構成図
上図のような既存構成があるとします。
ポイントとしては、AWS アカウントは同アカウント内で、VPC が CIDR 重複なしで複数ある状態としています。
これまで可能であったこと
先に記載した通り、以前より同 VPC 内の ENI を EC2 インスタンスのセカンダリ ENI としてアタッチすることが可能です。
画像では、赤の縦線で表しています。
Multi-VPC ENI アタッチメントで可能になったこと
今回 Multi-VPC ENI アタッチメントで、上図の通り「別 VPC の同 AZ の ENI をアタッチする」ことが可能となりました。
ただし、制限の通り別の AZ を指定することは不可能なため、AZ-1a の ENI をプライマリとして構築された EC2 インスタンスは、AZ-1c の ENI をセカンダリとして指定ができません。
動作検証用の構成
VPC を跨ぎつつ、同 AZ で ENI をアタッチするために、上図の通りの構成を準備しました。
AWS CLI による Multi-VPC ENI アタッチメント実装
この状態で、AWS CLI を用いて実装を行います。AWS CLI を利用するのは、今現在では AWS マネジメントコンソール上では同 VPC の ENI しか一覧に表示されないためです。
以下はコマンド例です。
aws ec2 attach-network-interface --device-index 1 --instance-id i-EC2-Side-A-1a --network-interface-id eni-ENI-Side-B-1a aws ec2 attach-network-interface --device-index 1 --instance-id i-EC2-Side-B-1c --network-interface-id eni-ENI-Side-A-1c
引数の各 ID 部分は置き換えてご利用ください。
以下は実際の実行結果です。
$ aws ec2 attach-network-interface --device-index 1 --instance-id i-052a1ea437756a660 --network-interface-id eni-0b5d6778913783e57 { "AttachmentId": "eni-attach-04892b64abbe8883f", "NetworkCardIndex": 0 } $ aws ec2 attach-network-interface --device-index 1 --instance-id i-0760487b7da4e2e7f --network-interface-id eni-02334a6e1f2214606 { "AttachmentId": "eni-attach-0a14d64f82c009462", "NetworkCardIndex": 0 }
無事に成功すると "AttachmentId" が返却されます。
マネジメントコンソールから、EC2 インスタンスの「Private IPv4 addresses」も合わせて確認します。画像の通りですが、「EC2 Side-A 1a」では「10.10.10.140」に加えて「10.20.20.140」がアタッチされていることがわかります。
そしてここまで完了すると、上図の通り VPC を跨いで ENI がアタッチされた「dual-homed インスタンス」がそれぞれの AZ ごとに完成します。
接続確認
この状況で、左上にある「EC2 Side-A 1a 10.10.10.140」から右下にある「EC2 Side-B 1c 10.20.20.150」への通信とその逆をそれぞれ検証します。
念のためですが、ENI を EC2 インスタンスにアタッチ後は、追加された ENI が正しく認識されるよう OS を再起動させています。
なお、各 Subnet のルートテーブルの設定ですが「local」の経路が各 ENI ごとにそれぞれ作用するため、本構成においてはルートテーブルの設定を編集することなく疎通が可能です。
① 「ENI Side-B 1a 10.20.20.140」を経由した Side-A から Side-B
まずは「EC2 Side-A 1a 10.10.10.140」に Session Manager でアクセスし、「EC2 Side-B 1c 10.20.20.150」へ疎通確認してみます。
方向としては、この図の左上から右下への矢印です。
参考まで、先に networkctl status
と ifconfig
, ip route
のコマンドの結果をそれぞれ掲載しておきます。Amazon Linux 2023 を利用していますが、特に OS では設定を変更しておらずデフォルトのままです。
networkctl status
sh-5.2$ networkctl status ● State: routable Online state: online Address: 10.10.10.140 on ens5 10.20.20.140 on ens6 fe80::471:74ff:fe82:ed5 on ens5 fe80::4a8:d1ff:fe54:aacd on ens6 Gateway: 10.10.10.129 on ens5 10.20.20.129 on ens6 DNS: 10.10.10.2 10.20.20.2 Search Domains: ap-northeast-1.compute.internal
ifconfig
sh-5.2$ ifconfig ens5: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 9001 inet 10.10.10.140 netmask 255.255.255.240 broadcast 10.10.10.143 inet6 fe80::471:74ff:fe82:ed5 prefixlen 64 scopeid 0x20<link> ether 06:71:74:82:0e:d5 txqueuelen 1000 (Ethernet) RX packets 68171 bytes 16505324 (15.7 MiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 67004 bytes 13341406 (12.7 MiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 ens6: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 9001 inet 10.20.20.140 netmask 255.255.255.240 broadcast 10.20.20.143 inet6 fe80::4a8:d1ff:fe54:aacd prefixlen 64 scopeid 0x20<link> ether 06:a8:d1:54:aa:cd txqueuelen 1000 (Ethernet) RX packets 5235 bytes 678967 (663.0 KiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 5488 bytes 555600 (542.5 KiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536 inet 127.0.0.1 netmask 255.0.0.0 inet6 ::1 prefixlen 128 scopeid 0x10<host> loop txqueuelen 1000 (Local Loopback) RX packets 12 bytes 1020 (1020.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 12 bytes 1020 (1020.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
ip route
sh-5.2$ ip route default via 10.10.10.129 dev ens5 proto dhcp src 10.10.10.140 metric 512 default via 10.20.20.129 dev ens6 proto dhcp src 10.20.20.140 metric 522 10.10.10.2 via 10.10.10.129 dev ens5 proto dhcp src 10.10.10.140 metric 512 10.10.10.128/28 dev ens5 proto kernel scope link src 10.10.10.140 metric 512 10.10.10.129 dev ens5 proto dhcp scope link src 10.10.10.140 metric 512 10.20.20.2 via 10.20.20.129 dev ens6 proto dhcp src 10.20.20.140 metric 522 10.20.20.128/28 dev ens6 proto kernel scope link src 10.20.20.140 metric 522 10.20.20.129 dev ens6 proto dhcp scope link src 10.20.20.140 metric 522
この状態で ping 10.20.20.150
を実行してみます。
sh-5.2$ ping 10.20.20.150 PING 10.20.20.150 (10.20.20.150) 56(84) bytes of data. ^C --- 10.20.20.150 ping statistics --- 3 packets transmitted, 0 received, 100% packet loss, time 2091ms
疎通できませんでした。これはデフォルトでプライマリになっている ENI が優先されるためで、今回であれば「10.10.10.140 on ens5」が優先されているためです。
よって「ENI Side-B 1a 10.20.20.140」を指定した状態で再度 ping を実行してみます。
sh-5.2$ ping 10.20.20.150 -I 10.20.20.140 PING 10.20.20.150 (10.20.20.150) from 10.20.20.140 : 56(84) bytes of data. 64 bytes from 10.20.20.150: icmp_seq=1 ttl=127 time=1.93 ms 64 bytes from 10.20.20.150: icmp_seq=2 ttl=127 time=1.95 ms 64 bytes from 10.20.20.150: icmp_seq=3 ttl=127 time=1.96 ms ^C --- 10.20.20.150 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 2003ms rtt min/avg/max/mdev = 1.934/1.947/1.960/0.010 ms
今度は疎通できました。
このように、EC2 インスタンスではデフォストでプライマリの ENI が優先されるため、OS のルート設定によって疎通の可否が左右されてしまうわけです。
② 「ENI Side-B 1a 10.20.20.140」を経由した Side-B から Side-A
今度は先の反対の経路で、この図の右下から左上への矢印です。
この場合に、宛先として指定する IP アドレスは「10.20.20.140」そのものになります。
「10.20.20.140」は「EC2 Side-B 1c 10.20.20.150」に直接アタッチされているわけではないため、EC2 インスタンスはプライマリの ENI から疎通が可能です。
h-5.2$ ping 10.20.20.140 PING 10.20.20.140 (10.20.20.140) 56(84) bytes of data. 64 bytes from 10.20.20.140: icmp_seq=1 ttl=127 time=1.94 ms 64 bytes from 10.20.20.140: icmp_seq=2 ttl=127 time=1.93 ms 64 bytes from 10.20.20.140: icmp_seq=3 ttl=127 time=1.95 ms ^C --- 10.20.20.140 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 2004ms rtt min/avg/max/mdev = 1.932/1.939/1.951/0.008 ms
この通り、通常通りプライマリ ENI からの疎通が可能となっています。
実際に「EC2 Side-A 1a 10.10.10.140」が ping を受信できているのか sudo tcpdump icmp -i ens6
で確認も行いました。
ens6 (10.20.20.140) 側で、ping を受信できていることがわかります。
sh-5.2$ sudo tcpdump icmp -i ens6 dropped privs to tcpdump tcpdump: verbose output suppressed, use -v[v]... for full protocol decode listening on ens6, link-type EN10MB (Ethernet), snapshot length 262144 bytes 05:12:08.557011 IP ip-10-20-20-150.ap-northeast-1.compute.internal > ip-10-20-20-140.ap-northeast-1.compute.internal: ICMP echo request, id 6, seq 1, length 64 05:12:08.557045 IP ip-10-20-20-140.ap-northeast-1.compute.internal > ip-10-20-20-150.ap-northeast-1.compute.internal: ICMP echo reply, id 6, seq 1, length 64 05:12:09.559053 IP ip-10-20-20-150.ap-northeast-1.compute.internal > ip-10-20-20-140.ap-northeast-1.compute.internal: ICMP echo request, id 6, seq 2, length 64 05:12:09.559086 IP ip-10-20-20-140.ap-northeast-1.compute.internal > ip-10-20-20-150.ap-northeast-1.compute.internal: ICMP echo reply, id 6, seq 2, length 64 05:12:10.560124 IP ip-10-20-20-150.ap-northeast-1.compute.internal > ip-10-20-20-140.ap-northeast-1.compute.internal: ICMP echo request, id 6, seq 3, length 64 05:12:10.560156 IP ip-10-20-20-140.ap-northeast-1.compute.internal > ip-10-20-20-150.ap-northeast-1.compute.internal: ICMP echo reply, id 6, seq 3, length 64 05:12:11.561165 IP ip-10-20-20-150.ap-northeast-1.compute.internal > ip-10-20-20-140.ap-northeast-1.compute.internal: ICMP echo request, id 6, seq 4, length 64 05:12:11.561196 IP ip-10-20-20-140.ap-northeast-1.compute.internal > ip-10-20-20-150.ap-northeast-1.compute.internal: ICMP echo reply, id 6, seq 4, length 64
そして②の構成は、後に改めて比較します PrivateLink の構成に似ています。
③ 「ENI Side-A 1c 10.10.10.150」を経由した Side-B から Side-A
参考までに、逆方向である「EC2 Side-B 1c 10.20.20.150」から「EC2 Side-A 1a 10.10.10.140」への通信も見ておきます。
方向としては、この図の右下から左上への矢印です。
sh-5.2$ ping 10.10.10.140 -I 10.10.10.150 PING 10.10.10.140 (10.10.10.140) from 10.10.10.150 : 56(84) bytes of data. 64 bytes from 10.10.10.140: icmp_seq=1 ttl=127 time=2.61 ms 64 bytes from 10.10.10.140: icmp_seq=2 ttl=127 time=1.99 ms ^C --- 10.10.10.140 ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 1002ms rtt min/avg/max/mdev = 1.988/2.298/2.608/0.310 ms
先ほどと同様、ping の引数でセカンダリ ENI の「10.10.10.150」を指定することで疎通が可能です。
④ 「ENI Side-A 1c 10.10.10.150」を経由した Side-A から Side-B
先の図の左上から右下への矢印も確認します。
h-5.2$ ping 10.10.10.150 PING 10.10.10.150 (10.10.10.150) 56(84) bytes of data. 64 bytes from 10.10.10.150: icmp_seq=1 ttl=127 time=1.99 ms 64 bytes from 10.10.10.150: icmp_seq=2 ttl=127 time=1.99 ms 64 bytes from 10.10.10.150: icmp_seq=3 ttl=127 time=2.00 ms ^C --- 10.10.10.150 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 2002ms rtt min/avg/max/mdev = 1.985/1.990/1.997/0.005 ms
プライマリの ENI が利用されるため、通常通り疎通が可能でした。
これらの検証結果の通り、VPC を跨いでアタッチされたセカンダリ ENI はデフォルトで優先されないため、合わせて OS 上で適切な経路設計が追加で必要なことがわかります。
Multi-VPC ENI アタッチメントと PrivateLink の比較
Multi-VPC ENI アタッチメントと PrivateLink を構成図上に並べて描いてみると、近い構成になることがわかります。
上図は上段が PrivateLink で、下段が Multi-VPC ENI アタッチメントです。
図の左側から右側に VPC を跨いで疎通したいと要望があった場合、PrivateLink で実装が可能なことはもちろんながら、NLB なしで Multi-VPC ENI アタッチメントでも実装が可能になります。「同一 AWS アカウント」且つ「同一 AZ」という制限はあるものの、要件に当てはまる場合は PrivateLink よりも安く実装できるでしょう。
加えて、PrivateLink よりも容易に「両方向の通信が可能」となる点もメリットとなります。
これを見るに、「同一 AWS アカウント」且つ「同一 AZ」においては Multi-VPC ENI アタッチメントが PrivateLink の代替案になる可能性はありそうです。
その他のサービスと比較して感じること
Transit Gateway と比較して検討する場合を考えてみると、Transit Gateway を実装する場合には「TGW アタッチメント」の保持で費用が嵩んでしまいますが、Transit Gateway なしで VPC 間を簡易的に疎通させたい場合にも有用かと思われます。
同様に VPC Peering ですが、特に「一時的に共有を行い、不要となれば削除する」ような使い方においては、VPC や Subnet の経路設計に影響が出てしまう VPC Peering と比較してもお手軽さを感じます。
まとめ
本ブログでは、新機能である Multi-VPC ENI アタッチメントを検証しつつ、これまでのサービスとの比較検討を行ってみました。
また本機能の制限として「同じ Availability Zone であること」と「同じ AWS アカウント内であること」が前提の機能となっていることを紹介しました。
動作検証と共に、最後に PrivateLink との構成を比較検討しました。
今後、適切な利用ケースにおいて本機能が役立つ場合があるかも知れませんため、本機能を頭の片隅に置きつつネットワークの構成提案を今後も続けていきたいと思います。
それでは、またお会いしましょう。
*1:https://blog.serverworks.co.jp/configuration-for-enabling-communication-between-instances-in-different-availability-zones-using-aws-privatelink
*2:AWS Resource Access Manager によるリソース共有が必要
*3:各 AZ に TGW アタッチメントを作成する必要がある点に注意が必要
*4:OS 内で NAT 等を行えば IP の重複も回避が可能
佐竹 陽一 (Yoichi Satake) エンジニアブログの記事一覧はコチラ
マネージドサービス部所属。AWS資格全冠。2010年1月からAWSを利用してきています。2021-2022 AWS Ambassadors/2023-2024 Japan AWS Top Engineers/2020-2024 All Certifications Engineers。AWSのコスト削減、最適化を得意としています。