0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Regional NAT Gateway の展開・縮小・切り替えを実測した

0
Last updated at Posted at 2026-09-02

こういう場面で読んでもらえたら、と思って書きました。

  • zonal NAT から regional NAT への切り替え作業を計画していて、メンテナンスウィンドウを何分申請すればいいか決められない
  • AZ を追加する手順書に「NAT の展開を待つ」と書いたものの、そこに何分と書けばいいか分からない
  • 切り替えで通信が止まるのか、止まるなら何秒なのかを、上司や顧客に説明する必要がある
  • regional NAT をもう使っていて、AZ が勝手に増減する挙動を把握しておきたい

どれも公式ドキュメントを読んだだけでは答えが出ません。そこで実際に作って壊して測りました。

公式ドキュメントを読んで手が止まることがあります。書いてあることは正しいけれど、それだけでは設計判断ができない、という止まり方です。

It may take your regional NAT Gateway up to 60 minutes to expand to a new Availability Zone

最大60分。これが5分なのか55分なのかで、AZ を増やす作業の段取りがまるで変わります。手順書に「NAT の展開を待つ」と書くとして、そこに何分を見積もればいいのか。

This will reset your existing connections. We recommend that you complete these steps in your maintenance window.

既存の接続がリセットされる。秒数がない。 メンテナンスウィンドウを30分取るべきなのか5分でいいのか、この一文からは決められません。

AWS の発表ブログには「平均15〜20分、最大60分」という数字もあります。ただし平均は母集団の話で、目の前の1回がどちらに転ぶかは分かりません。だったら自分で測るしかない、というのがこの検証の動機です。

ap-northeast-1 で実際に作り、壊し、測りました。この記事は Terraform の知識をほとんど必要としません。 測っているのは AWS 側の挙動そのものです。

測った結果

  • 展開時間のばらつきが大きい(検知まで 42秒 のときと 9分21秒 のときがあった)。平均値で手順書を書けません
  • 縮小は展開より遅く、最大53分52秒かかりました。公式は縮小の所要時間に一切触れていません
  • ルート切替では新規接続が1度も落ちませんでした。切れるのは既存接続だけ(6回中6回)
  • 一方 availability_mode を書き換えると160秒止まりました。同じ切り替えが、やり方で 0 と 160秒 に分かれます
  • AZ 展開のトリガは「ENI の存在」で、アタッチしていない ENI 1個でも発動します

測り方

private サブネットに置いた t3.micro から、2本立てで測りました。

  • 新規接続: https://checkip.amazonaws.com を約1.2秒間隔で叩き続ける(返り値が送信元グローバル IP なので、通ったかとどの NAT を通ったかが同時に取れる)
  • 既存接続: S3 の 64MiB オブジェクトを --limit-rate 64k で1本ダウンロードし続ける

NAT の状態そのものは手元から describe-nat-gateways を5秒間隔でポーリングしました。NAT が落ちている間もこれだけは生き残るので、測定の正本にしています。

環境は ap-northeast-1 / AZ は 1a と 1c / Terraform 1.9.4 / AWS プロバイダ 6.62.0 / aws-cli 2.35.6 です。

1. AZ 展開は「ENI の存在」で起きる。EC2 は要らない

公式にはこう書かれています。

the regional NAT gateway detects the presence of an network interface(ENI) in that Availability Zone and automatically expands to that zone

検知するのは ENI であって、EC2 の起動とは書いていません。 そこで、アタッチしていない ENI を1個だけ置いて試しました。

resource "aws_network_interface" "trigger" {
  subnet_id       = aws_subnet.private_c.id
  security_groups = [aws_security_group.probe.id]
}

これだけで展開しました。 ENI は課金されないので、展開の検証は EC2 を立てずに何度でも試せます。ここが分かった時点で、この日の検証計画が組み直せました。

裏を返すと運用上の注意になります。使っていない ENI が1個あるだけで、regional NAT はその AZ へ広がります。 削除済み Lambda の ENI が残っている環境では、意図しない AZ に広がる可能性があります。

2. 展開時間は「最大60分」としか書けない理由

公式ユーザーガイドは「最大60分」としか書いていませんが、AWS の Regional NAT Gateway 発表ブログには「平均15〜20分、最大60分」という数字があります。ただし平均は個々の作業の見積もりには使えません。実際に2回測りました。

