Cloud Run が作る世界 #devio2022

DevelopersIO 2022のビデオセッションにて、「Cloud Run が作る世界」というテーマでお話しました。その動画と関連資料をご紹介します。
2022.07.22

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

MADグループ@福岡 の 田中孝明 です。 Developers.IO 2022 〜技術で心を揺さぶる3日間〜 にて「Cloud Run が作る世界」というテーマでお話ししましたので、内容を簡単にご紹介します。

動画

資料

内容

Cloud Run

Cloud Run は2019年にデビューした、コンテナを直接実行できるマネージドコンピューティングプラットフォームです。

その強力な機能を一言で表すと、コンテナイメージをビルドできるものであれば、任意のプログラミング言語で記述されたコードをデプロイできることです。

コンテナイメージをビルドできるということは、ローカルの環境でも実行環境を再現しやすいということが言えます。

Cloud Run を使用すると、サービスの運用、構成、スケーリングに必要な時間がほとんどなくなるため、開発者はコーディングに集中することができます。クラスタの作成やインフラストラクチャの管理をすることなく Cloud Run でアプリ開発の生産性を向上できます。

当然ながら、Google Cloud 上の他のサービスと連携できます。

Pub/Sub を使用してメッセージを Cloud Run サービスのエンドポイントに push できます。

これは、 Cloud Storage バケットへのPutイベントなどを受信した後、Cloud Run のエンドポイントに向けて通知し、データに対して変換処理を Cloud Run で行うなどができます。

Cloud Scheduler を使用すれば、スケジュールに沿って Cloud Run サービスをトリガーできます。

これは cron ジョブで Cloud Run を使用するのと同じイメージになります。定期的に行う必要がある処理に対して有効な選択肢となり得ます。

Cloud Tasks を使用して、非同期に処理される Cloud Run のタスクをキューに入れることができます。

Eventarc とも連携できます。Eventarc は、60 以上の Google Cloud のサービスから Cloud Audit Logs 経由でイベントを受信することや、Pub/Sub にメッセージをパブリッシュしてカスタムソースからイベントを受信することなどができます。

Cloud Run デプロイ その1

まずは GitHub リポジトリから直接ビルドする方法があります。

Github の Repository に任意のコードと Dockerfile を配置しておきます。

次に Cloud Build を使い、コンテナのビルドを行います。ビルドが成功すれば、成果物が Container Registry に配置されます。 Cloud Run からは Container Registry の成果物を使用してデプロイされます。

Github からビルドして Cloud Run を実行

ローカル環境に、ビルドとアプリの実行ができるソースコードと Dockerfile を用意しましょう。今回は前々から試してみたかった Rust のライブラリ、 actix-web を試してみました。

ローカルの環境で実行して動作することを確認しましょう。試したソースコードは個人の Github リポジトリに配置していますので、よろしければ参照してください。

次に Cloud Build のトリガーの設定を行います。

先程のリポジトリをソースに設定します。

Github の指定したブランチに Push すると、 Artifact を作成するビルドが走ります。

タイムアウトがデフォルトだと 10分 なので注意してください、今回の環境だと 12分 かかりましたので、それを目安に伸ばしましょう。

次にCloud Runのサービスを作成しましょう。

まず、コンテナイメージURLに先程 Cloud Build で作成した コンテナイメージを指定します。

サービス名とリージョンは適当なものを指定してください。

その他の設定は必要に応じて行ってください。今回はお試しなので最小の構成で行っています。

ここまで来れば、いよいよCloud Runが起動します。

ローカルで実行していたものがそのままWEBで実行できるのが確認できます。

指定したURLが発行されるので、そちらにアクセスしてみましょう。

また、以前ビルドしたバージョンの切り替えも行うことができます。

バージョンアップを切り戻したい時などに活用してください。

Cloud Run が有効なケース

Cloud Run が有効なケースが Google Cloud から提示されているので、そちらをお話しします。

アプリが次の基準のすべてを満たしている場合が、Cloud Run が有用なケースになります。

まずは、HTTP、HTTP/2、WebSocket、gRPC 経由で配信されるリクエスト、ストリーム、イベントのいずれかを提供していること。

次にローカル永続ファイル システムを必要としないこと。

次に、同時に実行しているアプリの複数のインスタンスを処理するようにビルドされていること。

最後に Go / Java / Node.js / Python でコードが記述されているか、それ以外の言語の場合はコンテナ化されていることが条件になります。

アプリがこれらの条件を満たしている場合は、Cloud Run に適しています。

アプリがすべての基準を満たしていない場合は、Cloud Run には適していないので、ニーズに合う可能性がある他のプロダクトを探す必要があります。

Cloud Run でコードを実行する2つの方法

Cloud Run には現状、コードを実行する方法が2つあります。

一つは先ほどRustのサンプルで動作させたようなWebからのリクエストに対応するサービス。もう一つは作業を実行し、完了後に終了するコードを実行するジョブがあります。

