🦁

App Engine VS Cloud Run

2020/12/03に公開
3

ちょいちょい、これから Web Application を作るなら、App EngineCloud Run どちらを使うべきか?と聞かれるので、思いの丈を綴っておこうと思う。

結論

僕はどちらにも好きなところと嫌いなところがあって、使い分けているが、だいたい Cloud Runを使っている。
App Engineを使うのは、Landing Pageのようなあまり複雑なことをしないケース。

この先は2つを比べて、僕がどちらを使うのかを判断する時の材料を書いていく。
App Engine には Standard と Flex があるが、この記事では Standard を主に扱っている。
Cloud Run には fully managed と for Anthos があるが、この記事では fully managed を主に扱っている。

App Engine と Cloud Run を比べてみる

課金体系

App Engine は Instance 課金、Cloud Run は 使用したリソースでの課金になる。
App Engine(automatic scaling, basic scaling) は Instance が起動してから、最後のリクエストの15分後に終了するまでを単位にしている。
Cloud Run は 100ms 単位で切り上げで計算される。
そのため、1min毎に5sec処理するみたいなことをした時に、App Engine は Instance が終了しないので、ずっと課金対象だが、Cloud Run は都度 5000ms 課金されるだけで済む。
cron で定期的に起動するような時やリクエスト頻度が少なくぽつぽつ来るケースだと Cloud Run が有利で、心が Cloud Run に傾く。

マシンスペック

App Engine は規定されたいくつかの種類から選択するが、Cloud Run は CPU コア数と Memory を選択できるので、Memory だけ増やすことができて便利。
最大スペックも Cloud Run の方が大きいので、心が Cloud Run に傾く。

App Engine Instance Class

Instance Class Memory Limit CPU Limit
B1 128 MiB 600 Mhz
B2 256 MiB 1.2 Ghz
B4 512 MiB 2.4 Ghz
B4_1G 1024 MiB 2.4 Ghz
B8 1024 MiB 4.8 Ghz
F1 128 MiB 600 Mhz
F2 256 MiB 1.2 Ghz
F4 512 MiB 2.4 Ghz
F4_1G 1024 MiB 2.4 Ghz

Cloud Run

  • CPU 0.08 ~ 8 Core (2nd gen は最小 0.5~)
  • Memory 128 MiB ~ 32 GiB (2nd gen は最小 512MiB~)

Deploy

App Engine は Deploy (gcloud app deploy) を実行すると Cloud Build が暗黙的に動いて Deploy が行われるが、これがなかなか時間がかかる。
開発環境だと CI でとりあえず main branch に merge されたら、Deploy したりするけど、Deploy を Skip してもよいような時でも CI 回してると Deploy を待つことになって、ちょっとめんどうに感じる。
更にこの仕組みは成果物は Deploy しないと生まれないので、CI と CDを分離しづらい。

Cloud Run は Container Registry and Artifact Registry の Container Image を Deploy できるので、App Engine より短い時間で CI を完了できる。
Container Image を作ってさえおけば、Deploy は簡単にできるので、CI と CD を分離しやすい。

スピンアップタイム

App Engine for Go はスピンアップタイムが爆速なので、ここは App Engine for Go が圧倒的。
ただ、App Engine for Java 使ってた時は 3sec ぐらいかかっていたので、現状の Cloud Run にそんなに不満はない。
min-instances を指定すれば、スピンアップに当たる数は少なくできるし、要件がよほどシビアでなければ、問題ないだろう。

Runtime

App Engine は最新の Version から 1つか2つぐらい遅れるが、幸い Go は後方互換を大事にする文化なので、むちゃくちゃ困ってはいない。
Cloud Run だと コマンドラインツール で提供されているものも動かせることの方が嬉しいかもしれない。

認証

Identity Aware Proxy を使う場合、Cloud Runは Serverless NEG が必要となるため、完全無料ではできない。
完全無料を目指していない場合は、App EngineとCloud Runでどちらを選択するかに影響するような差はない。

Static Contents