ENI 設置 → associating associatingsucceeded 合計
1 9分21秒 6分24秒 15分45秒
2 42秒 6分38秒 7分20秒

前半が13倍違います。一方、後半(IP を確保して有効化する実処理)は 6分24秒 と 6分38秒 でほぼ一定でした。

ばらついているのは AWS が「その AZ に ENI がある」と気づくまでの検知時間。実処理ではなく検知が読めない、という構図です。

展開は2段階である

これも公式には書かれていません。describe-nat-gatewaysNatGatewayAddresses を見ると、

  1. まず AZ が一覧に現れる(Status: associatingPublicIp は無い)
  2. 6〜7分後に Status: succeeded になり、IP が確定する

AZ が一覧に出た時点ではまだ使えません。 監視で「AZ が出たら完了」と判定すると早合点します。succeeded を見てください。

結論: 平均値で手順書を書かない

実測が 7分20秒 と 15分45秒 に割れた以上、だいたい10分で終わる、と書いた手順書は危険。 公式の「最大60分」という書き方のほうが正しい。AZ 追加を伴う段取りは最悪値で見る。

3. 縮小は展開より遅く、最大53分52秒かかった

公式は縮小についてこう書くだけで、所要時間に一切触れていません。展開には "up to 60 minutes" があるのに、縮小には上限すら書かれていない。

the NAT Gateway contracts from the Availability Zone that has no active workloads

ENI を削除して2回測りました。

ENI削除 → disassociating disassociating → 消滅 合計
1 20分01秒 6分42秒 26分43秒
2 47分22秒 6分30秒 53分52秒

2回とも展開より遅い。そして展開とまったく同じ構造で、後半はほぼ一定、前半が2.4倍ばらつく。

4回測って見えた構造

展開2回と縮小2回、合わせて4回ぶんを前半と後半に分けて並べます。

測定 前半(AWS が気づくまで) 後半(実処理)
展開1回目 9分21秒 6分24秒
展開2回目 42秒 6分38秒
縮小1回目 20分01秒 6分42秒
縮小2回目 47分22秒 6分30秒
範囲 42秒 〜 47分22秒。実に68倍 6分24秒 〜 6分42秒。ほぼ一定

後半は4回とも6〜7分に収まっています。AWS 側の実処理は驚くほど安定している。

読めないのは前半、つまり ENI が増えた/減ったことに AWS が気づくまでの部分だけ。68倍の幅があります。

これが「最大60分」の正体だと考えています。実処理は数分で終わるが、検知がいつ走るか分からない。だから上限でしか書けない。

展開と縮小は非対称です。 AZ を増やしても展開までは使われず、AZ から抜けても NAT は残り続けます。縮小のほうが遅いので、「使っていない AZ の NAT がいつまで残るか」のほうが読みにくい。スケールイン・アウトを繰り返す構成では、ここが効いてきます。

4. 切り替えで何秒止まるのか

公式は「既存の接続はリセットされます。メンテナンス時間に実施してください」と書いていますが、秒数がありません。

zonal NAT と regional NAT を並走させ、private サブネットのルートだけを張り替えて、3往復(切替6回)測りました。

対象 結果
新規接続 全1,639試行中 失敗 0回
既存接続 6回中6回とも切断(curl 終了コード 56)
切断までの遅れ 中央値 約1.9秒(範囲 0.30〜5.99秒)
切断後の再確立 1.7秒

新規接続は一度も落ちませんでした。隣り合うサンプルの間で、出口 IP だけが入れ替わっています。

2026-09-01T12:41:15.4Z,200,0,0.209,203.0.113.11   ← zonal NAT の IP
2026-09-01T12:41:16.6Z,200,0,0.211,203.0.113.20   ← regional NAT の IP

(IP は掲載用に置き換えていますが、2つが別アドレスである点はそのままです)

ただし「0秒」とは書けません。 約1.2秒間隔で叩いているので、正しくは「1.2秒の分解能では断を検出できなかった」です。

一方、64MiB をダウンロード中の接続は毎回切れました。

12:41:19.055,broken,56,19535322   ← 18.6MB 転送した時点で切断
12:41:20.742,start                ← 1.7秒後に再確立

