で、Cloud Run と App Engine って何が違うの？

## はじめに
こんにちは、Datadog Japan で Sales Engineer をしている [**AoTo**](https://qiita.com/AoTo0330) です。

この投稿は **[<font color="#6495ED">AoTo Advent Calendar 2024</font>](https://qiita.com/advent-calendar/2024/aoto) 21日目**の記事です。

普段から Google Cloud を利用されている方や、PaaS やマネージドコンテナをの利用を検討する方が直面する、「**で、Cloud Run と Google App Engine って何が違うの？**」という疑問を解消するべくこのブログを執筆しています。

今回の比較対象は [<font color=#4285F4>**App Engine スタンダード環境**</font>](https://cloud.google.com/appengine/docs/standard?hl=ja)・[<font color=#DB4437>**App Engine フレキシブル環境**</font>](https://cloud.google.com/appengine/docs/flexible?hl=ja)・[<font color=#F4B400>**Cloud Run services**</font>](https://cloud.google.com/run/docs/overview/what-is-cloud-run?hl=ja#services) の3つです。特に、これらのサービスは全く異なる基盤から構成されていますが、それぞれの機能追加の結果、類似点が非常に多くなっています。App Engine のスタンダード/フレキシブル環境の違いに触れながら、Cloud run services とのユースケースの違いを考察します。

:::note warn
<font color=#4285F4>**App Engine スタンダード環境**</font>と <font color=#F4B400>**Cloud Run services**</font> はそれぞれ第一世代と第二世代があり、本ドキュメントは**第二世代**を対象として解説しています。
:::

**Cloud Run** 内の **serivces, jobs, functions** は『[で、Cloud Functions と Cloud Run って何が違うの？](https://qiita.com/AoTo0330/items/1977c1ae14381d274c0b)』で解説しています。

https://qiita.com/AoTo0330/items/1977c1ae14381d274c0b

<!--
ここからは、便宜上 **GAE Std, GAE flex, Cloud Run service** と記載します
-->

## まとめ
### 実行環境
 - <font color=#4285F4>**App Engine スタンダード環境**</font>は、コンテナインスタンスに事前構成されたランタイム環境上でコードをデプロイする
 - <font color=#DB4437>**App Engine フレキシブル環境**</font>は、**Compute Engine** を基盤とした Docker コンテナ内でコードを実行する
 - <font color=#F4B400>**Cloud Run services**</font> は、Knative Serving 互換のコンテナ上で実行する
 - <font color=#DB4437>**App Engine フレキシブル環境**</font>と <font color=#F4B400>**Cloud Run services**</font> は、`Dockerfile` 利用したコンテナイメージのデプロイができる

### スケーリングとセキュリティ
 - どのサービスも、アプリケーションの需要に応じた**オートスケール**が備わっている
 - <font color=#4285F4>**App Engine スタンダード環境**</font>と <font color=#F4B400>**Cloud Run services**</font> は、ゼロスケールに対応している
 - **セキュリティパッチ**は <font color=#4285F4>**App Engine スタンダード環境**</font>とコンテナイメージランタイムを除く <font color=#DB4437>**App Engine フレキシブル環境**</font>に自動適用され、<font color=#F4B400>**Cloud Run sevices**</font> は**ベースイメージ自動更新**が対応している

### サービス構成
 - <font color=#F4B400>**Cloud Run services**</font> のみ [GPU 構成](https://cloud.google.com/run/docs/configuring/services/gpu?hl=ja)に対応している
 - <font color=#4285F4>**App Engine スタンダード環境**</font> のみ[静的ファイルハンドラ](https://cloud.google.com/appengine/docs/standard/serving-static-files?tab=python&hl=ja#configuring_your_static_file_handlers)を構成し、コンピューティングリソースを使用せずに静的コンテンツを配信できる
 - <font color=#DB4437>**App Engine フレキシブル環境**</font>と <font color=#F4B400>**Cloud Run services**</font> は、**WebSocket 通信**を利用できる
 - <font color=#4285F4>**App Engine スタンダード環境**</font>と <font color=#F4B400>**Cloud Run services**</font> は、起動時間に応じた課金がされる
 - **App Engine** と **Cloud Run** は[リソースモデル](https://cloud.google.com/appengine/migration-center/run/compare-gae-with-run?hl=ja#resource_model)が異なる

### Simplified Chart
|  | <font color=#4285F4>App Engine<br>スタンダード環境</font> | <font color=#DB4437>App Engien<br>フレキシブル環境</font> | <font color=#F4B400>Cloud Run services</font> |
| -- | -- | -- | -- |
| デプロイ単位 | ソースコード | ソースコード<br>コンテナイメージ | ソースコード<br>コンテナイメージ |
| デプロイ構成 | [`app.yaml`](https://cloud.google.com/appengine/docs/standard/reference/app-yaml)<br>[`dispatch.yaml`](https://cloud.google.com/appengine/docs/standard/reference/dispatch-yaml) | [`app.yaml`](https://cloud.google.com/appengine/docs/standard/reference/app-yaml)<br>[`dispatch.yaml`](https://cloud.google.com/appengine/docs/standard/reference/dispatch-yaml) | [`service.yaml`](https://cloud.google.com/run/docs/reference/yaml/v1)<br>(Knative 仕様) |
| 実行環境 | gVisor 上のコンテナ | GCE 上の Docker | Knative Serving 互換 |
| タイムアウト | 自動:10分<br>手動:24時間 | 60分 | デフォルト:5分<br>最大:60分 |
| VPC 接続 | サーバレス VPC コネクタ | サーバレス VPC コネクタ | サーバレス VPC コネクタ or<br>ダイレクト VPC Egress |
| デプロイ時間 | 秒単位 | 分単位 | 秒単位 |
| エントリポイント | `app.yaml` の `entrypoint` 属性 or<br>ランタイムデフォルト | `app.yaml` の `entrypoint` 属性 or<br>ランタイムデフォルト | 言語固有の構成 or<br>`GOOGLE_ENTRYPOINT` 環境変数 |

https://cloud.google.com/appengine/migration-center/run/compare-gae-with-run?hl=ja

## 選定方法
今回に限らず、クラウドサービスの利用を検討する際は複数の類似サービスを比較・検討することが重要です。利用者はより運用・管理コストの低いマネージドサービスから検討していくことで、クラウドのメリットを最大限に享受できます。

**App Engine, Cloud Run** はどちらも**ソースコードデプロイ**と**コンテナデプロイ**が可能なマネージドサービス(**PaaS, CaaS**)です。従来は App Engine が PaaS、Cloud Run が CaaS として棲み分けされていましたが、それぞれの機能追加の結果、現在は類似機能がとても多くなっています。

こうした背景からも、どういった実行基盤で動作しており、どのような制限があるかを理解することで、どのようなユースケースに向いているかを知ることができます。

```mermaid
%%{init:{'theme':'forest'}}%%
flowchart LR
 1["Google Compute Engine"] --> 2[<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2363567/16cce992-198a-a2ff-dfe5-18b5131b95dc.png">]
 subgraph Cloud Run service
 2 --"①"--> 3["Custom runtime(Sandbox2)"]
 end
 1 --> 4[<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2363567/b92728f4-5c2e-3ada-13a6-dd9eacfb2cd5.png">]
 subgraph "App Engine フレキシブル"
 4 --"②"--> 5["Ubuntu OS(App runtime)"]
 4 --"③"-->6[Custom runtime]
 end
 7[Linux host] --> 8[<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2363567/43b3e93c-fe07-49fe-78dd-b4ac5d6baf88.png">]
 subgraph "App Engine スタンダード"
 8 --"④"--> 9["Ubuntu OS(App runtime)"]
 end

 a([実行基盤]) ----> b([サービス])
```


さらに、それぞれのサービスを選定する基準や方針は以下のように言い表せます。

 1. Knative Serving 互換の環境で `service.yaml` で構成しコンテナをデプロイしても良い
コンテナ設計を考慮せず、ソースコードデプロイで柔軟にスケールする環境が欲しい
 1. アプリケーションコードのみを管理したい上で、独自の `app.yaml` を扱える
 1. コンテナイメージの管理不要で `Dockerfile` のみで柔軟にスケールする環境が欲しい
 1. 各アプリケーションランタイムの制約が影響なく、独自の `app.yaml` を扱える

さて、ここまで対等に比較していましたが、**App Engine** には重大な制約があります。
各 **Google Cloud プロジェクト**に含めることができる App Engine アプリケーションは <font color=#DB4437>**$\huge{1 つだけ}$**</font>なんです。[^1]また、作成後に App Engine アプリケーションの**ロケーションを変更することもできません**。
[^1]: [App Engine 用の Google Cloud プロジェクトの設定](https://cloud.google.com/appengine/docs/flexible/managing-projects-apps-billing?hl=ja)より引用

こうした制限はドキュメントを眺めるだけではなかなかわかりづらいため、机上で検討する前に Google Cloud Console でも実際に検証してみることをお勧めします。

このように **Cloud Run** と **App Engine** はコンテナデプロイやソースコードデプロイが可能な類似したマネージドサービスですが、[リソースモデル](https://cloud.google.com/appengine/migration-center/run/compare-gae-with-run?hl=ja#resource_model)が大きく異なります。

**App Engine** は単一で最上位の Application リソースと、対応する `default` サービスが必要となります。この他に Application リソースは以下に Service, Version, Instance を配置する形になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2363567/372a844f-5f56-5e1b-534f-23d9df7debc8.png)

## サンプルアーキテクチャ
最後に、それぞれのサービスの特徴を活かしたアーキテクチャを考えてみましょう。

### <font color=#4285F4>**App Engine スタンダード環境**</font>と Cloud Storage で静的ウェブサイトのホスティング
![gae_static.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2363567/72cf5e52-e4c2-1216-5d24-adc75c954ba8.png)

**App Engine** を介して **Cloud Storage** 上の静的コンテンツをホスティングするアーキテクチャです。<font color=#4285F4>**App Engine スタンダード環境**</font>の[静的ファイル ハンドラ](https://cloud.google.com/appengine/docs/standard/serving-static-files?tab=python&hl=ja#configuring_your_static_file_handlers)を構成して、URI パスに応じたコンテンツ配信できます。

<font color=#4285F4>**App Engine スタンダード環境**</font>は静的ファイルハンドラを構成できるため、**Cloud Storage** 上の静的コンテンツをコンピューティング リソースを使用せずに配信できます。

https://cloud.google.com/appengine/docs/standard/hosting-a-static-website?hl=ja

### <font color=#DB4437>**App Engine フレキシブル環境**</font>でコンテナイメージを管理せず Rust アプリケーションの実行
![gae_flex_custom.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2363567/1a074f84-2cc8-372e-8ba0-c4866bb0ba0d.png)

<font color=#DB4437>**App Engine フレキシブル環境**</font>を用いた、任意のアプリケーション言語をカスタムランタイムを用いて実行するアーキテクチャです。`app.yaml` と `Dockerfile`、アプリケーションコードを用意するだけで、**Cloud Build** を介して簡単に任意のアプリケーションをビルド・デプロイし **App Engine** で実行できます。

<font color=#DB4437>**App Engine フレキシブル環境**</font>は Docker ベースのカスタムランタイムを実行することができるため、アプリケーションランタイムの制約を考慮せずにアプリケーションを実行できます。この時 **Cloud Build** を用いることで、ソースコードの変更がコミットされるとその他の要素を管理することなく新たなバージョンをデプロイできます。

### <font color=#F4B400>**Cloud Run services**</font> でマルチコンテナ LLM アプリのホスティング
![cr_llm_multi.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2363567/ca48e1c4-0d3d-fe24-0d45-8369f9bbbe0d.png)

<font color=#F4B400>**Cloud Run services**</font> を用いた、GPU を必要とするワークロードを実行する LLM アプリケーションをホスティングするアーキテクチャです。**Cloud Run** 内でフロントエンドコンテナと LLM アプリ、それらのパフォーマンスを監視するための監視エージェントをデプロイし、**Cloud GPU** を活用した LLM ワークロードを信頼性高く実行できます。

<font color=#F4B400>**Cloud Run services**</font> は**常時リソースを必要とするサービスをホスティング**し、**GPU** を活用したワークロードを実行できます。この時、**GPU** の利用と **[マルチコンテナ](https://cloud.google.com/run/docs/deploying?hl=ja#sidecars)によってコンテナ毎に役割を分離**し、複雑な LLM ワークロードを安定的に実行しパフォーマンスを監視できることが特徴です。[^2]
[^2]: 筆者のやりたいことを詰め込んだ内容のため、サービス選定や各要素の必要性は度外視してご覧ください🐶

## おわりに
App Engine と Cloud Run はどちらも多機能なサービスです。

どちらにもアップデートの歴史がありますが、App Engine は**15年を超える歴史**を持っており、それ故に当初の役割から大きく進化したサービスを提供しています。

一方で Cloud Run は**5年**という短い歴史で、Google Cloud のメインストリームとして、積極的な機能アップデートやサポート技術の追加を色濃く受けているサービスです。

本ブログを通して、全てのケースに *Cloud Run** を利用せずとも、**App Engine** を活かせる場面がいくつか残っていることがお分かりいただけたかと思います。

この考え方は、Cloud Run services と Google Kubernetes Engine(GKE) の選定の際も同様で、サービスに対する理解を深めることが重要です🐶