共有VPCを使い複数のGCPプロジェクトでGKEを使い回す

:::note info
この記事は[WEMEX株式会社 Advent Calendar 2023](https://qiita.com/advent-calendar/2023/wemex)21日目の記事です
:::

## 複数ProjectでのGKE運用どうするか
私はGCPでコンピュートリソースを立てる際にはGKEをファーストチョイスとして選択することが多いのですが、プロジェクト構成によっては迷うことがしばしばあります。例えばプロダクトを複数持っているような組織の場合、プロダクトごとにGCPのプロジェクトを分けるのは珍しくないかと思います。さらにproduction、staging等の環境ごとにもプロジェクトを分ける場合、プロジェクト数はかなりの数になります。 そしてプロジェクトごとにGKEクラスタを立てるとなると、管理の手間も費用面も負担が大きくなってきます。

## GKEのクラスタ管理費用に関して補足
ここで一応GKEの費用に関して補足しておきます。GKEは、クラスタの管理手数料として1クラスタあたり＄0.1/時間の料金がかかります。また、無料枠として請求アカウントごとに＄74.4のクレジットが提供されます。１クラスタだけなら管理手数料は無料枠で相殺されるので課金されないのですが、注意してほしいのは無料枠はプロジェクトごとではなく請求アカウントごとであるという点です。

＄0.1/時間は日本円にすると約1万円/月くらいなので、複数プロジェクトでクラスタをいくつも立てるとなるとそれなりの負担になってしまいます。

## 一つのGKEクラスタを複数プロジェクトで共有できればいいのでは？
そこで、クラスタ管理手数料をやクラスタ管理の手間を減らすために、一つのマルチテナントクラスタを複数のプロジェクトで共有する方法はないかと考えました。具体的には、以下二つの方法を検討しました

1. VPCピアリングを使って共有
2. Shared VPCを使って共有

## 1. VPCピアリングによる共有

真っ先に思いついた方法です。共有GKEクラスタ管理用のプロジェクトを作成し、このプロジェクトのVPC内に共通で使うクラスタを立て、このクラスタのあるVPCを各々子プロジェクトのVPCとピアリングするという方法です。GKE以外のリソースに関しては子プロジェクトのVPC内に構築します。下の図は子プロジェクト2つでそれぞれCloud SQLとMemoryStoreを立てた場合の例です。

![vpcpeering1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79302/81039ded-bc60-2d04-0e00-06ebd07f5431.png)


・・・と言いたいところですが、実際には少し違います。CloudSQLやMemoryStoreでPrivate IP接続を利用する場合はPrivate Service Accessを使うことになりますが、Private Service AccessはGCP管理のVPCとユーザー管理のVPC間のpeeringによって成立しているため、正確には以下の図のようになります。

![vpcpeering2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79302/564e0125-c7e4-960b-e578-7b89c774cc09.png)


「VPC1 -> VPC2 -> VPC3」のように複数のピアリングを介した接続は現状不可能なので、上の図で言うshared clusterはCloud SQLやMemoryStoreに接続することができません。CloudSQLに関してはPublicIPを利用すれば接続することはできますし、MemoryStoreは別のデータストアで代用可能であるとはいえ、GKEを共通化したいがためにインフラ構成に制限がかかるのはあまり良くありません。
と言うわけでこの方式は早々に断念しました。

## 2. Shared VPCによる共有
ピアリングだと厳しいのでShared VPCを試しました。共有クラスタを立てたsubnetと同じVPC内に子プロジェクトごとのsubnetを作成し、子プロジェクトに共有します。子プロジェクトでは共有されたsubnetに対してCloudSQLやMemoryStore等のリソースを配置します。

![sharedpvc.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79302/af88b061-419c-647e-91d7-818dc069dece.png)

この方式ならネットワーク面の問題も起きませんし、実際に試しましたが正常に機能しました。

## 3. GKEをShared VPCで共有することの問題点
GKEをShared VPCで共有することは成功しましたが、普通にGKEクラスタを運用する場合と比較して考えることは結構多いです。パッと思いつくものをいくつか列挙します。

#### ロードバランサをどこで管理するか
ロードバランサ、というかingressを定義する際の構成要素をどこで管理するか。IPとかDNSの設定とか。Admin Projectで一括管理するのが楽だけど子プロジェクトのメンバーにある程度権限を移譲したいとかだと権限管理が難しくなりそう。

#### コンテナイメージの管理
Artifact Registryはどっちのプロジェクトを使うのか。子プロジェクトの使うとcloud buildの権限管理が楽だけどGKE側の権限管理が煩雑になる。逆にAdmin Projectのを使うとGKE側の権限管理は簡単だけど子プロジェクトに追加の権限が必要。

#### secret managerどうするか
自分はGKEにsecretを登録する際にはTerraform経由でsecret managerから値を取得してk8s secretに登録するという手法を使っているが、この時にどのプロジェクトのsecret managerを使うか。

#### VPCが統一されてしまうけど大丈夫か
Shared VPCを使う訳なので、当然だけど複数プロダクトで同じVPCを使うことになる。もちろんGKEクラスタ以外はsubnetで分かれるので必要に応じて追加のネットワークポリシーを設定することはできるが、気になる人は気になるかも。

## 4. GKEをShared VPCで共有することの副次的な利点
上で問題点を列挙しましたが、GKEクラスタの費用節約や運用負担低減以外にもメリットはあります。

#### プロジェクトごとにVPC作らなくていい
これはGKEクラスタの共有というとりShared VPC使うことのメリットではあるけど・・・VPCを新しく立てるときってPrivate Service AccessとかCloud NATとか付随するリソースを含めると結構めんどくさい。Shared VPCで共有する方式ならAdmin ProjectでSubnet切るだけなので楽。

#### VPCのポリシーを統一できる
これもShared VPCのメリットではあるけど、組織全体でVPCを作る際のルールやポリシーを統一できる。インフラ構築のレビューフローが整ってれば関係ないけどね。

#### 嫌でもcidrが重複しない
あんまり気にしなくてもいいかもしれないけど、ProjectごとにVPCを作らなくて良くなるのでsubnetのcidrが重複しにくくなる。

#### プロダクト間の連携がしやすくなる
VPCもクラスタも同じなので、別のGCPプロジェクトで動いてるシステムと連携がし易くなる。

## まとめ

今回は共有VPCを使って単独のGKEクラスタを複数プロジェクトで共有するための検証に関して書きました。現状すでに社内の4プロジェクトほどで、この共有クラスタの運用を始めています。

GCPやAWSでマネージドk8sを複数プロジェクトで使うことって結構多いと思うのですが、プロダクト数が多いような組織だとどうしてるんでしょう。

今回書いたような共有VPCを使ってクラスタをマルチテナントとして使い回す方法は良さそうとは思うものの、これはこれで運用が難しい部分ありますからね・・・