実務上の結論

メンテナンスウィンドウの設計で効くのは「切替の所要」ではなく「そのシステムが持っている接続の寿命」です。

  • HTTP API のように短命な接続しかない → 窓はほぼ要りません
  • 大きなダウンロード、DB セッション、WebSocket がある → そこだけが対象

公式の「メンテナンスウィンドウで実施せよ」は正しい。ただ理由が「切替に時間がかかるから」ではなかった。ここは測るまで逆に理解していました。

冒頭で引っかかっていた「戻せるのか」について

行き(zonal→regional)と戻り(regional→zonal)で、挙動に差はありませんでした。 新規接続は両方向とも落ちず、既存接続は両方向とも切れる。戻す操作が特別に危険ということはない、というのが今回の範囲での答えです。

公式に手順が書かれていないので身構えていたのですが、やることは行きと同じでした。regional NAT を残したまま zonal NAT を作り、ルートを戻し、regional を消す。それだけです。

ただし、これはルートを張り替える方式での話です。次節のとおり、availability_mode を直接書き換えると話が変わります。

5. コードを書き換えると160秒止まる

引数を間違えなかった場合でも、destroy → create の順である以上、経路が無い時間は必ず生まれます。そこで availability_moderegionalzonal に書き換えて apply し、4節と同じプローブで測りました。

時刻 できごと
14:32:14 apply 開始
14:32:42 旧 NAT が deleting
14:32:49 通信が落ちる
14:33:35 旧 NAT が deleted
14:33:41 新 NAT が pending
14:35:28 新 NAT が available
14:35:30 通信が戻る

断は 160.4秒。連続41回の失敗。

断の開始は旧 NAT が消え始めた直後、断の終了は新 NAT が使えるようになった直後。経路が無い時間がそのままダウンタイムになっています。

既存接続は「切れる」というより「ぶら下がったまま死ぬ」

このとき、ダウンロード中だった接続がどうなったかも記録が残っていました。

14:32:10  start                       ← 断が始まる39秒前に開始
14:35:55  broken (exit 56, 2.6MB)     ← 通信が戻った25秒後にようやくエラー
14:35:56  start                       ← 張り直し

断が明けた 14:35:30 の時点でも、この接続は復帰していません。 そこから25秒ハングした末にエラーで落ちています。3分45秒かけて 2.6MB しか進んでいません。

ルート張り替え(4節)では既存接続が1.9秒前後で即座に切れたのと対照的です。経路そのものが消えると、TCP はすぐには諦めない。監視や再接続処理を設計するなら、この「気づくのが遅れる」挙動のほうが厄介です。

同じ切り替えが、やり方で 0 と 160秒に分かれる

方式 新規接続の断 既存接続
ルートを張り替える(公式手順、4節) 失敗 0回(6回中6回) 1.9秒前後で切れる
availability_mode を書き換える 160.4秒 ハングした末に落ちる

理由は単純です。NAT Gateway の作成には時間がかかります(このときは1分54秒)。削除してから作れば、その間は経路が消える。 一方ルート張り替えなら、両方の NAT が生きている状態で向き先を変えるだけなので断が出ません。ただし今回のダウンタイム測定(160.4秒)は1回のみです。再現性は高いと考えていますが、次回以降で確かめます。

公式の変換手順は、この160秒を避けるための手順です。 availability_mode を1行書き換える PR は、公式手順とは別物。レビューで見つけたら止めてください。

なぜ書き換えが必ず「置換」になるのかは、private を指定したら public ができた話の4節に書きました。modify-nat-gateway という API がそもそも存在しないので、作り直す以外の方法がありません。

測定は1回のみです。ただし内訳(削除53秒 / 作成1分54秒)は NAT Gateway の作成・削除の所要そのものなので、大きくは動かないはずです。なお create_before_destroy = true を付けた場合は試していません。NAT は EIP とサブネットの制約があるので、そのまま付けて解決するかは別途確認が要ります。

6. 確実に消す

NAT Gateway の時間課金だけで 1本あたり月 $45.3 相当 (ap-northeast-1、$0.062/時、730時間換算)。public IPv4 やデータ処理の料金は別です。消し忘れが一番高くつきます。

