AWS VPC のネットワーク小話~Public/PrivateとIPv4/6~

日々何気なくお世話になっている VPC 含むネットワークは、ちゃんと理解しようとすると思ったより多い情報量と、それに対するパターンの経験が必要になります。

私自身、正直ネットワークのお話は好きじゃないのですが、現行の事情を踏まえてこの辺の基本と雑学を振り返っておくと、技術力のベースが整ってよろしいのではと思って整理することにしました。



はじめに

新年度なので、学習教材シリーズです。今回はネットワーク周りで、基礎に味付けするような内容です。もしかしたらお嫌いなジャンルでしょうか、でも少しだけやりましょうそうしましょう。

関連情報としては、このあたり。

書くお気持ちになった関連としてはこの辺。ツリーではタラタラ申してますけど、基本的にはサービスの完全無料とか無制限系は信用していないので、ちゃんと従量課金になっている AWS は好きですよホント。


NAT G/W の存在もアレですが、IPv6 の存在感が強くなってきたことで、ネットワークを Public / Private の存在意義から振り返ったり、どういう内容の時にどういう構成が適しているのか、を改めて振り返る意味が出てきたと思います。

世の中には『WEBサーバーが Private に配置されていない時点でお察しw』みたいなコメントを定期的に見かけるくらいには、凝り固まった考え方の人もいて、教科書とか資格で学ぶのかな?って眺めたりしますが、大事なのは仕組みを正しく理解し、正しく最適化することなので、柔軟な学びと設計を心がけられればな、という感じです。

ということでタイトルの内容について振り返りつつ、どういう項目を考慮しながら設計すると、効率化やコスト削減につながるかをザックリと追っていきます。環境に応じてベター・ベストは異なる点もあると思うので、まずは知識と現状把握を均すところから大事にできればって雰囲気で入っていきます。


IPv4 Public / Private の違い

まずこの2つの違いを端的に表現すると、『GlobalIPアドレスを所持するかしないか』ということになります。PrivateIPアドレスだけを持つ場所が Private Network、両方とも持つ場所が Public Network、と論理設計します。物理はオンプレならこうってのはあるけど、クラウドはブラックボックスなので省略。

(※以下、IPアドレス を IP と略すけど、いちいち突っ込まないこと:-)

それぞれネットワークとして機能するために Routing が異なり、また SecurityGroup などのもろもろ設定が変わりますが、大きな違いはそれ1点だと考えてよく、それによる特徴を整理していきます。

外部からのリクエスト受信 (INPUT)

インターネットに公開するサーバーが、ユーザーからリクエストを受けるためには、GlobalIP が必須です。AWS で言うところの ALB / NLB あたりは自動的に PublicIP が割り当てられ、バックエンドには Private Network で通信します。EC2 が単体で直に受けたい場合は固定な ElasticIP を割り当てて、外から接続できるようにします。

Private Network のリソースは GlobalIP を持たないので、外部から直にアクセスされる可能性はゼロとなります。

外部から直接に接続できることはリスクを含みます。OS や DB へのログインを、不特定多数の人間がチャレンジできる環境がヤバいのは誰にでもわかることなので、外からのアクセスを必要としないリソースには GlobalIP を割り当てないことが基本です。

仮に割り当てても、SecurityGroup を基本として、必要があれば NetworkACL, firewalld (旧iptables) でも制限することで必要最低限の開放にできますが、そもそも不要なら割り当てなければ、それらの設定ミスといった事故を回避できます。

外部へのリクエスト送信 (OUTPUT)

ここでいう OUTPUT はリクエスト受信に対するレスポンスではなく、自身が送信元となるリクエストのことです。yum や apt で外部からパッケージをダウンロードしたり、git でコードを取得したり、aws コマンドのような外部API を実行するのもそうです。

インターネット上にあるリソースにアクセスするにも、GlobalIP が必須です。そのため Public Network で PublicIP を持てば Internet Gateway (IGW) を通して不自由なく可能となり、Private で持たなければ外部との通信が不可能となります。

しかし、Private リソースも yum や aws コマンドを実行したい場合が当然あり、それをなんとかしてくれるのが NAT(Network Address Translation)Gateway です。Global IPv4 が有限かつ枯渇気味であること、そもそも GlobalIP を割り当てるべきではないリソースのために、NAT G/W が存在します。

