こんにちは。SmartHRで文書配付機能の開発しているプロダクトエンジニアのkekkeです。 私が所属しているチームではインフラにGoogle Cloudを採用しており、ウェブ アプリケーションをCloud Run 上に構築して外部へのアクセスはCloud NATを経由して行っています。 この記事ではCloud RunとCloud NATを組み合わせた時の「インスタンスあたりの最小ポート数」の適正値について調査した内容を紹介します。
背景
ある日Cloud NATのVMあたりの使用ポート数が増加して、このままだとCloud Runから外部にアクセスできなくなってしまうため対策を打つ必要がありました。 Google Cloudのドキュメントを確認したところ「インスタンスあたりの最小ポート数」を上げることで解決することがわかったのですが、以下のような疑問が生まれチーム内では腑に落ちない雰囲気を感じました。
- 使用ポート数の上限値を設定したいからどちらかというと「最大ポート数」なのでは?なぜ最小なの?
- Cloud Runってそもそもサーバレスだからインスタンスはないのでは?
そこで「インスタンスあたりの最小ポート数」とはなにか調べ、そしてCloud RunとCloud NATを組み合わせた時の「インスタンスあたりの最小ポート数」の適正値はどのように判断するのか調べて記事に残すことにしました。
この記事を読むとどうなる?
- Cloud NATの「インスタンスあたりの最小ポート数」とは何を意味するのか理解できる
- Cloud RunとCloud NATを組み合わせた時の「インスタンスあたりの最小ポート数」の適正値を判断できる
前提条件
私が所属しているチームの環境を前提としています。
- Cloud Run から Cloud NAT を使用するために、 Serverless VPC Access コネクタを使用
- Cloud NAT は静的ポートの割り当てを使用
- Google Cloud としては動的ポートの割り当てが推奨されていますが、動的ポートの割り当てはパケットドロップのおそれがあり、さらに Cloud Run はこのパケットドロップへの対処法がないため、やむなく静的ポートの割り当てにしています。
- 参考: Cloud NAT | 動的ポート割り当てが構成されているときにパケットがドロップされる
- NATゲートウェイに設定する NAT IP は一つ
- ポートの枯渇の対策として NAT IP を増やす方法がありますが、私のチームの場合IPアドレスを増やすことでどのような影響があるのか調査に時間がかかりそうだったため、NAT IP 一つという制限で調査しました。
- 参考:Cloud NAT | 追加の IP アドレスを割り振る必要がある
先に結論
前提条件下では、次の結論になりました。
- Cloud NATの「インスタンスあたりの最小ポート数」とは何を意味するのか?
- 一つのNAT IPアドレス当たりのVM1台に利用できる固定のポート数になる
- Cloud RunとCloud NATを組み合わせた時の「インスタンスあたりの最小ポート数」の適正値の判断基準
- モニタリングで確認した1VMあたりの最大使用ポート数を上回らない2のべき乗(64、128、256…)を設定する
- 一つのNAT IPアドレス当たりの「インスタンスあたりの最小ポート数」は最大4096まで設定しても枯渇は起きない
- Serverless VPC Access コネクタが最大10台までしかスケールアウトしないため
- 4097以上に設定する場合はNAT IP アドレスを一つ追加する方が安全
- 4097以上にすると2の累乗に切り上げられて8192と設定されるため
そもそもNATとは?
NATとはローカルなネットワークでプライベートIPアドレスを使用し、インターネットへ接続するときにグローバルIPアドレスへ変換する技術です。さらにポート番号も付け替えるNAPTが登場したことで、1つのグローバルIPアドレスで複数のホスト間の通信が可能になりました。現在はNATといえばNAPTのことを指すことが多いです。
以下はNAPTのイメージ図です。
参考
- NATとは|「分かりそう」で「分からない」でも「分かった」気になれるIT用語辞典
- マスタリングTCP/IP―入門編―(第6版) - 5.6 NAT
Cloud NATとは?
ではCloud NATについて公式ドキュメントを確認してみます。
Cloud NAT(ネットワーク アドレス変換)を使用すると、外部 IP アドレスを持たない特定のリソースからインターネットへの送信接続が可能になります。
Cloud NAT ゲートウェイは、VM から送信されたパケットに対して送信元ネットワーク アドレス変換(送信先 NAT または SNAT)を実行するときに、パケットの NAT 送信元 IP アドレスと送信元ポートを変更します。
これはNAPTの説明になりますので以降はNAPTである前提で話を進めます。
Cloud NATのポート割り当てについて
Cloud NAT は NAPT ということなのでポートを利用することで一つのグローバルIPアドレスで複数のホスト間通信が行えます。 では、Cloud NATではどのようにしてポートが割り当てられるのか公式ドキュメントを見ながら確認していきます。
NAT IP アドレスはリージョンの外部 IP アドレスで、インターネット上でルーティングが可能です。
Cloud NAT はNAT IP アドレス(グローバルIPアドレス)を設定することができます。
Cloud NAT ゲートウェイの各 NAT IP アドレスは、64,512 個の TCP 送信元ポートと 64,512 個の UDP 送信元ポートを提供します。TCP と UDP はそれぞれ IP アドレスあたり 65,536 個のポートをサポートしていますが、Cloud NAT は先頭の 1,024 個の既知(特権)ポートを使用しません。
NAT IP アドレス一つにつき、送信元ポートの変換に利用できるポート数は64,512 個です。 この64,512 個の中から、VM1台に利用するポート数を予約します。
静的ポートの割り当て
次にポートの割り当てについて説明していきます。 前提条件で述べた通り、ポートの割り当て方法は静的ポートの割り当てを採用しています。 ※動的ポートの割り当てについては割愛します。
静的ポートの割り当てを構成する場合は、VM インスタンスあたりの最小ポート数を指定します。 すべての VM に同じ数のポートが割り当てられるので、すべての VM のインターネット使用量が同様ならば、静的ポートの割り当てが最適です。
「インスタンスあたりの最小ポート数」に設定された数がVM1台に利用できる固定のポート数になります。
割り当てられるポート数が固定なので、64,512 / インスタンスあたりの最小ポート数
の計算で一つのNAT IPアドレスでサポート可能なVM数も算出できます。
参考: ポートの予約 | IP アドレスとポート | Cloud NAT | Google Cloud
以下は最小ポート数を 4,096 に設定した時の計算例です。
(1 NAT IP アドレス) × (アドレスあたり 64,512 ポート) ÷ (VM あたり 4,096 ポート) = 15 VM
除算の小数点以下を切り捨てになります。
除算の結果は、最も近い整数に切り捨てます。除算の小数点以下を切り捨てます。
例えばVM2台、インスタンスあたりの最小ポート数が64の場合、
- 64,512 個のうち128個(VM2台✕64)のポートを利用
- VMは最大1028台(64,512 個 ÷ 64個/VM1台)までサポート
となり、以下のような構成イメージになります。
Cloud NATの「インスタンスあたりの最小ポート数」とは何を意味するのか
前述の通り、一つのNAT IPアドレス当たりのVM1台に利用できる固定のポート数になります。
Cloud NAT は設定された「最小ポート数」より多くポートを割り当てる場合があります。 たとえば「最小ポート数」が2の累乗じゃない場合は切り上げられます
- 128を設定した場合 -> 128ポートが割り当てられる
- 129を設定した場合 -> 256ポートが割り当てられる
参考: ポートの予約手順 | IP アドレスとポート | Cloud NAT | Google Cloud
「少なくとも設定されたポート数よりは多くポートを割り当てますよ」という意味で「(ユーザーが割り当てたいと思ってる)最小ポート数」となります。
Cloud RunとCloud NATを組み合わせたときの構成
こちらも公式ドキュメントを見ながら確認していきます。
サーバーレス VPC アクセスを使用すると、Cloud Run、App Engine、Cloud Functions などのサーバーレス環境から Virtual Private Cloud(VPC)ネットワークに直接接続できます。
Cloud Runはサーバレスなので、Cloud NATを利用する場合サーバーレス VPC アクセスが必要となります。
サーバーレス VPC アクセス コネクタは、コネクタ インスタンスで構成されています。
つまり、コネクタインスタンスが「インスタンスあたりの最小ポート数」に影響するVMになります。
コネクタに許可されるコネクタ インスタンスの最小数と最大数を設定できます。最小値は 2 以上にする必要があります。 サーバーレス VPC アクセスは、トラフィックが増加すると、コネクタ内のインスタンス数を自動的にスケールアウトします。
コネクタインスタンスは最小2台,最大10台のオートスケールが可能です。 トラフィックが増加によってスケールされますが、それ以上詳しい仕様については明記されていませんでした。
以下はCloud Run と Cloud NAT を組み合わせた時の構成イメージです。
Cloud RunとCloud NATを組み合わせた時の「インスタンスあたりの最小ポート数」の適正値はどう判断するか
前提条件下で話を進めます。
一旦Cloud Runのことは忘れてCloud NATに設定する「インスタンスあたりの最小ポート数」の適正値ついて考えてみます
Cloud NAT の主要なリソースは外部 IP とポートのペアです。インスタンスが最大ポート使用率に達すると、インターネットへの接続が切断される可能性があります Cloud Monitoring では、次のサンプル MQLクエリを使って Cloud NAT のポート使用率を確認できます。
まずCloud NATの直近の1VMあたりの最大使用ポート数をモニタリング等で確認します。
Cloud NAT ゲートウェイは、前のステップで特定した VM インスタンスごとに指定または調整された最小ポートを使用して、VM に割り当てる NAT 送信元 IP アドレスと送信元ポートのタプルの数を計算します。 Cloud NAT は、NAT 送信元 IP アドレスと送信元ポートのタプルの数を、2 のべき乗を使用して、NAT 送信元アドレスと送信元ポートのタプルが最小ポート数以上になるように、指定した VM インスタンスごとに割り当てます。
直近の1VMあたりの最大使用ポート数がわかったらその数値を上回らない2のべき乗が「インスタンスあたりの最小ポート数」の適正値となります。
例えば、直近の使用ポート数が最大3000ポートだった場合4096に設定しておくと安全です。
では、できるだけ大きな値に設定しておけばいいのではと思いますが、VMインスタンスのサポートできる台数に上限があるためむやみに大きな値にはできません。
再掲となりますが1つのNAT IP アドレスに利用できるポート数は64,512 個となり以下の計算式により使用可能インスタンス数を計算できます。
使用可能インスタンス数 = 64,512 / インスタンスあたりのポート数
例えば「インスタンスあたりの最小ポート数」を4096に設定した場合、
使用可能インスタンス数 = 64,512 / 4,096 = 15
台
までのサポートになります。
ここで Cloud Run について考えてみます
VPCコネクタは最大で10台までスケールアウトすることを説明しました。 前述の通り、「インスタンスあたりの最小ポート数」を4096に設定した場合は15台までサポートできるため問題ありません。
次のべき乗である8192に設定した場合、
使用可能インスタンス数 = 64,512 / 8,192 = 7
台となり10台のVPCコネクタはサポート不可となります。
つまり、使用台数が8台以上になるとポートが枯渇し外部へのアクセスができなくなります。
もし「インスタンスあたりの最小ポート数」を8192ポート以上に設定したい場合はNAT IPアドレスの追加する方が安全です。
参考:Cloud NAT | 追加の IP アドレスを割り振る必要がある
以下はCloud Run × Cloud NAT(静的ポートの割り当て)でインスタンスあたりの最小ポート数を4096に設定した場合の構成イメージです。
結論
先に結論を参照
最後に
この記事ではCloud RunとCloud NATを組み合わせた時の「インスタンスあたりの最小ポート数」の適正値について説明してきました。弊社のプロダクトの環境を前提とした内容となりますが、少しでも参考になれば幸いです。
We are hiring!
Google Cloud の運用・改善を行いながら開発ができるSmartHRで一緒に働きませんか!? SmartHRではエンジニアを大募集しています! 詳しくは以下を御覧ください!