サービス

Cloud Run は、受信したすべてのリクエストを迅速に処理するためにスケールアウトされます。サービスは、コンテナ インスタンスを 1,000 個まで迅速にスケールアップできます。割り当ての増加をリクエストした場合は、さらにスケールアップが可能です。需要が減ると、Cloud Run はアイドル状態のコンテナを削除します。コストやダウンストリーム システムの過負荷が懸念される場合は、インスタンスの最大数を制限できます。

Cloud Run のコンテナ インスタンスは使い捨てです。すべてのコンテナにはメモリ内に書き込み可能なファイル システム オーバーレイがあり、コンテナがシャットダウンした場合、これらは保持されません。Cloud Run は、スケールインなどの際に、インスタンスへのリクエスト送信を停止してシャットダウンするタイミングを独自に決定します。

コンテナ インスタンスに割り当てられた CPU とメモリは 100 ミリ秒単位で課金されます。そのため、ゼロへのスケーリングは、経済的な理由で魅力的な設定となります。最小インスタンス数を設定していない場合、サービスが使用されていなければ料金は発生しません。

有効にできる料金モデルは 2 つあります。

一つは リクエストベース です。

リクエストベースでは、コンテナインスタンスがリクエストを処理していない場合、CPU は割り当てられず、課金もされません。そのかわり、リクエストごとの料金が発生します。

もう一つはインスタンスベースです。

インスタンスベースではコンテナインスタンスの全期間に対して課金され、CPU が常に割り当てられます。そのかわり、リクエストごとの料金は発生しません。

Cloud Run サービスは、リクエストやイベントを処理するコードに最適です。

ジョブ (Preview)

こちらはプレビュー版であることにご注意願います。

コードが動作後に停止する場合、Cloud Run ジョブを使用してコードを実行できます。スクリプトが良い例です。

ジョブは、コードを実行するために 1 つのコンテナ インスタンスを開始できます。これは、スクリプトまたはツールを実行する一般的な方法です。さらに、独立した同一のコンテナインスタンスを複数並行して開始することもできます。これはジョブを配列のようにあつかうことができます。配列ジョブは複数の独立したタスクに分割できるジョブを迅速に処理します。

たとえば、Cloud Storage から 1,000 枚の画像を読み取ってサイズ変更や切り抜きを行う場合、連続して処理する方が、多くのコンテナ インスタンスで同時に処理する場合より時間がかかります。

Cloud Run ジョブは、作業の完了後に終了するコードを実行する場合に適しています。いくつか例を挙げましょう。

ひとつは、スクリプトまたはツールスクリプトを実行して、データベースの移行などの運用タスクを行うことに使えます。

もうひとつは、配列ジョブCloud Storage バケット内のすべてのファイルに高度な並列処理を行います。もうひとつは、スケジュールされたジョブ請求書の作成や送信を定期的に行い、データベース クエリの結果を XML 形式で保存し、数時間ごとにファイルをアップロードすることなどに適しています。

ただし、実行には 第2世代の実行環境が必要です。

第2世代

第1世代と第2世代はバージョンアップというより、そもそも実行されるものに違いがあります。

第1世代の実行環境はコールドスタート時間が高速でエミュレーションを行いますが、全てのOSのシステムコールが実行できるわけではありません。

ちなみにここでお伝えした、コールド スタートは第2世代のプレビュー版が終了するまでに、このパフォーマンスのギャップは小さくなるとのことです。

第2世代の実行環境では、Linuxの完全な互換性が実現され、CPUパフォーマンスの高速化ネットワークパフォーマンスの高速化、全てのシステムコール、名前空間、cgroupのサポートを含む、Linuxとの互換性が担保されます。

このように両世代違いがあるので、その違いを理解した上で選択する必要があります。

第2世代の実行環境では、ネットワークファイルシステムをコンテナ内のディレクトリにマウントできます。ファイルシステムをマウントすると、ホストシステムとコンテナインスタンスの間でリソースを共有し、コンテナインスタンスがガベージコレクションされた後もリソースを保持できます。

コンテナでファイルシステムのマウントやアプリケーションプロセスなどの複数のプロセスを実行する必要があるため、高度な Docker の知識が必要です。

まとめ

ローカルで動かせる環境をそのままコードとして実行できるので、開発者のマシンに依存しない開発が可能なことは、コードに集中したい開発者にとって、非常に有用な選択肢になると思います。インフラを意識しなくて済むのも良い点でしょう。

第二世代の登場で、今までサーバーレスで実現できなかった処理も今後は選択肢になりうることも重要なポイントでしょう。

Cloud Functions の項目で取り上げたように、Cloud Run のアップデートが他のサービスに追従したりと、 Cloud Run が Google Cloud のサービスとして根付いてきているのがわかるので、今後もアップデートを楽しみに待っていましょう。

参考資料