App Engine には Static Contents Server があるので、html, js などを配信するのはとても簡単だけど、Cloud Run にはそういった機能はないので、何かしら考えてやる必要がある。
Firebase Hosting 使うか、後述する Serverless NEG を使って App Engine か Cloud Storage から返してやることになるだろうか。

Deadline

App Engine, Cloud Runでそれなりに差があるが、結構長い。
Serverlessだと、長時間の処理は分割した方が良いので、どちらを使うか?という観点ではあまり気にならないかもしれない。

HTTP Request Deadline

シンプルにHTTP Requestを受け取った時の伸ばすことのできる最長のDeadline。
App EngineはScaling Configによって変わる。

  • App Engine Automatic Scaling : 10min
  • App Engine Basic Scaling and Manual Scaling : 24h
  • Cloud Run : 60min

Cloud Tasks, Cloud Scheduler

App Engine Target Task だと 送信先がBasic Scaling or Manual Scaling なら timeoutは 24h
Cloud Run 自体の Deadline は 60min だが、Cloud Run に Request を送るために使う HTTP Target Task が 30min までなので、こっちに引っ張られてしまう。

  • App Engine HTTP Task to Basic Scaling and Manual Scaling : 24h
  • HTTP Target Task : 30min

HTTP Target Task

Timeouts: for all HTTP Target task handlers the default timeout is 10 minutes, with a maximum of 30 minutes.

HTTP Target Job attempt_deadline

For HTTP targets, the default is 3 minutes. The deadline must be in the interval [15 seconds, 30 minutes].

Observability

Cloud ProfilerAlways CPU をONにしていない場合は、Cloud Run ではうまく動かないのは少し不便なところではある。
まぁ、CPU割当がちょくちょく停止するので、仕方ない気もする。

App Engine と Cloud Run を Mix するために

