こんにちは、SCSKの齋藤です。
本記事では、Cloud RouterとBGP + BFDを使った専用線の冗長化についてご紹介します。
はじめに
検証環境でPartner Interconnectを使った専用線接続を構築する中で、ルーティングの設定に取り組みました。専用線を2本引いて冗長化するところまでは前回の記事で書いたのですが、実際にルーティングを制御するにはCloud RouterとBGPの設定が必要でした。

正直なところ、BGPやルーティングの知識はあまりなく、最初は「ルートが勝手に交換されるんでしょ?」くらいの認識でした。しかし実際に構築してみると、優先パスの制御やGray Failure(部分障害)への対策など、考慮するポイントがたくさん出てきました。特にBFD(Bidirectional Forwarding Detection)という仕組みを知ったのは大きな収穫で、これがないと実運用で困る場面があることがわかりました。
この記事では、Cloud RouterとBGPの基本的な役割を整理しつつ、BFDを使った高速障害検知の仕組みと、Terraformで構築する際に苦労したポイントを紹介します。
Cloud Routerとは
Cloud Routerは、Google Cloudが提供するフルマネージドのルーティングサービスです。BGP(Border Gateway Protocol)を使って、Google Cloudのネットワークと外部ネットワークの間でルート情報を動的に交換します。
Cloud Routerを使うことで、以下のことが実現できます。
- VPC内のサブネットルートを外部ネットワークに自動的に広告する。新しいサブネットを追加しても、手動でルーティングテーブルを更新する必要がない
- 外部ネットワークから広告されたルートを学習し、GCPからのトラフィックが正しく外部に到達するようにする
- 複数のBGPセッションを持つことで、経路の冗長化とフェイルオーバーを実現する
- Cloud NATやPartner Interconnect、Cloud VPNと連携して動作する
静的ルートとの違いとして、Cloud Routerは経路の状態を動的に把握します。外部ネットワーク側で経路が変わった場合も、BGPを通じて自動的に学習するため、手動でのルート更新が不要です。これはネットワーク障害時のフェイルオーバーにおいて非常に重要な特性です。
Cloud Routerは完全にマネージドで動作するため、VMやアプライアンスを自前で管理する必要がありません。Google Cloud側の冗長性も確保されており、Cloud Router自体がSPOF(単一障害点)になることはありません。
BGPによるルート交換の仕組み
BGP(Border Gateway Protocol)は、異なるネットワーク(AS: Autonomous System)間でルーティング情報を交換するためのプロトコルです。Cloud Routerでは、以下のようにBGPが動作します。
まず、Cloud RouterにASN(Autonomous System Number)を割り当てます。
resource "google_compute_router" "interconnect" {
name = "my-cloud-router"
network = google_compute_network.vpc.name
region = "asia-northeast1"
bgp {
asn = 16550
advertise_mode = "DEFAULT"
}
}
対向の外部ネットワーク側にもASNが割り当てられており、お互いのASNを指定してBGPピアリングを確立します。ピアリングが確立すると、Cloud RouterはVPC内のサブネットルートを相手に広告し、相手側からも外部ネットワークのルートを受け取ります。
重要なのは、BGPセッションが切断されると広告されていたルートが無効になるということです。これにより、障害が発生した経路を自動的に迂回できます。ただし、BGPのkeepalive間隔(デフォルト20秒)× Dead timer(通常3回)= 約60秒かかるため、障害検知には1分程度のタイムラグがあります。
冗長構成とルート優先度
今回は2本のVLAN Attachmentに対して、それぞれBGPピアを設定しました。2本のBGPセッションに異なるルート優先度(MED: Multi-Exit Discriminator)を設定することで、通常時の優先パスを明確にしています。
ルート優先度の値が小さいほうが優先されます。
resource "google_compute_router_peer" "peer_primary" {
advertised_route_priority = 100 # 優先パス
# ...
}
resource "google_compute_router_peer" "peer_secondary" {
advertised_route_priority = 200 # セカンダリ
# ...
}
プライマリパスに小さい値、セカンダリパスに大きい値を設定することで、通常時はプライマリが使われ、プライマリの障害時にのみセカンダリにフェイルオーバーする設計になります。
この設計にした理由は、Active-Activeで両方のパスに均等にトラフィックを流すと、障害発生時の影響範囲の特定やログの追跡が難しくなるためです。Active-Standby構成にしておけば、「普段使っていないパスに切り替わった」という事実だけで障害を認識でき、運用がシンプルになります。
BFD(Bidirectional Forwarding Detection)の必要性
BGPだけでは検知できない障害パターンがあります。これが「Gray Failure」と呼ばれるもので、実際に遭遇して初めてBFDの必要性を理解しました。
Gray Failureとは、完全にダウンしているわけではないが、部分的にパケットが通らない状態のことです。具体的には、VLAN Attachmentの片方でパケットロスが発生しているのに、BGPのkeepaliveパケットがたまたま通ってしまい、BGPセッションはUPのままという状態です。この場合、Cloud Routerは「この経路は正常」と判断してトラフィックを流し続けるため、通信品質が劣化したまま気づけません。
BGPとBFDの障害検知能力を比較すると以下のようになります。
| 項目 | BGPのみ | BGP + BFD |
|---|---|---|
| 検知間隔 | keepalive 20秒 | 1秒 |
| 障害検知時間 | 約60秒(20秒 × 3回失敗) | 約5秒(1秒 × 5回失敗) |
| Gray Failure検知 | ❌ できない | ✅ できる |
| 誤検知(False Positive)リスク | 低い(判定は遅いが安定) | チェック頻度が高い分、瞬間的なノイズも拾いやすい |
| 設定の複雑さ | シンプル | やや複雑(相手先との合意が必要) |
| 推奨用途 | 非クリティカルな経路 | 専用線の冗長経路 |
BFDは、BGPとは別にもっと高頻度でパケットを送り合って、経路の正常性を確認する仕組みです。1秒間隔でパケットを送信し、複数回連続で受信できなければ「障害あり」と判定してBGPセッションをteardownします。これにより、BGPのkeepaliveだけに頼る場合(約60秒)と比較して、数秒で障害を検知できるようになります。
BFDのセッション開始モードには「ACTIVE」と「PASSIVE」があります。今回は相手先の要件で「ACTIVE」を指定しました。これはCloud Router側からBFDのネゴシエーションを開始するモードです。
bfd {
session_initialization_mode = "ACTIVE"
min_transmit_interval = 1000 # ms
min_receive_interval = 1000 # ms
multiplier = 5 # 5回連続失敗でDown
}
相手側がPASSIVEに設定されている場合、こちらがACTIVEでないとBFDセッションが確立しません。この設定は相手先と事前に合意しておく必要があります。
BFDの誤検知リスクとトレードオフ
BFDは検知が速い一方で、「本当は障害でないのに障害と判定してしまう」誤検知(False Positive)のリスクとのトレードオフがあります。1秒間隔で5回連続失敗(約5秒)を判定基準にしているので、Cloud Router側やプロバイダ側のルーターが一時的に高負荷になってBFDパケットの処理が遅れただけでも、誤ってダウン判定されてしまう可能性があります。BGP単体(keepalive 20秒 × 3回 = 60秒)のほうが、こうした瞬間的なノイズには鈍感で安定している、という側面もあります。
Interconnectは専用の物理線なので、インターネット経由の接続と比べれば誤検知の原因になるノイズ(輻輳など)は少ないと考えられますが、ゼロにはなりません。ルーター機器の制御プレーンが一時的に高負荷になるケースなどは、専用線であっても起こり得ます。
BFDを入れるかどうかの判断基準
| 入れたほうがよさそうなケース | 入れなくてもよさそうなケース |
|---|---|
| 冗長経路(セカンダリ)が実際に存在する | 単一経路しかなく切り替え先がない |
| Gray Failureが起きうる環境 | 障害が「完全に落ちるか/生きているか」の二択に近い |
| 本番相当のクリティカルな通信 | 検証用途で複雑さを避けたい |
| プロバイダ側もBFD対応で調整可能 | 相手先が非対応、または調整コストに見合わない |
ポイントは「切り替え先があって初めて速い検知の価値が出る」ということです。冗長構成がないのにBFDだけ入れても、検知が速くなるだけで復旧手段がなければあまり意味がありません。
モニタリングしながらの判断
正直なところ、実際の運用でどれくらい誤検知が起きるかは、この検証環境レベルではまだわかっていません。Cloud MonitoringでBGPセッションのUp/Down回数やBFDのステート遷移を記録しておき、一定期間動かした後に「本当の障害でもないのにダウン判定が頻発していないか」を確認する、という運用しながらのチューニングが必要になりそうです。もし誤検知が多いと分かれば、multiplierやmin_transmit_intervalを緩めたり、最悪の場合はBFD自体を外してBGP単体に戻す、という選択肢も持っておいたほうがよさそうです。
# BGPセッションのUp/Down回数をCloud Monitoringで確認する際に見る指標例
gcloud logging read \
'resource.type="gce_router" AND jsonPayload.event="bgp_session_state_change"' \
--limit=50 --format="table(timestamp, jsonPayload.state)"
工夫したところ・ハマったところ
Router Interface は MANAGED_BY_ATTACHMENT
これが一番ハマったポイントです。Partner InterconnectのVLAN Attachmentを作成すると、Cloud Routerに自動的にRouter Interfaceが追加されます。最初これを知らずに google_compute_router_interface リソースでインターフェースを管理しようとしたところ、terraform planで衝突が発生しました。
原因を調べたところ、VLAN Attachmentが作成するRouter InterfaceはTerraformの管理対象外として扱う必要があることがわかりました。つまり、Router Interfaceの管理はVLAN Attachmentに完全に委ねるのがよいようです。Terraformで明示的に書くのはBGP Peerの部分だけで、インターフェースはAttachmentが勝手に作ってくれます。
このことはドキュメントに明確に書かれているわけではなく、実際にやってみて初めて気づいたポイントでした。Partner Interconnectを Terraform で管理する場合は必ず知っておいたほうがよさそうな仕様です。
まとめ
– Cloud Routerはフルマネージドのルーティングサービスで、BGPによる動的なルート交換を実現する
– ルート優先度を分けることで、Active-Standby構成のフェイルオーバーが簡単に実現できる
– BFDはGray Failure対策として必須。BGPだけでは60秒かかる障害検知を数秒に短縮できる
次回はILBとFloating IPパターンの実装について書きます。