Routing によって、自身の知らない宛先を全て任せる 0.0.0.0/0 を NAT G/W に転送すると、送信元アドレスを NAT G/W が持つ GlobalIP に変換して転送 (FORWARD) してくれます。なぜ NAT 処理が必要かというと、パケットが返ってこれなくなるからです。

通信は送信元アドレス (src addr) と宛先アドレス (dst addr) で成り立ち、往路は宛先に送りつけるだけですが、復路では送信元に向かって返す必要があります。お互いが GlobalIP を持っていれば、悠々とインターネット上を行き来できますが、PrivateIP しか持たないリソースの送信元アドレスは当然 PrivateIP になるため、宛先リソースがその赤の他人の PrivateIP に返そうとしても迷子になるだけです。

  • Global 同士は往復できる
    203.0.113.1 ─往路→ 198.51.100.2
    203.0.113.1 ←復路─ 198.51.100.2
  • Src が Private のままだと帰り道で迷子
    192.168.0.1 ─往路→ 198.51.100.2
    192.168.0.1 ←誰?─ 198.51.100.2
  • NAT G/W を挟むことで Private からも往復できる
    192.168.0.1 ─往路→ NAT G/W 203.0.113.3 ─FORWARD + SNAT→ 198.51.100.2
    192.168.0.1 ←復路─ NAT G/W 203.0.113.3 ←復路─ 198.51.100.2

通信内容を限定すれば、それだけプロキシを通したり、特定の AWS サービスだけ VPC Endpoint を使ったり、することで Private からでも外部通信と等しいことが可能ですが、限定せずに外部通信するには NAT G/W が便利であり、必須ではないんだけど、利便性を考えるとほぼ必須に近い存在となります。


通信の方向と費用形態を知る

さきほど例として出した『WEBサーバーは Private であるべき』かは、外からリクエストを受ける GlobalIP はロードバランサーが担当し、バックエンドとなるWEBサーバーには必要ない、という意味では正しいものです。

しかし、現代のシステムは様々な処理を行うため、機能としては十分でも最適化においてはベストではないかもしれない、と考えるのは通信と費用に種類があるからで、ここでは4つの通信種類があることを復習しておきます。

Request INPUT

わかりやすく WEB サーバーで考えた時、インターネットの不特定多数から発される HTTP(S)リクエスト がこれにあたります。受けるためには PublicIP / ElasticIP が必要で、AWS においてはこの INPUT データ転送費用は無料となっています。

なぜ無料かは推測になりますが、大きく2点考えられます。1つはユーザーリクエストの容量で、コンテンツのアップロードを除けば多くはヘッダのみであるため平均的に微量であるからです。

もう1つはシステムとして機能するための最低限必要な通信種類ということで、ここが無料でないと気軽に利用してもらえないだろうという損して得取れな話で、それに似た志向の仕組みも他にあるため後述します。

Response OUTPUT

外から受けたリクエストを処理したら、その多くはコンテンツを含むレスポンスを返します。HTML や JSON だったり、画像や動画など色々ありますが、その容量は KB, MB 単位あたりまで様々です。

このデータ転送費用は有料で、東京リージョンなら USD 0.114/GB 以下となっています。

動的に生成するコンテンツは圧縮率が有効な内容なら圧縮して返したり、静的コンテンツやキャッシュ可能なものは CDN を通すことで、速く安価にしようと工夫するところです(話がそれるので割愛)。

Request OUTPUT

サーバー自身がインターネットに向けて送信するリクエストで、さきほども書いた通りパッケージのダウンロードや外部API の実行、容量が大きなところでは何かしらのコンテンツのアップロードがこれにあたります。

性質は違えど費用は Response OUTPUT と同じ USD 0.114/GB 以下 ですが、これは PublicIP を持っている場合の話です。PublicIP を持たない場合は NAT G/W を通す必要があるため、往路に追加で USD 0.062/GB かかることになります。

微量な外部処理のために NAT G/W を置くには存在そのものが高く、大容量の転送をするには追加のデータ転送費用が重くのしかかってくる箇所のため、気をつけないと容易く Evil なパーツになるので、どのような通信内容と量が通るかは可能な限り把握しておきたいところです。

