AWS と GCP を VPN でつないでみたら、マルチクラウドの夢が広がった話

こんにちは。はてなで SRE をしている id:nabeop です。最近の趣味は、AWS CDK で TypeScript と戯れることです。

今回は、社内の開発合宿で AWS と GCP を VPN で接続して、実運用に載せた場合の課題や構成を検討したので、その内容について書いてみます。

VPN で AWS と GCP をつなげたい背景

はてなでは、クラウド環境として長らく AWS がデファクトスタンダードとなっています。ただし、最近は GCP で構築したシステムも少しずつ増えてきました。現時点では GCP で構築されているシステムが、はてなの内部ネットワークと通信する要件はありません。しかし将来的には、新しく GCP で構築されたシステムで内部ネットワークと通信する必要が出てくることも想像できます。

そのような事情があり、GCP でシステムを構築しているチームに所属している Web アプリケーションエンジニアの id:t_kyt や SRE の id:taketo957 と、共通基盤を管理するチームに所属している id:nabeop で、AWS と GCP を VPN で接続するときに発生する課題などを確認するため、開発合宿で検証してみることになりました。

どんな構成の VPN を開発合宿で試したか

はてなの内部ネットワークは、以前紹介したように AWS Transit Gateway (TGW) を中心として、オンプレミス環境と AWS 環境を接続するような構成に変更している最中です。GCP 環境も、TGW に接続することを想定しています。

ただし、GCP からの VPN は1つで、VPN の先に複数のサービスが各自でシステムを構築し、VPN と Cloud Router で接続する構成を想定しています。

VPN の見え方が AWS と GCP で異なる構成

実際に開発合宿中に構築した環境は以下のようになりました。VPN 部分は AWS と GCP で見え方が異なるため、両方の視点で見たときの構成図を書いています。

構成図
構成図

AWS と GCP で VPN の構成が異なって見える原因は、それぞれの環境における VPN 終端の構成が、実際に構築しているリソースと1対1で対応できないためです。

つまり、VPN 終端としては以下のようになっています。

  • AWS ... 2つの VPN 終端を持つ AWS Site-to-Site VPN (AWS VPN) を2つ作成
    • つまり、AWS 側のリソースとしては、2つ作成している
  • GCP ... VPN 終端として4つの GCP ピア VPN ゲートウェイを作成
    • つまり、GCP 側のリソースとしては、4つ作成している

この構成の違いは、VPN 回線の冗長性を確保するときに重要な要素となってくるので、注意が必要です。

手軽に VGW で試してみたけど TGW でも大丈夫

当初、開発合宿では VPN の構築を主題に置いていたため、AWS 側では VPN を AWS 仮想プライベートゲートウェイ (VGW) でお手軽に収容する構成からスタートしました。TGW を構築・運用している経験から、VPN さえつながれば、AWS 側の収容は TGW でも VGW でもとくに大きな差異は出ないだろうと想定していました。

開発合宿の最終日に時間が余ったので、実際に VGW から TGW に構成を変更してみましたが、大きなハマりごともなく構成変更は完了しました。

ただし、GCP 側の Cloud Router では、BGP の経路再計算で40秒ほどのネットワーク断を確認しました。このあたりは GCP のドキュメントにあるとおり、避けられない問題のようでした。実際に本番環境で構築する場合は、最初から TGW で収容するような構成にしておく必要がありそうです。

VPN エンドポイントにおける IP アドレスの扱い

VPN の構成は開発合宿初日の昼過ぎに完成しましたが、構築中に唯一ハマったのは、AWS と GCP の双方で VPN 関連のリソースを作るときでした。

今回は、Terraform や AWS CDK といった Infrastructure as Code (IaC) 的なアプローチは取らず、それぞれのコンソール画面でリソースを作っていました。VPN 関連のリソースを作るにあたり、双方で対向の VPN 終端の IP アドレスが決まっているという前提になっていました。このためリソース作成時にデッドロックが発生して、作業が進まないという事態になりました。