App Engine と Cloud Run をやりたいことに合わせてMixして使うのも結構強力だ。
それができる機能として Serverless NEG がある。
Serverless NEG はざっくり言うと External HTTP(S) Load Balancing の後ろに App Engine, Cloud Run, Cloud Functions を持ってこれるサービス。
Google Cloud Customer Engineer の Seiji Ariga さんが 噛み砕いた記事 を書いてくれている。
Path ごとに向き先を設定できるので、 /api/* は App Engine /image/upload はマシンスペックを大きくした Cloud Run に送ることができる。

更に External HTTP(S) Load Balancing が前にいれば、 Cloud Armor が使えたり、Tokyo Region の App Engine, Cloud Run に Custom Domain を割り当てた時に遅くなる問題 が解決されるなど良いことが多い。

Severless NEGを使う場合、App EngineやCloud Runをそのまま使うのに比べて 制限事項 があるので、一通り確認しておいた方がよい。
1 Projectでのシンプルな構成であれば問題なるものは少ないと思うが、複雑なことをやろうとしている場合、制限に引っかかるものがあるかもしれない。

Cloud Tasks, Cloud Pub/SubなどからのRequestをどこに送るのか?というのも少し気にする必要がある。
自分はHTTP LB経由ではなく直接App EngineやCloud Runに送ることが多い。
HTTP LBを経由する必要性をあまり感じないからだ。

余談

Cloud Run を見ていると、App Engine が一度目指した世界を今の技術でもう一度!という感じがします。
Managed VMs が生まれて5年ほどが経ち、現在の App Engine Flex になったわけですが、微妙にこれじゃない感がありました。
App Engine 自体が Google Cloud Platform より昔から存在していたこともあり、GCPに馴染んでいない点もちょいちょいあるわけですが、Cloud Run は今の GCP でもう一度 Serverless を作るなら、こうするぞ!という王道を爆走してる感じがあります。
課金体系も App Engine がまだベータだった時のものに近い リソース利用時間での課金となり、あの日の夢をもう一度見させてくれそうです。

Cloud Runに実装された双方向ストリーミングや WebSocketは、App Engineに要望はあったけど、実現されなかったものです。
App Engine Image Service など Web Application を作る上で便利で安価なサービスが詰まっていた Platform としての App Engine は失われていくけど、時代に合わせて進化していくGCPが来年も楽しみです。

Cloud Functions は?

ここまで読んだ読者の中には、Serverless には Cloud Functions もあるけど・・・?と思っている方もいるでしょう。
現状、僕はあまりCloud Functionsを使うことがありません。
まず、Cloud Functions は Web Application を作るのには適しません。
1 Instance 1 Function なので 10 API 作ろうと 10 Function Deployすることになり、アクセス権の制御など下回りの共通処理の UPDATE を考えると Deploy 祭りになってしまうのもつらいところです。
1 Instance で同時に処理する Request は 1 なのも大人数が同時に利用し、1画面開くと同じユーザから複数 Request が実行される Web Application 向きではありません。

そのため、Cloud Functions に向いてるのはユーザからの Request より、独立したイベント処理です。
例えば、画像が新しくアップロードされたイベントから、サムネイルを作るとか、cron で 30秒毎にキャッシュを作っておくなどの処理です。
ただ、これらの処理は App Engine や Cloud Run を使ってもできる処理なので、あまり Cloud Functions に分けておこうというモチベーションはありません。

更に僕の場合、Go がメインですが、Go だと Dockerfile 書くのも簡単だし、main 関数で Web Server を立ち上げるのも簡単です。
Cloud Run に簡単に乗せられるので、Cloud Run に寄せておきたい気持ちになります。
そんな感じで、僕の場合は Cloud Functions を使う理由がないので、今のところほとんど使っていません。

Cloud Functions にしかできないこと

Cloud Functions を選択するケースとして、Cloud Functions にしかない Event Trigger を使うケースがあります。

  • Cloud Firestore Trigger
  • Google Analytics for Firebase Triggers
  • Firebase Realtime Database Triggers
  • Firebase Authentication Triggers
  • Firebase Remote Config Triggers

これらの Trigger は Cloud Functions にしかないので、選択肢がありません。
ただ、 Event Trigger も Cloud Run が追いかけてる ので、Cloud Run 側の対応が進めば、好きな方を選べるようになりそうです。

GitHubで編集を提案

Discussion

bino98bino98

素晴らしい記事をありがとうございます!
自分もその2つの使い分けに悩む事があったので助かりました。

以前、RailsのプロダクトをCloudRunでホスティングさせた際に起きていた問題として、
CloudRunだと、コールドスタートにかかる時間が結構かかっていて(数十秒というレベル感)、遊休期間が長いプロダクトなどは対応が必要になりそうやなと思ってます。
https://cloud.google.com/blog/ja/products/gcp/3-ways-optimize-cloud-run-response-times

App engineだとどういう挙動になるのか分からないので、もし今後も比較される事がありました、ぜひ... (切実

sinmetalsinmetal

僕はGoがメインなのであれですが、スピンアップに時間がかかるフレームワークはオートスケールすることが前提のServerless Productだと不向きだと思いますねー。
Javaでの話ですが、App Engineが生まれた後、Javaにもともと存在していたフレームワークではスピンアップに時間がかかりすぎる (起動した後、動き続けるサーバであれば、起動に時間がかかったとしても、リクエストの処理が早い方がいい)ので、App Engineに最適化されたフレームワークが生まれました。

僕はRailsを全く知らないので分かりませんが、RailsがServerlessを意識していないのであれば、動きはするけど、現実的には厳しいという状態を脱することは難しいんじゃないかなと思います。
そういったものは、サーバのスケールを自分でコントロールできるGKEやGCEの方が向いてる感じですね。

sue445sue445

こんにちは。

appengine, Cloud Run, Rubyが一通り分かる人間です。

僕はRailsを全く知らないので分かりませんが、RailsがServerlessを意識していないのであれば、動きはするけど、現実的には厳しいという状態を脱することは難しいんじゃないかなと思います。

まさにこれで、Railsは起動に時間かかるのでオートスケールのように起動時間がシビアなシステムで使うのがそもそも間違いだと思います。僕ならこういう時sinatra使うかなぁ