背景

cloud run + nuxtjs でサイトを作ってみたので、普段業務で使っている appengine と比較して感じたことなどを書いて行きます。


※この記事は書かれてから 1 年以上経っているため、当時の気持ちぐらいに取らえてください。

公式の見解は?

そもそも公式ドキュメントでは、どのように使い分けるよう書いてあるか見ていきます。
この記事を書いている段階では、こちらの公式ドキュメントにサーバーレスの選択について書いてあります。ぱっと見分かりやすいのが下の図ですね。

サーバーレスの選択フローチャート

こちらを見る限りは、単純(少数)な api なら cloud function。複雑(複数)な api やアプリケーションなら基本的に appengine を使っておいて、cloud run は言語などが対応していない時の appengine の代替案かなという印象を受けます。 flexible 環境は論点にも上がらない感じですね。

使用しての個人的な比較

それでは実際に使用してみての比較について書いていきます。個人的な感想なので、使っていない anthos 周りについては書いてありません。

build & deploy

サーバーレスアプリケーションにおいて、ci & cd でどのようにサーバに反映されるかはかなり重要だと思うのでまずはここから。 最初に cloud build の公式サンプルを見ていきます。

  • appengine の build & deploy
steps:
  - name: "gcr.io/cloud-builders/gcloud"
    args: ["app", "deploy"]
    timeout: "1600s"

github の push でトリガーされて、これで deploy 完了というのはほれぼれしますねー。
個人的な難点としては appengine のデプロイルールに縛られることだと思います。app.yml の設定、依存関係の解決、ディレクトリ構造。。。少し凝ったことをすると意外とハマりやすい印象です。 はまればすごい楽というイメージです。

  • cloud run の build & deploy
steps:
  # Build the container image
  - name: "gcr.io/cloud-builders/docker"
    args: ["build", "-t", "gcr.io/[PROJECT_ID]/[IMAGE]", "."]
  # Push the container image to Container Registry
  - name: "gcr.io/cloud-builders/docker"
    args: ["push", "gcr.io/[PROJECT_ID]/[IMAGE]"]
  # Deploy container image to Cloud Run
  - name: "gcr.io/cloud-builders/gcloud"
    args:
      [
        "run",
        "deploy",
        "[SERVICE_NAME]",
        "--image",
        "gcr.io/[PROJECT_ID]/[IMAGE]",
        "--region",
        "[REGION]",
        "--platform",
        "managed",
        "--allow-unauthenticated",
      ]
images:
  - gcr.io/[PROJECT_ID]/[IMAGE]

image のビルドも含めたの、appengine と比べると記述量が多いですね。
しかし、個人的には cloud run の方がデプロイはしやすく感じました。理由としましては

  • deploy option で cloud run 特有の設定を一元化されるため、一つのファイルに設定がまとまって分かりやすい。(appengine だと app.yml と deploy option に設定が分かれることがある)
  • 依存関係の解決 => メインファイルのビルド => 実行という手順以外で実行されるものは稀なケースじゃないため。Dockerfile に自分で実行手順をかけるのは結構楽。

上記のような理由があるため、個人的には、よりビルド手順が複雑になっていっても cloud run だとそこまで問題は起きにくいかなって思いました。

deploy 速度

デプロイ速度自体は、差分だけでビルドするときは appengine が爆速ですが、普通はそこまで変わらない印象です。そもそも、appengine も docker 作って docker を立ち上げているだけなので、速度自体は同じくらいなんじゃないかなって思います。

ローカル実行

appengine はdev_appserver.pyで、cloud run は Dockerfile を実行する形だと思います。Dockerfile 上でサービスアカウントを指定するのに、少し工夫が必要ですが、dev_appserver.py の意味わからない挙動に苦しめられることよりはマシかなって思います。
私は dev_appserver.py が嫌いなので、それだけですね。


追記: 今はそもそも dev_appserver.py 使わないのでここら辺は気にしませんね…

アクセス制御

appengine にはIAPという便利なものが有りますが、cloud run にはありません。これが結構不便です。開発中の URL を外に晒したくない場合は、API なら --no-allow-unauthenticated を付けてデプロイして、アクセストークンを取得するなどの方法がありますが、ウェブアプリとかだとかなりきついです。ログイン機能があるサイトなら良いですが、そうでもない限りは大分難しいかなって思います。

逆に cloud run ならではの設定もあります。先程の--no-allow-unauthenticatedを設定して、こちらのドキュメントのように bff にのみアクセスを許可することができたりします。iap の設定の楽さに比べると面倒ですが。。。(IAP もトークンの検証することを推奨されていますが。。)

因みに cloud function だと、--ingress-settings というオプションでアクセスを gcp ネットワークのみに絞れるため、非公開 api とか結構簡単に作れていい感じです。


追記: 現在は NEG による IAP が可能になったので Loadbancer は必要ですが、Cloud Run でも IAP できるようになっています。

Cold Start

cloud run が最小インスタスが 0 固定なのは辛いです。でも、最小インスタンスが0固定なのは廃止予定らしいので楽しみですね。デプロイ直後に遅いのはこの辺が関わっているのかなぁ?よくわかんないです。


追記: 最小インスタンス 1 以上が GA になりました。

GRPC サポート

grpc を使えるのは GCP の PaaS コンテンツでも cloud run だけです!(正確には CaaS ですが)appengine にはできないこと、と考えると一番の違いだと思います。現在はストリーミングに対応していませんが、将来的には対応予定らしいので、楽しみですね。


追記: ストリーミングに対応した。

まとめ

やっぱり、web アプリを開発中にアクセス制御となると、IAP があるのが強いですね。でも、IAM でアクセス制御を行える cloud run は api としては強いという思いです。 そのため、個人的な意見になりますが、web アプリケーションは appengine。バックエンドは cloud run という構成が良いのかなと思いました。web アプリケーションが bff だと、なおよしって感じですかね。
開発者としては、開発しやすく、色々オプションもあり、できる幅が広そうな cloud run は興味が惹かれるなーって感じました。

数年後の所感(2022/02/12 追記)

やはり今でも AppEngine のお手軽 IAP は強いです。また、静的ファイルの指定ができるためインスタンスの利用料金が Cloud Run に比べ安くなる傾向があります。 その面でもフロント部分は AppEngine という使い方が多いなぁというのを感じています。 SSR などで構成されたフロントエンドから、Cloud Run でできた API を叩くというような構成にするとセキュアでスケーラブルなシステムができる印象です。 適材適所って感じですね。