Cloud Run を GKE の代替として利用する

## はじめに
こんにちは、Datadog Japan で Sales Engineer をしている [**AoTo**](https://qiita.com/AoTo0330) です。
Google Cloud で好きなサービスは、圧倒的に **Cloud Run** です！

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

Google Cloud 上でマネージドな Kubernetes 環境を構築できる **Google Kubernetes Engine(GKE)** は大規模で柔軟な管理が行えるコンテナオーケストレーションサービスです。
一方、**Cloud Run** は Kubenetes からより抽象化された Knative 互換の API を利用したマネージドコンテナサービスです。

[2023年11月に **Cloud Run** のマルチコンテナ(サイドカー)機能が **GA(一般提供)**](https://cloud.google.com/run/docs/release-notes#November_13_2023) となり、**GKE** と **Cloud Run** の大きな差は縮まり、様々なユースケースで **Cloud Run** の利用を検討できるようになりました。

公式ドキュメントでは [**Cloud Run** から **GKE** への移行](https://cloud.google.com/run/docs/migrate/to-gke?hl=ja)について触れられていますが、今回は **GKE** から **Cloud Run** への移行を検討できる条件とその方法についてまとめています🐶

https://cloud.google.com/run/docs/migrate/to-gke?hl=ja

## Cloud Run の特性
### Cloud Run に適したアプリケーション
まずは稼働するアプリケーションが **Cloud Run** に適しているかを確認しましょう。これらの前提条件が合致しない場合は、**Cloud Run** の利用は**検討外**です。

 - 通信プロトコルは `HTTP`, `HTTP/2`, `WebSocket`, `gRPC` を用いる
 - 高パフォーマンスな永続ファイルストレージを必要としない
 - [インスタンスごとに8個の CPU と32 GiB のメモリを上限](https://cloud.google.com/run/quotas?hl=ja#cloud_run_limits)以上のリソースを必要としない
 - 厳密なスケーリング戦略を必要としない

以上の制限に該当する場合は、**GKE** の利用が推奨されます。

ですが、一般的な Kubernetes の利用事例を参照すると、それほど問題なく **Cloud Run** に移行できる場合があります。特に、[**Cloud Run** のリソース上限](https://cloud.google.com/run/quotas?hl=ja#cloud_run_limits)は一見厳しそうに見えますが、水平スケールを前提とする [**Kubernetes Deployments**](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/) に当てはめると十分に実現可能なことがわかります。

### Cloud Run の利点
さらに **Cloud Run** は高度に抽象化されたマネージドコンテナサービスのため、利用者の管理する部分のほとんどがコンテナに最小化されます。

![CloudRun_Components.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2363567/35229720-d7dc-6ccf-c573-bb5dd3f06bc6.png)

サービスのリクエストを受信する <INS>**Ingress コンテナ**はインスタンスに常に1つのみ</INS>で、その前段には <INS>TLS 終端やDoS 攻撃保護を担う [**Google Fron End(GFE)**](https://cloud.google.com/docs/security/infrastructure/design?hl=ja#google-frontend-service), [**Cloud Load Balancing**](https://cloud.google.com/load-balancing/docs/load-balancing-overview?hl=ja)</INS> と <INS>HTTP 受信リクエストを負荷分散する **HTTP プロキシ**</INS>が自動的に配置されます。

**Cloud Run** はサーバレスでもあるため、そのネットワークも大部分を Google Cloud が管理します。デフォルトでは[サーバレスネットワーク](https://cloud.google.com/run/docs/securing/private-networking?hl=ja)が適用される一方で、[プライベートネットワークと **Cloud Run**](https://cloud.google.com/run/docs/securing/private-networking?hl=ja)を構成する柔軟なオプションが用意されています。

つまり、デフォルトでは [**IAM 認証**](https://cloud.google.com/run/docs/securing/managing-access?hl=ja)や [**Ingress 制御**](https://cloud.google.com/run/docs/securing/ingress?hl=ja)で HTTP リクエストを制御しながら、[**Direct VPC Egress**](https://cloud.google.com/run/docs/configuring/vpc-direct-vpc?hl=ja) や [**VPC コネクタ**](https://cloud.google.com/run/docs/configuring/vpc-connectors?hl=ja)による VPC 内のリソースとの統合が可能です。さらに、[**サーバレスネットワークエンドポイントグループ(NEG)**](https://cloud.google.com/load-balancing/docs/negs/serverless-neg-concepts?hl=ja)によるネットワークアクセスの効率化・負荷分散や **NEG** を利用した [**Cloud Service Mesh**](https://cloud.google.com/service-mesh/docs/configure-cloud-service-mesh-for-cloud-run?hl=ja) の構成など、様々なネットワークオプションを活用し要件に合わせた環境を構築できます。

以下のように Kuberbenets による複雑な構成管理から脱却し、**Cloud Run** によるマネージドコンテナの恩恵を受けることができる場合は、**Cloud Run** を **GKE** の代替としても利用できます。

 - 複雑なスケーリング戦略を持たない、外部公開サービス環境
 - マルチリージョン冗長が必要な、高可用サービス環境
 - ゼロスケールが有効な、ワークロードの波が大きな環境
 - マルチコンテナアプリケーションの動作検証環境

## GKE からの移行
**GKE** から移行する場合、単純な **Deployment** を定義した `app.yaml` ファイルは以下のように **Cloud Run** サービスの `app.yaml` のように書き換えることができます。

```diff_yaml:app.yaml
-apiVersion: apps/v1
+apiVersion: serving.knative.dev/v1
-kind: Deployment
+kind: Service
 metadata:
   name: my-app
-  namespace: default
+  namespace: PROJECT_NUMBER
   labels:
-    app: my-app
+    app: cloud.googleapis.com/location: REGION
 spec:
   template:
     metadata:
-      labels:
-        app: my-app
+       name: REVISION_NAME
+     annotations:
+       autoscaling.knative.dev/minScale: MIN_INSTANCES
+       autoscaling.knative.dev/maxScale: MAX_INSTANCES
     spec:
       containers:
       - image: gcr.io/cloudrun/hello
         ports: 
         - containerPort: 80
         env:
         - name: HELLO
           value: world
       - image: gcr.io/datadoghq/agent
         env:
         - name: SIDECAR
           value: woofwoof
-  replicas: 3
-  selector:
-    matchLabels:
-      app: my-app
```

詳細を全て解説はしませんが、**Cloud Run** は [**Knative Serving 互換**で yaml を記述](https://cloud.google.com/run/docs/reference/yaml/v1)します。そのため、`apiVersion: serving.knative.dev/v1`, `kind: Service` のように Kubernetes では見慣れない内容を記述します。

加えて **Cloud Run** の構成のために、プロジェクト ID が `.metadata.namespace` に定義されます。[ReplicaSet](https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/) のような記載は必要なく、**Cloud Run** インスタンスの最大最小スケーリングを `.spec.template.metadata.annotations.autoscaling.knative.dev/` で定義します。

簡略化のため記載を省略していますが、コンテナ定義の `ports.containerport`, `resource.limits`, `volumeMounts`, `command`, `args` などはそのまま利用できます。詳細は[Cloud Run YAML リファレンス](https://cloud.google.com/run/docs/reference/yaml/v1)をご参照ください。

https://cloud.google.com/run/docs/reference/yaml/v1

コンテナは10コンテナまで記載でき、そのうち Ingress コンテナは1つまでの点には注意が必要です。

## おわりに
**Cloud Run** はシングルコンテナのマネージドサービスから大幅に進化しています。現在は、Google Cloud 上のコンテナホスティングサービスとしては、マネージドサービスの恩恵を受けられる第一の選択肢として選定できるサービスです。

これまで **GKE** を利用してきた方も、これを機に **Cloud Run** の利用を検討してみてはいかがでしょうか🐶