Response INPUT

サーバー自身が外へ出したリクエストのレスポンス、つまりダウンロードがこれにあたります。

PublicIP を持てば INPUT なので無料、持ってなければ NAT G/W を通って返るので USD 0.062/GB となります。そう、NAT G/W は送受信どちらにも同じ金額がかかるってところがテストに出るミソです。

大きなアップロードの処理ならレスポンスはおそらく小さい成否結果だけですし、逆に外からのダウンロードだとここが大きくなるところで、今だとコンテナイメージや Git データあたりがそれに当たりやすそうです。

常駐サーバーでやっていた定期的なジョブ処理を、良かれと思ってコンテナでのスケジューリング化したら、毎回 NAT G/W 経由でイメージのダウンロードをして── って考えると、その頻度次第では結構な費用になりそうなので、最適化が必要じゃないですか?って感じが1つの例です。

最適化は難しい (1)

WEBアプリケーション・サーバーが、リクエストを受けて様々な処理をする中で、全てが Private Network 内で完結する処理ならば PublicIP など不要で、Private に置くことが正となります。しかし最近のシステムは、その1つのリクエスト処理中もしくは非同期に、外部へログを送信したり、外部API を実行したり、起動のたびにイメージやデプロイのダウンロードが必要だったりと、自己で完結しない処理になることが多いです。

そのデータ通信量によっては、必ずしも Private に置くことが最適であるとは限らず、PublicIP の INPUT 無料を活用することや、それ以外の安価にするための手段の認識と検討をする必要がでてきます。

この辺りの最適化はやや難しい話で、アプリケーションの開発中にその整理整頓をすることは少なく、リリース後に運用中のメトリクスなどを見てから構成変更などの最適化をすることが多いでしょう。そしてそのメトリクスは Network INPUT / OUTPUT Bytes のような形で確認できますが、送信元の区別はないため、先ほど復習した4種類の判断は不可となります。

VPC 内のリソースを流れるパケットの、送信元・宛先、IPv4・IPv6、ポートやプロトコル、AZ内 or AZ間、そしてそれらの容量の傾向は、となると調べられないわけではないですが、お手軽な方法はおそらく無いため、ネットワーク含めたリソース構成の最適化に手を出すことは、それなりの理解度と調査力を必要とすることになります。


IPv6 の特徴を知る

基礎の振り返りが終わったところで IPv6 を仲間に加えて場を荒らしていきましょうそうしましょう。

IPv6 はグローバル

VPC で割り当てる IPv6 はグローバル・ユニキャスト・アドレスなので、インターネット上で一意な存在です。そのため IPv4 とは事情が全く異なってきます。

AWS では無料で割り当てられ、IPv6 単体での利用は難しいため、活用するなら PublicIPv4 / PrivateIPv4 と並行して利用することになり、IPv6 ありきでしかできない最適化も検討できるようになります。

IPv4 で Public / Private の区別があったところも、IPv6 を割り当てるとどちらもグローバルアドレスを持つことになるので怖そうに見えるかもですが、常日頃から SecurityGroup で最小限の開放に留めていれば特にリスクはなく、メリットだけを享受することができます。

IPv4 と互換性がない

扱いが難しい最たる理由がこれで、IPv4 と互換性がありません。

これはどういうことかというと、自分が IPv6 を持っていても相手が IPv6 を持っていなければ IPv6 で通信することはできませんし、逆に相手が持っていても自分に無ければやはりできません。

また、OS としても IPv6 を扱えるように設定する必要がありますし、IPv4 と IPv6 どちらを優先して扱うかといった設定も存在し、それに関わる成否も無くはないです。

そして肝心の世の中的には、大きな企業・プラットフォームなどの多くは IPv6 対応をしていますが、中規模以下だとまちまちですし、なにより AWS 自体が全てのサービスに対応しているわけではなく、各サービスの API Endpoint も全く十分とは言えない状態です。