幸い、GCP 側では最初に VPN 終端である GCP クラウドゲートウェイを作成する手順になっていたので、GCP クラウドゲートウェイが作られたところで GCP 側の作業を止めて、GCP クラウドゲートウェイで使用されているグローバル IP アドレスを AWS CGW として、AWS 側のリソースを作成しました。

あるいは、VPN 接続を完了する前に、GCP であらかじめグローバル IP アドレスを確保してから、GCP クラウドゲートウェイを作成するという手段も取れることに気づきました。GCP 側で VPN 終端用の IP アドレスを確保してから、AWS 側の VPN リソースを構築するというアプローチでもできそうでした。

また、マルチクラウド環境の IaC 的アプローチを取るときには、このようなデッドロック状態を回避するため、リソースの依存関係などを考慮しつつリソース作成をする必要がありそうです。

GCP VPC を構成してみて浮上した課題

AWS と GCP の VPN 接続が開発合宿の初日にできてしまったので、残りの時間は、実際に本番環境で使う場合の懸念点や、運用ポリシーを議論しました。

まず最初に、VPN で通信させたい場合、GCP VPC はカスタムモードの VPC ネットワークとして作成しておく必要があります。初期状態で作成されている GCP VPC は、自動モードの VPC ネットワークが作成されているので注意が必要です。

複数のサービスが VPN を共有する構成

また本番環境では、AWS と GCP の VPN は1つとして、複数のサービスが VPN を共有する形態を想定しています。したがって、以下のような構成で検証環境を構築しました。

f:id:nabeop:20200409212447p:plain
GCP VPCの構成図

つまり、ネットワーク全体を管理するチームが運用するホストプロジェクトに共有 VPC を作成して、GCP で構築するサービスやシステム単位で作られたサービスプロジェクトが共有 VPC に接続するイメージです。共有リソースであるネットワークとシステム固有のコンポーネントを分離することで、責任分界点とすることを検討しています。

このような構成で作成したサービスプロジェクト側で使いそうな GCP リソースを実際に構築して挙動を確かめたところ、運用上の課題が浮かび上がってきました。

VPC ピアリングで接続するサブネットが作成される

まず、サービスプロジェクト側で MemoryStore を作成したところ、サービスを構築している VPC とは別の VPC とサブネットが作成されたことを確認しました。

ホストプロジェクト側のルートテーブルや AWS 側のルートテーブルを確認したところ、MemoryStore によって作成されたサブネットの経路は登録されていません。MemoryStore の作成で作られたサブネットは VPC ピアリングで接続しているため、GCP 外のネットワークには経路広報されないようでした。

ただし、共有 VPC で作成すると、接続しているサービスプロジェクトにも経路伝播していることが確認できたので、共有 VPC で作成する場合は十分に注意する必要がありそうです。これは、共有 VPC では外部環境と接続する VPN 関連のリソースのみを作る、ということで回避はできそうです。

MemoryStore によって作成されるサブネットは、既存の GCP リソースが使用しているサブネットとは異なるネットワークアドレスで構築されるようですが、GCP 外の環境で使用しているネットワークアドレスとバッティングすることは考えられます。全体での IP アドレスの管理方針など、運用ポリシーを定めておく必要がありそうです。

また、VPC ピアリングで接続する GCP リソースは他にもあるはずなので、どのようなリソースを作ると同じ挙動をするかということも把握しておく必要がありそうです。

おわりに

仕事から少し離れて、普段一緒に仕事をしていない同僚と、普段は触っていないサービスを検証して議論することはリフレッシュになるし、普段とは別の視点から気づきも得られて、充実した3日間でした。

GCP は普段触っている AWS とは勝手が違い、考え方を変えて向き合う必要があったりしますが、今回の開発合宿で得られた知見を活かしてプロダクション環境への実装についても進めていきたいですね。