terraform destroy

今回は Destroy complete! Resources: 32 destroyed で一度で通りました。そのうえでリージョン全体を実物で確認したところ、残骸はゼロでした。

身構えていた2点も、確認したら大丈夫でした。

心配していたこと 実際
auto モードで AWS が払い出した IP が残らないか 残らない。describe-addresses が空
regional が自動作成したルートテーブルが残らないか 残らない。NAT の削除と一緒に消える

自分で作っていない IP とルートテーブルなので消し漏れを疑っていましたが、どちらも NAT に紐づいて消えます。

それでも「実物を見に行く」確認が要る

terraform destroystate にあるものしか消しません。 そして今回、1組だけ消え残りました。

AWS API を直接叩いたときにできてしまった NAT 2本です。Terraform の管理外なので destroy の対象になりません。 手で delete-nat-gateway しました。

同じことは、次のようなケースでも起きます。

  • CLI で直接叩いた検証の産物(今回これを踏みました)
  • 置換の途中で失敗して state から外れたリソース(5節の経路)
  • 上記 #45828 で destroy が途中失敗した残骸

Destroy complete! は「state にあったものは消した」という意味でしかありません。 なので実物を見に行きます。

aws ec2 describe-nat-gateways --region ap-northeast-1 \
  --filter 'Name=state,Values=pending,available,deleting' \
  --query 'NatGateways[].[NatGatewayId,State,AvailabilityMode]' --output text
aws ec2 describe-addresses --region ap-northeast-1 \
  --query 'Addresses[].[AllocationId,PublicIp]' --output text

どちらも空で返ってくることを確認してください。 terraform destroy の完了メッセージを撤去の確認にしない。ここは横着しないほうがいいです。

手で消す場合は順番があります。

aws ec2 delete-nat-gateway --region ap-northeast-1 --nat-gateway-id nat-xxx

NAT の削除完了までは待ちが入ります(今回は destroy 開始から NAT が完全に消えるまで約1分半)。EIP の release はその後でないと失敗します(これが #45828 の本質でもあります)。

aws ec2 release-address --region ap-northeast-1 --allocation-id eipalloc-xxx

おまけ: 検証中に自分がやった失敗

「エラーになるはず」と思って API を4パターン叩いたところ、2件が成功して NAT が2本できました。 約3分で気づいて消しましたが、エラーを確認するつもりの操作でも、リソースは生まれます。 この種の確認は、先に後始末の手順を決めてから実行してください。

測った6つを1枚に

項目 実測
展開のトリガ アタッチしていない ENI 1個で発動(EC2 不要)
展開時間 7分20秒 / 15分45秒。前半の検知が 42秒〜47分で68倍ばらつく
縮小時間 26分43秒 / 53分52秒。2回とも展開より遅い
前半と後半 後半(実処理)は4回とも6〜7分で一定。読めないのは検知だけ
ルート切替の断 新規接続は失敗0回。既存接続は6回中6回で切断
コードの書き換え 160.4秒。同じ切り替えが、やり方で 0 と 160秒に分かれる

一番使えるのは最後の2行だと思います。メンテナンスウィンドウの設計で効くのは「切り替えの所要」ではなく「そのシステムが持っている接続の寿命」と「どちらのやり方を選ぶか」です。

まだ測れていないこと

  • 課金がゲートウェイ1個あたりなのか、展開した AZ の数ぶんなのか。Regional には zonal と別の usagetype (RegionalNatGateway-Hours) がありますが、単価は同じ $0.062 でした。差が出るとしたら「何個ぶん課金されるか」のはずで、そこは公式にも料金ページにも書かれていません
  • 展開・縮小の回数(各2回)。前半の検知が68倍ばらつくので、範囲でしか言えません

関連

private NAT を指定したときの罠、引数の書き間違いがどこで止まるか、availability_mode がなぜ置換になるのかは Regional NAT Gateway に private を指定したら public ができた に書きました。本記事5節の160秒は、そちらの「置換になる」話の続きです。

参考


本記事の数値は 2026-09-01 に ap-northeast-1 で実測したものです。展開・縮小時間は測定回数が少なく(各2回)、環境やタイミングで大きく変わります。掲載した IP は置き換えていますが、別アドレスである点はそのままです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?