GCPネットワークのルート選定の裏側:静的ルートとCloud Router(BGP)の優先度・ネクストホップ仕様を完全攻略する
こんにちは、SREチームのシニアエンジニアです。
現場でインフラを設計・運用していると、必ずと言っていいほど「あれ、意図したルートと違うパスにトラフィックが流れているぞ?」という瞬間に出くわします。特にマルチクラウド接続や、オンプレミスとの閉域網(Interconnect / VPN)を絡めたハイブリッド環境において、GCPのルートテーブルがどのような基準でパケットを送り先を選定しているのかは、夜中にPagerDutyが鳴り響くかどうかの分かれ道です。
今回は、GCPのVPCネットワークにおける「カスタム静的ルート」と、「Cloud RouterがBGPで動的に学習するルート」が、お互いにどのようにプライオリティを競い合い、最終的にどのネクストホップへパケットを押し出していくのか、そのシビアな仕様と現場のトラブルシューティングの極意を徹底的に解説します。
—
1. ルート選定の基本哲学:GCPはどこを見てパケットを曲げるのか?
まず大前提として、GCPのVPCは「分散型のソフトウェア定義ネットワーク(SDN)」であり、各VMインスタンスのハイパーバイザーレイヤー(またはVPCのデータプレーン)でルーティングの判断が下されています。
パケットがVPC内から外へ(あるいは別サブネットへ)飛び出す際、GCPは以下のステップで最も合致するルート(Longest Prefix Match)を検索します。
1. 最長一致プレフィックスマッチ(Longest Prefix Match)
送信先IPアドレスに対して、最もマスク長(プレフィックス長)が長いルートが勝負の土俵に立ちます。例えば、10.0.0.0/16 よりも 10.0.1.0/24 へのルートが優先されるのは、ネットワークの基本中の基本です。
2. ルートの優先度(Priority)の比較
同じプレフィックス長を持つルートが複数存在する場合、次に比較されるのが priority パラメーターです。数値が小さいほど優先されます(例: 100 は 1000 より優先)。
3. 静的ルート vs 動的ルート(BGP)の優劣
ここが今回のメインディッシュです。同じプレフィックス、同じプライオリティ値であった場合、静的ルートと動的ルートのどちらが勝つのでしょうか? また、BGPのパス属性(MEDやAS Path)はどのように絡んでくるのでしょうか?
泥臭い現場の挙動を見ていきましょう。
—
2. パラメーターと仕様の深掘り:静的ルート vs 動的ルート
カスタム静的ルートの仕様
カスタム静的ルートは、管理者が明示的にGCPコンソールやgcloud、Terraformで定義するルートです。
- プライオリティ値:
0から65535の間で指定可能(デフォルトは1000)。 - ネクストホップのタイプ:
- インスタンス(
--next-hop-instance) - IPアドレス(
--next-hop-address:主にプライベートIPルーター用) - VPNトンネル(
--next-hop-vpn-tunnel) - デバイス(
--next-hop-ilbなど)
Cloud Router(BGP)による動的ルートの仕様
Cloud Routerは、BGPセッションを張ってオンプレミスや他クラウドから動的にルートを吸い上げます。
- プライオリティ値(Base Priority): Cloud Router自体に設定するベースプライオリティ(デフォルトは
1000)。 - MED (Multi-Exit Discriminator): BGPの広告元から送られてくるMED値が、GCP側でのルートプライオリティに加算されます。つまり、
Cloud RouterのBase Priority + MEDが、GCPのVPC内での実効プライオリティになります。 - 方向(Direction): 動的ルートには、リージョナルな特性があり、カスタム動的ルートモードまたはグローバル動的ルートモードによってVPC全体への伝播範囲が変わります。
—
3. どっちが勝つ? 競合時の評価順序とネクストホップの決定フロー
もし、「手動でねじ込んだ静的ルート」と「Cloud RouterがBGPで学習した動的ルート」が、全く同じ宛先(プレフィックス)を向いているとき、GCPはどのように勝敗を決めるのでしょうか。
結論から言うと、「プライオリティ(数値の小ささ)」が絶対正義です。静的か動的かという出自よりも、設定されたプライオリティ値の勝負になります。
判定アルゴリズムの全貌
[パケットの宛先IP]
↓
(1) 最長一致プレフィックスマッチ (Longest Prefix Match)
↓
(2) 実効プライオリティの比較 (数値が小さい方が勝ち)
* 静的ルート: 設定した priority 値
* 動的ルート: Base Priority + MED 値
↓
(3) 【重要】プライオリティが完全に同値の場合のタイブレーカー
* 同一プレフィックスに対して静的ルートと動的ルートが競合した場合、
GCPの内部実装および設計思想として、明示的な管理者の意図を汲む形、
あるいは特定の順序で評価されますが、実務上は「意図しないルーティングの揺れ」を
防ぐためにプライオリティを明確に分離させるのが鉄則です。
現場で最もやりがちなミスが、Cloud Routerのベースプライオリティをデフォルト(1000)のままにしておき、バックアップ用の静的ルートもデフォルト(1000)で作成してしまうパターンです。これにより、マルチパス(Equal-Cost Multi-Path: ECMP)が意図せず有効化され、パケットがフラフラと分散して通信断を引き起こす原因になります。
—
4. 実践:設定例とコードスニペット
では、実際にこの挙動をコントロールするための設定を見ていきましょう。
今回は、メイン回線としてCloud Interconnect(BGP動的ルート)を使い、万が一の障害時にのみ切り替わるバックアップ用のVPN(静的ルート)を構築するシーンを想定します。
4.1. Cloud Routerの作成(動的ルート・ベースプライオリティ指定)
まずはBGPを喋るCloud Routerを、優先度高め(プライオリティ 100)で作成します。
# Cloud Routerの作成(メイン回線用:プライオリティを低め=実効優先度を高く設定)
gcloud compute routers create main-cloud-router \
--network=production-vpc \
--region=asia-northeast1 \
--asn=65001 \
--advertisement-mode=custom
4.2. バックアップ用カスタム静的ルートの作成
メインのBGPルートよりも優先度を「落とす」(数値を大きくする。例: 2000)ことで、通常時はBGPルートが使われ、BGPが落ちたときだけ静的ルートにフォールバックさせます。
# バックアップ用の静的ルートを作成(プライオリティを 2000 に指定して通常時は隠す)
gcloud compute routes create backup-static-route \
--network=production-vpc \
--destination-range=192.168.100.0/24 \
--next-hop-vpn-tunnel=backup-vpn-tunnel-a \
--priority=2000 \
--description="Primary BGP down no toki no fallback route"
4.3. 現在のルート状況をプログラム(Python)で確認する
SREとしては、現在のルートテーブルが想定通りの優先度で評価されているか、API経由で自動チェックするスクリプトを持っておくと安心です。以下はGoogle Cloud Client Library for Pythonを使ったルート一覧取得のサンプルです。
from google.cloud import compute_v1
def list_active_routes(project_id: str, vpc_name: str):
"""
指定したVPC内のすべてのルート(静的・動的)を取得し、
プライオリティとネクストホップを出力する実用スニペット
"""
client = compute_v1.RoutesClient()
# VPCネットワークのフルURLを構築
network_url = f"projects/{project_id}/global/networks/{vpc_name}"
print(f"--- VPC [{vpc_name}] のルートテーブル一覧 ---")
# ネットワークに関連するルートをリストアップ
# 注: gcloudの routes.list はグローバルリソースです
request = compute_v1.ListRoutesRequest(project=project_id)
for route in client.list(request=request):
# 自VPCのルートに絞り込み
if route.network == network_url:
print(f"ルート名: {route.name}")
print(f" 宛先範囲 (Dest Range): {route.dest_range}")
print(f" プライオリティ (Priority): {route.priority}")
print(f" ネクストホップ (Next Hop): {route.next_hop_gateway or route.next_hop_ip or route.next_hop_instance or 'Dynamic/BGP/Other'}")
print(f" タイプ: {route.route_type}")
print("-" * 40)
if __name__ == "__main__":
# 実際のプロジェクトIDとVPC名に書き換えて実行してください
PROJECT_ID = "my-production-gcp-project"
VPC_NAME = "production-vpc"
list_active_routes(PROJECT_ID, VPC_NAME)
—
5. 現場の教訓:よくあるトラブルとデバッグTips
最後に、私が実際の現場で踏み抜いたトラブルシューティングの知見をいくつか共有します。
1. 「あれ、静的ルートが効かない?」と思ったら最長一致を疑う
- バックアップ用に
192.168.0.0/16の静的ルートを置いたつもりが、BGPから細分化された192.168.100.0/24が学習されている場合、パケットは細分化されたBGPルートに吸い込まれます。静的ルートも宛先を揃えるか、プレフィックス長に注意してください。
2. ECMPの罠に気をつける
- 同じプレフィックスに対して、全く同じプライオリティの静的ルートと動的ルート(あるいは複数のCloud RouterからのBGP)が存在すると、GCPは喜んでECMP(等コストマルチパス)を有効化します。ステートフルな通信(ファイアウォールやプロキシを挟む通信)でこれが起きると、パケットが往復で違うパスを通り、非対称ルーティング(Asymmetric Routing)によってパケットがドロップします。冗長化のつもりが単なる通信不安定化の原因にならないよう、プライオリティは必ず優劣をつけましょう。
3. パケットの実際の経路を確認する最終兵器
- ルートテーブルの机上の計算が合っていても、VPCファイアウォールルールや、オンプレ側でのリバースパスフィルター(RPF)に阻まれていることがあります。そんなときは、GCPの Network Connectivity Center や VPC Flow Logs、そして実機での
tracerouteやtcpreplayを駆使して、泥臭くパケットを追いかけましょう。
GCPのネットワークは非常に洗練されていますが、その裏側にあるロジック(最長一致とプライオリティの力学)を正確に理解していれば、どんな複雑なハイブリッド構成であっても怖くありません。
皆さんのインフラ運用が、静かで平穏なものになることを願っています!
コメント