基本的に *.amazonaws.com は IPv4用、*.api.aws が IPv4/6両用(デュアルスタック)で、多くのサービスやアメリカの主要リージョン以外は非対応です。そのため、Private Subnet で IPv6 を持っても、実質的に IPv4 での外部通信が必須、つまり NAT G/W が必須、という流れで NAT G/W 不要構成にする障壁の1つとなっています(と、自分は感じている;-(

Egress-Only Internet Gateway (EIGW) を知る

PublicIPv4 が外へ出る時は IGW から出ていく Routing にしていますが、IGW は IPv6 でも出ていけるので、::/0 も IGW へ Routing 可能です。

Private Network で IPv6 を持った場合、Egress-Only Internet Gateway (EIGW) を通して外に直に出ることが可能です。宛先が IPv6 を持っていればという条件付きになるため、IPv4 のみなら NAT G/W が必要となり、情勢的にやはり NAT G/W が必要となる要因の1つです。

しかしながら EIGW の存在は IGW 同様に無料で、データ転送費用も IGW 同様 EC2 費用ページを参照するように指示されているため、INPUT 無料・OUTPUT 有料となります。これを活用すると、IPv6 でのインターネットからのダウンロードが無料になるため、IPv4 で NAT G/W を通していた通信のコスト削減する可能性を秘めています。

最適化は難しい (2)

アプリケーションが外部通信を必要としたとして、その宛先を整理し、それぞれ IPv4 / IPv6 の所有と通信量を踏まえて、IPv6 対応するのか NAT G/W を排除できるのか、を検討するのはなかなかに骨が折れる話です。

AWS API を叩くにしても、リソース自身が IPv6 対応しているのか否か、サービスが IPv6 対応しているか否かで、API Endpoint を自動切替するってのは、コーディングするだけとはいえぼちぼち面倒な作業です。

極端に言えば世の中が IPv6 全対応すれば、ちまちました外部接続のためにお高い NAT G/W を置く必要はなくなるし、全てのリソースが自動的に IPv6 をプライベートDNSで名前解決すれば、IPv4 もいらないでしょ。みたいな妄想を始めてしまうのが、実情です;-)


節約用の通信経路

ここまでで、基本構成とその経路について確認してきました。処理内容によってはその基本のままだとコスト的に不利になる場合があるため、美味しい選択がいくつかあることを知っておく必要があります。


IGW / EIGW から S3 / DynamoDB への送信

データのストレージへの保存は、アプリケーションにおける肝ですので、S3 や DynamoDB へのインターネット経由でのデータ転送は無料になっています。本来は有料である Request OUTPUT の部分が、ということになります。

Private からだと、通常は NAT G/W を経由することになるため、その分のデータ転送費用が上乗せされることに注意が必要です。

S3 からの OUTPUT は、1ヶ月100 GB までは無料で、それ以上は有料なので、ダウンロードもゴリゴリするような処理だと注意が必要な箇所になります。

Gateway Endpoint の S3 / DynamoDB

そしてこの2つのサービスに限り、Private での NAT G/W 経由による課金を発生させないために、Gateway Endpoint という仕組みが存在します。これ自体の存在やデータ転送は無料です。

Gateway Endpoint を作成して、Routing に宛先が マネージドプレフィックスリスト (S3 や DynamoDB) の場合に VPC Endpoint (vpce) へ向かわせるだけで利用できるので、Terraform などでコード化してしまい、それを使うかどうかに関わらず用意してしまうのが得策でしょう。

PrivateLink Interface の各サービス

AWS の各サービスを利用する際に、Public からの OUTPUT や、Private からの NAT G/W 経由 INPUT / OUTPUT の容量が大きい場合に、データ転送費用が高騰しがちになります。というか、細かく見る人がいないと、それが普通であって高騰であると気付けないかもしれない箇所です。

もし特定のAWSサービスの利用において、データ転送容量が大きいとわかっている場合は、PrivateLink の Interface Endpoint を使うことでコスト削減できる可能性があります。

なぜ安くなるかというと、シンプルにデータ転送費用が $0.01/GB と格安だからです。NAT G/W の 1/6 以下なので、容量次第ではかなりの効果を見込めます。

ただし、その存在自体にも費用がかかることと、サービスごと・AZごとに必要となるため、存在以上のデータ転送による削減をできないとマイナスになりますし、リソース管理も煩雑になってしまいます。

なので本番とテスト環境はできるだけ同じ構成にしたいところとはいえ、データ転送の少ないテスト環境では PrivateLink を使わない、といった細かい節約も考えられます。

PublicIP

2月から $3.6/月 と有料になった PublicIP とはいえ、INPUT が無料であることに変わりはありません。

自身から外部へ出すリクエストのデータ転送は、アップロード(OUTPUT) よりもダウンロード(INPUT) の方がサイズが大きいことが多いので、NAT G/W から PrivateLink に中途半端に変えるよりも、PublicIP にした方がシンプルかつ安いこともあります。

データ転送による費用が高騰する時は、月額数百~数千ドル単位以上になるので、PublicIP 20個台までなら百ドル未満と考えれば、その通信内容を精査して検討する価値は十分にあると言えます。


創意工夫のコスト削減

ここまでの内容でも調査と考察をできれば、わりと最適化に向かえますが、ネットワーク周りにおいてさらにどういった小賢しい工夫が考えられるかを楽しんでいきます。

CostExplorer で費用確認

まずは何に多く料金が発生しているかを確認するために、CostExplorer のグループ化で「使用タイプ」にしつつ、「使用タイプ」フィルタで下記の名前あたりで絞り込むと、今回の内容に関連したものに絞れます。

  • *-DataTransfer-Out-Bytes
  • *-DataTransfer-Regional-Bytes
  • *-NatGateway-Hours, *-NatGateway-Bytes
  • *-PublicIPv4:InUseAddress
  • *-VpcEndpoint-Hours, *-VpcEndpoint-Bytes

名前からサービスがわかりづらいので、上記で絞りつつグループ化を「サービス」にすると、どこで多く使われているかわかるので、それから金額順に1つ1つサービスを絞って確認するとよいです。

おそらく CDN が CloudFront ならそれが飛び抜けていて、本件はそれ以外の話になるため、金額的にはチマチマしているように見えるかもですが、構成を変えるだけで月額数千ドルを減らせるなら年間で百万円以上削れるし、くらいの気持ちでお宝探しをしましょう。

怪しいとか許容できなさそうな数字を見定めたら、その該当リソースのメトリクスを確認しにいき、その通信の容量や往復路といった性質を整理して、最適化できないか検討するゲームの始まりです。

節約経路を活用する

さきほど整理したいくつかの経路を踏まえつつ、現行の構成と通信の流れとを比較して、まずはザックリと変更した方が安価になり特に悪影響はないと判断できれば、その効果と手順を整理していきます。

この調査がやや難しく、ネットワーク費用に影響する意味での内容整理は、仕組みの要素を正しく把握していないと漏れが生じやすいところです。把握漏れがあると、変更後に想定外の箇所で逆に高くなる場合もあります。

ほぼ最適化して大丈夫と判断しつつも、その調査の難しさから、把握漏れがあることを想定し、変更後のメトリクス変化のチェックを怠らず、1~2日後に反映される CostExplorer のチェックもすることで、もし漏れがあった場合も早めに対処できるような運用にするとよいです。

IPv6 EIGW を活用する

Private において IPv6 を有効にすると、外部への通信は EIGW を通って出ていけるので、宛先が IPv6 を持っていれば NAT G/W を通る必要がなくなります。

そしてインターネットからの INPUT は無料なので、ダウンロードを無料にできるのですが、如何せん AWS 内のサービスでも、サイズが大きくなりがちなイメージやビルドを扱う箇所では今のところはそれを狙えないようになっています。

単純に IPv6 非対応であったり、処理をするリソースが Public なアドレスを持てないとかで、NAT G/W やプロキシ等が必須になる仕組みであったりするからです。これが狙ってケチなのか、開発が追いついていないだけなのかは不明です。

それでも AWS 以外も含めて一部の処理だけでも NAT G/W を通らなくできれば最適化へ歩み寄れるので、IPv6 を活用する方向に寄せていくのは良いことだと思われます。

極小サイズの EC2 NAT G/W

NAT G/W がほぼ必須だとして、丁寧にやると AZ間のデータ転送を発生させない&冗長化のためにも、AZ数と同じ数だけ作成することになります。

存在自体が $0.062/h なので、30日間3AZ とすると $134/月 になり、なかなか地味に財布を絞り上げてくる金額です。しかもこれを、複数ある VPC ごとにってなると、財布に穴が空いているような気持ちになりかけます。

なのでいったん NAT G/W は欲しいけど、たいしたデータ転送量が通るわけではないし、拡張性もいらないし、EC2 Auto Recovery 程度の耐久度があればイィやって想定にした時に、自前で NAT G/W を用意する手段が考えられます。

オンプレ時代からネットワークを触っている人にとってはお手の物なヤツです。馬鹿正直にマネージドかつ Multi-AZ 配置にせず、最小インスタンスかつ Single-AZ にすることで、たった数ドル/月 で機能を満たすことができます。

CPU も Memory も Network もほとんどパワーを必要としないので、ちょっとインスタンスを構築して Routing を普段と変えるだけで、安くお手軽に実現できるため、その VPC 内リソースの重要度を踏まえて検討すれば、開発系環境の数をこなすことでチリツモ削減ができるかもしれません。

Single-AZ でAZ 間データ転送をカット

昨今のシステムは冗長化に対応していて、Multi-AZ に配置することでダウンタイムを最小に抑えることを正とします。

でも例えば社内専用のシステムだと、データの保全はしていても、WEB・アプリケーション層はあえてシングルポイントで動かしていたり、など色々な構成があるはずです。

大きな容量を扱うシステムは役割をノードで分けていたりすることがあり、それをなんとなく複数の AZ に分けて配置していると、AZ間の通信が発生して少なくないデータ転送費用になる場合があります。管理画面WEBサーバーが 1a で、ストレージ系やビルド処理が 1c だと、リクエストは 1a で受けるのにデータ生成は 1c でされて、1c → 1a へのコンテンツ転送が発生する、という感じ。

それが必要な配置ならよいのですが、実はそうではない場合、1つの AZ に集約することでリージョン内AZ間データ転送費用を排除し、かつ処理時間の短縮が見込めます。なんでもかんでも Multi-AZ っぽくしたら良いわけではない、というお話でした。

圧縮率の調整

これは太古昔からの工夫で、主にユーザーへの Response OUTPUT のコンテンツは圧縮して返すことで、データ転送量を減らそうというものです。

特に平文コンテンツは有効なので、非圧縮から圧縮にしたり、圧縮率を調整して最適化します。容量が小さくなる代わりにサーバーでの圧縮処理とクライアントでの解凍処理のCPUパワーを必要とするので、サイズ縮小と合わせると処理全体としては時間短縮になるかどうかは内容次第です。

この辺は最近久しぶりに調べることがあったので、気が向いたら別記事にまとめるかもしれません。


おわりに

少しだけと言っておきながら、結局いつも通りの悪い癖で長編となりましたが、これでも範囲を意識的に絞っているので、それくらい面倒くさいジャンルで実は知ることやるべきことが多いということで、学習教材としては十分な湯加減だったと思われます。

ネットワーク周りの最適化が難しい理由は、その技術知識や調査力以外にもあり、1つはリリース前のアプリケーションでの判断と適用がしづらいことです。

仕組みの把握や負荷試験をしたとしても、通常はそのキャパシティや品質に問題がないかの確認までであり、経路や容量によるコストにまでその段階で気を配ることは難しいです。また、開発の〆切直前は変更を切り出せるような余力も少なく、最初に設計・構築されたそれが、いったんのベストであると扱われがちなため、その時点で一定以上の地力をつけておきたいところ。

もう1つはリリース後・運用期の話で、ネットワークに対する本音としては、誰もができれば動かしたくない箇所です。最適化の変更をするにしても、オンラインで出来るのかできないのか、その効果とリスクはどの程度なのか、などを整理していった時に、その方面の内容を正しく理解して納得できる人材が少ない場合、なかなかズバッと進行することが難しいジャンルでもあります。


逆に自信もって進行できる人材が豊富ならば、そう難しさや怖さを感じずに、やればいいじゃんってナチュラル進行できる場合も多いので、

最初から全てを最適化することは難しくても、途中からの最適化ができれば万事めでたしということで、スムーズにそうなるための基礎を身につけた人材が増えると嬉しいですね:-)