Cloud Run導入したお話し

[PTAアドベントカレンダー](https://adventar.org/calendars/6450)2021の12/16の記事です。

# はじめに
本記事では私が約３年程携わっているシステムをGKEからCloud Runへ移行した際の話をまとめたものになります

# Cloud Runについて
公式によると **Cloud Run は、サーバーレスのコンテナ化されたマイクロサービスをデプロイしてスケールするためのフルマネージド コンピューティング環境です。** とのことです
https://cloud.google.com/blog/ja/topics/developers-practitioners/cloud-run-story-serverless-containers

# 導入
ここではCloud Runの導入に至った動機、背景を書き記しました

## 動機
兎にも角にも **やってみたかった** これに尽きます
勿論これは仕事なのでそれだけでなく後述する理由やメリットを揃えた上で進めました

## 理由
ここではCloud Runが適していると考えられる事柄を揃えました

- サービス稼働時間が短い  
  利用者が社内のメンバーに加え招待している社外の方々である  
  基本的に営業日(月〜金、10:00〜19:00)をサポートしていればOK
- コンポーネント群が他サービスから独立している  
  他のサービスが本サービスに依存している箇所が少なく調整する手間が掛からない
- 性能をそこまで求められていいない  
  体感で不快を感じなければOKくらいに思っていた  
  今までも性能に関するクレームは聞かなかったので

## メリット
ここではCloud Runにすることで得られるメリットを揃えました

- コストダウン  
  休憩時間が長いので従量課金制と相性が良いはず
- kubernetesからの卒業  
  deploymentなどお約束的に用意していた定義ファイル達から卒業  
  kubernetes clusterのアップデートによる影響を受けない->これが一大イベントになることがある
- セキュリティの向上  
  2021年春先にCodecovでの不正アクセスの問題があったこともあり(我々のチームは使用しておりませんでした)セキュリティ向上の機運が盛り上がったのでこの際に放置していたコンポーネントにも手を入れようと

# セキュリティ
ここではセキュリティについて心がけた事、やった事について書き記しました

## ポリシー
- サービスアカウントによる認証を用いる  
  Cloud Runが提供している認証機能に乗っかる
- 1コンポーネント1サービスアカウントを基本とする  
  [ベストプラクティス](https://cloud.google.com/iam/docs/best-practices-for-using-and-managing-service-accounts?hl=ja#single-purpose)に従う
- 権限は必要最小限、最小範囲とする  
  ストレージなら必要なバケットのみ

## 設定する

トリガーにて認証が必要をチェックすることでクライアントがコンテキストに[run.invoker](https://cloud.google.com/run/docs/reference/iam/roles)を有したサービスアカウントにて発行したトークンをセットして送らないとエラーとなります  
本システムではコンポーネント間の通信は全てgRPCを用いているので以下を参考に実装しております  
https://cloud.google.com/run/docs/triggering/grpc?hl=ja#request-auth
https://cloud.google.com/run/docs/triggering/grpc?hl=ja#connect

### サービスアカウントの権限
- secret accessor
  サービスアカウント毎に参照できるSecretManagerSecretを指定します
  以下の例では`secret-a`に対する**roles/secretAccessor**を有しているので参照できます
  `secret-b`に対しては権限を有していないので参照してもエラーとなります
  - terraform  

      ```tf
      resource "google_secret_manager_secret_iam_binding" "secret-a-secre-accessor" {
        secret_id = "secret-a"
        role    = "roles/secretmanager.secretAccessor"
        member  = ["run-service-a@example.com"]
      }

  - 構成図  
      ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/960906/48a37f91-9684-d833-8698-f9b8c8d3e33c.png)


- run.invoker
  サービスアカウント毎に実行できるCloudRunServiceを指定します
  以下の例では`run-service-a`に対する**roles/run-invoker**を有しているのでこれを実行できます
  `run-service-b`に対しては権限を有していないので実行してもエラーとなります  

  - terraform  

      ```tf
      resource "google_cloud_run_service_iam_binding" "run-service-a-run-        invoker" {
        role    = "roles/run.invoker"
        service = "run-service-a"
        member  = ["client@example.com"]
      }
      ```

  - 構成図  
      ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/960906/511c4310-aa5e-8132-45b1-5c4893604e22.png)

# 進め方
ここではGKEで動かしているサービスたちをCloud Runに切り替えていった際の手順を書き記しました

## 移行前
service-a、service-b、service-cがGKE上に存在しています
これらをservice-c、service-b、service-aの順にCloud Runへ移行していきます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/960906/8733bbe0-3ec5-759f-1e91-eebd066689d3.png)

## Step.1
service-cをCloud Runに移行します
service-a、service-cはservice-aに対するrun.invokerを与え、gRPCクライアントのコネクション、認証付きリクエストの修正をします

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/960906/c5000899-2c61-ac89-c649-e9b51a9c60e4.png)

## Step.2
service-bをCloud Runに移行します
service-aはservice-bに対するrun.invokerを与え、gRPCクライアントのコネクション、認証付きリクエストの修正をします

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/960906/32f061c5-c377-fd2f-5581-2fe36f86cf71.png)


## Step.3
service-aをCloud Runに移行します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/960906/a42ee812-6feb-c500-6f8d-5f2300f1acae.png)

# 結果
GKEからCloud Runへの置き換えを進めた結果、システムコスト(Compute Engine部分)が**51.81%**の削減を実現しました

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/960906/443a63cf-165f-18d2-48d1-fa18407fe98e.png)

# まとめ
- 人柱になれた 
  サービス全体をサーバーレスで組むというのはまだやっていなかったことなのでこのような事例を作ることができたので今後の選択肢を増やせたので良かったです 
  
- リプレイスならその効果を計るための計測方法を用意する 
  このCloudRun導入にはコスト削減の狙いもあったのでその成果をアピールよできるよう導入前後でその効果を測るための計測方法を用意しておくべきでした 
  特に導入前はそれを進めてしまうと戻すこともできない場合があるので以前の状態を机上で算出することになるので細かい内訳等下調べは重要です  
  ビジネスサイドへの説明は定量的な数字に落とせないと伝わり難いのでここを意識して行くよう心掛けます

- 一人で出来るとしても周りを巻き込んだ方が良い 
  このCloudRun導入は一人で細々と進めていたこともあり周りには詳細な事は共有せずにおりました 
  そのような状態ですと詰まった時、悩んだ時、意見を求めたい時に今までの経緯から説明しなければならなく相談相手として機能する状態にするまでに手間と時間が掛かってしまいました 
  なので多少なりと良い意味で周りを巻き込んでいくことは大事だと思います