開発環境をCloud Runにして変わったこと

# はじめに
本記事は[QualiArts Advent Calendar 2021](https://qiita.com/advent-calendar/2021/qualiarts) 10日目の記事です。
去年([開発環境をGKE運用からサーバーレス運用に変更してみた](https://qiita.com/iyu/items/c57f2d1c28660c8859b1))に引き続き今回も[Cloud Run](https://cloud.google.com/run)について書きます。去年記事を書いた段階ですとCloud Runで動かし始めたばかりの時期で開発環境とはいえ本格運用していない段階でした。今回は本格運用して１年経ったので変えてみてよかった点や悪くないなと思った点について書きます。
Cloud Runの一部機能はまだ[プレビュー](https://cloud.google.com/products#section-22)版のものもあるので今後大きく変更が入る可能性もありますがご了承ください。

# 料金について
去年の記事でも料金については大きな期待をしつつも、実際開発環境にどのくらいのリクエストが来ているかを秒単位で把握はしていなかったので具体的には予測できていませんでした。実際規模のあるプロジェクトで運用し始めましたが従来の構成に比べてCompute価格は**約96%のコストカット**が出来ました。96%になったのではなく96%OFFです。1/25です。もちろん従来の構成(前まではGKE構成でした。)だったり現在の利用頻度等によって大きく変わる話なのでどのプロジェクトでも安くなるとは言えませんが、弊プロジェクトのパターンだと予想通り大幅なコストカットが出来たので大満足です。
おさらいですが、Cloud Runはリクエスト単位の課金になります。単位は秒です。10msの通信を1000回行えば10秒分の請求がされます（秒数の細かい合算方法については認識あっているか不安になってきたので公式ドキュメント読んでください。大きくは間違ってないと思います。）したがって開発環境のように常時アクセスが来るわけではないような環境であればVMの管理よりも大幅に安くなる可能性があります。
ただし月に数時間しか使わないから数十円で済むかと言われると利用する周辺機能によっては別途料金が掛かるので注意です。例えばLoadBalancerを使うとなったらその料金は掛かりますし、Cloud Armorを使うとなってもその料金が掛かります。すごくあたりまえですけども。
あとは、Cloud MemorystoreやVPC内のリソースへアクセスをする場合、[Serverless VPC access](https://cloud.google.com/vpc/docs/configure-serverless-vpc-access)の設定が必要です。これですが最初は気づかなかったのですが作成するとe2-microインスタンスの料金が掛かります。場合によってはCloud Runの料金より高くなります！笑 これもPreview時代に飛びついたので当時は設定時にe2-microなんて単語はでてこなかったですし、請求書にはCompute Engineの項目で請求ありますがCompute EngineのVM一覧にはなにもないみたいな状況で不思議に思った記憶があります。今はServerless VPC accessコネクタを作成時にインスタンスタイプを設定できるみたいです。（terraformだとbeta provider使わないとまだ未対応?）

# 管理について
Cloud Runに移行するまではGKEで開発環境用に１クラスタ立ててその中にdev1,2,3...のようなServiceを作っていました。GKEのときはdev環境の数が増えてくるとどうしてもnode数を増やしていく必要があり全devがアクセスあるわけじゃないのに無駄だなーという思いが強かったです。podのresource.requestを無理に小さくし騙し騙しでnode数の削減等をしていました。休日や深夜帯だったら停止したりスケールインしたりも考えなくてはいけませんでした。あと大変だったのはGKE自体のアップデートで、開発環境なので基本的に自動アップデートONにしていましたがアップデートによってk8sAPIが使えなくなったり、もしくは既存リソースが動かなくなったり、それを防ぐためにk8sのリリースノートは常に監視する必要がありました。こういうオペレーションコストや人的コストがCloud Runに移行してからは一切なくなり、インフラコスト96%OFFなんかよりも大きなメリットだったと感じています。

# この１年のアップデートについて
ここからはCloud Runを使うようになってからアップデートされた部分について書いていきます。Cloud Runのアップデート内容のすべてではなくCloud Runのアップデート内容の中から実際に利用開始したものや利用を考えたものをピックアップしています。

## Identity-Aware Proxy (IAP) の対応
[Identity-Aware Proxy](https://cloud.google.com/iap)は昨年末に導入しました。詳細は公式ページを参照してください。GKEで運用していたときも利用していてCloud RunがIAPのサポートをするまでは、自前でIAPと同じ動きをするプロキシを作ってBackendサーバーではIAP関連のヘッダが来る前提での検証をするように作るほど、待ち焦がれていた機能です。この機能のおかげでプロジェクトの管理コンソールではユーザーを特定する認証をGoogleに任せることができ、安全に処理できるようになっています。ちなみにサポートされてそろそろ１年経つはずですがまだプレビューのままです。HTTP/2サーバーで利用しようとしたらバグりました。正式リリースが待ち遠しいです。

## Cloud Armor の対応
[Cloud Armor](https://cloud.google.com/armor)についてもIAPと同時期にサポートされました。これがサポートされるまではCloud RunだけではIPアドレス制限をすることができずIPアドレス制限させたVMをプロキシする等の工夫が必要でした。HTTPサーバーだけでなくHTTP/2サーバーも利用できるようです。ただしIAPが動かなかったので純粋なHTTP/2のWEBサーバーは利用してないですが。gRPCサーバーでもIPアドレス制限が動いていることは確認済みです。

## Serverless NEG の登場
IAPやCloud Armorが利用できるようになったのが[Serverless NEG](https://cloud.google.com/load-balancing/docs/negs#serverless-neg)の登場のおかげです。細かいことを言えば昨年末より少し前にはリリースされていました。ただしその当時はCloud Runに[Internal and Cloud Load Balancing](https://cloud.google.com/run/docs/securing/ingress#settings)というingressの制限がなかったため、LB経由ではIAPを効かせられるがCloud Run直のURLがPublicという状態でした。したがってIAPやCloud Armorが利用できるようになったのはこのingress制限が登場した昨年末だったと思います。
IAPやCloud Armorは[Cloud Load Balancing](https://cloud.google.com/load-balancing)とセットで使う機能なのでCloud Run単体では利用できません。構成イメージは下記のような図になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19658/53ef8ed0-e2ac-fd7a-bf4e-489e16fe26e0.png)

LBからNEGの設定を通り、IAPの評価をしてからCloud Armorの評価をし、最終的にCloud Runのサービスに到達します。LBのBackendServiceごとにIAPを設定するかCloud Armorを設定するかを決められるのでLBに関しては１つで複数サービスを捌けます。開発環境なので１つのLBで十分だと思っています。

### URL masks について
Serverless NEGの設定をさらに楽にするものとして[URL masks](https://cloud.google.com/load-balancing/docs/negs/serverless-neg-concepts#url_masks)があります。こちらはSeverless NEG登場と同時に最初からあったのか後から追加されたのかは覚えていません。私が存在に気づいたのは実は最近です。この機能を利用することでCloud Runのサービスが増えてもLB側のBackend Serviceを追加する必要がなくなったのでより楽になったと思います。とはいえマネージドSSL証明書を更新するのでLBの更新がなくなるわけでもないのですが。マネージドSSL証明書ではなくワイルドカードSSL証明書を自前で管理しているのであればLBの更新がなくなると思います。下記はURL masksを使う場合のイメージです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19658/57f6c226-2ce6-4684-26f2-e0555b8e67d4.png)


## Secret Manager の利用
[Secret Manager](https://cloud.google.com/secret-manager)をボリュームとしてマウントしたり、環境変数に渡すことができるようになりました([*doc](https://cloud.google.com/run/docs/configuring/secrets))。この機能も１年前はなかった気がします。
Cloud RunやCloud Functionsは環境変数に機密情報を利用することを非推奨しています。これは去年私が[書いた記事](https://qiita.com/iyu/items/33dd85a2201d159680ac#%E7%92%B0%E5%A2%83%E5%A4%89%E6%95%B0%E3%81%AB%E6%A9%9F%E5%AF%86%E6%83%85%E5%A0%B1%E3%82%92%E5%85%A5%E3%82%8C%E3%81%A6%E3%81%AF%E3%81%84%E3%81%91%E3%81%AA%E3%81%84)でも説明しています。当時はCloud RunにSecret Manager関連の機能はなかったので、プログラム側からAPI経由でSecret Managerのデータを取得していました。先程の記事にもサンプルコードを載せています。ですので既に別の手法で実装済みだったためボリュームマウントや環境変数へ渡すような実装には変更していません。ただ、当時からこの機能があったのならばGKE時代では環境変数やボリュームマウントで機密ファイルを扱うコードもあった気がしたのでそちらを選んでいたかもしれません。

## ソースコードからのデプロイ
[ソースコードからデプロイ](https://cloud.google.com/run/docs/deploying-source-code)することができるようになりました。これまではCloud Buildの設定をしてgitにコードをコミットしてCloud Buildが起動してDockerビルドをしてGCRにコンテナイメージがアップロードされてCloud Runのリビジョンの更新をしていました。今もメインアプリに関しては基本この手法なのですが、ちょっとした検証用のアプリ等のためにCloud Buildを設定してーから始めるのはとても大変でした。今ではさくっとソースコードからデプロイして検証し終わったら削除するという風にできるのでとても楽になりました。

## 常時CPU起動
[常時CPU起動](https://cloud.google.com/run/docs/configuring/cpu-allocation)ができるようになりました。この機能の登場前はリクエストが終了するとコンテナも終了する可能性があるのでバックグラウンドでタスクを実行しておくことが出来ませんでした。どういうときに困るのかというユースケースについては昨年記事を書かせていただきました([Eventarcを使用した非同期でジョブを実行するSlackAppづくり](https://qiita.com/iyu/items/33dd85a2201d159680ac))。実際のところ業務ではEventarcは使ってなく、[Cloud Tasks](https://cloud.google.com/tasks)を利用しています。今では[非同期タスクの実行](https://cloud.google.com/run/docs/triggering/using-tasks)のガイドが公式でできており、ここでもCloud Tasksを紹介しているのでまぁCloud Tasksでよかったのかなと思ってます。
話を戻すと常時CPU起動によってCloud Tasksを使うといった面倒なことをせずともバックグラウンドでタスクを実行できるようになりました。ただしこの機能を使うと割引が適用されるとはいえ24時間毎日起動することになり、先に述べた開発環境だから使う時間が限られ料金が低コストになるという話は吹っ飛びます。開発環境で使うといろいろメリットを失いそうです。

### より低価格な単位で常時CPU起動がほしい
とはいえCloud Tasksだけで逃がすことが出来ないケースもあります。ユースケースはまたまたSlackAppなわけですが今年正式リリースされた[ソケットモード](https://slack.com/intl/ja-jp/blog/transformation/people-partners-systems-slack)です。これはWebHook方式とは違って外部からリクエストが飛んでくるわけではないのでCloud Runで表現はできません（試してないです。）常時CPU起動してならできるかもしれませんがそうするとe2-microよりも高くなってしまいます。サーバーレス環境を目指しているのにe2-microのVMを立てたくもないがコストが大幅に上がってしまう・・・ので・・・**1coreCPUよりも低単価なリソースが欲しいところです！**spannerは1node単位だったのが今年になって0.1node単位で設定できるようになりました！**Cloud Runもみなさまの声が上がれば100mCPU単位になってくれるかもしれません！みなさま声を上げましょう(冗談)** 100mCPUでソケットモード起動してジョブ動かすときはCloud Tasksで別Cloud Runを動かせばいいのでソケットモードのサービスはおそらくそんなにCPU使わないと思います。

# おわりに
最後は要望で終わってしまいましたが(笑)、ここ１年でCloud Run周りで主に取り組んだことでした。直近だと[Cloud RunでCloud Storageをマウントする方法](https://cloud.google.com/run/docs/tutorials/network-filesystems-fuse)の検証をしようとしています。他にもいろいろやろうと思っていることもあるので、また来年Cloud Runについて書くことがあればそのへんも書こうかなと思っています。以上です。