Cloud Run functions の実行環境

Cloud Run functions は、インフラストラクチャ、オペレーティング システム、およびランタイム環境を運用する、フルマネージド サーバーレス環境で動作します。各関数は、互いに切り離された独自の安全な実行コンテキストで動作し、自動的にスケーリングします。また、そのライフサイクルは他の関数とは独立しています。

ランタイム

Cloud Run functions では、複数の言語のランタイムをサポートしています。各パッケージには、システム パッケージの標準セットと、その言語に必要なツールとライブラリが含まれています。コマンドラインから、または Terraform を介して関数をデプロイする場合は、ランタイム ID 値が必要になります。

セキュリティとメンテナンスの更新は、すべての Cloud Run functions と Cloud Run functions(第 1 世代)の実行環境で利用可能です。これらの更新は、環境と構成に応じて自動または手動で適用されます。実行環境の更新の詳細については、Cloud Run 関数の保護をご覧ください。

ランタイム イメージは、Artifact Registry が利用可能なすべてのリージョンでホストされます。URI の最初の部分を目的のリージョンに置き換えることで、ランタイム イメージのパスをカスタマイズできます。

REGION-docker.pkg.dev/serverless-runtimes/STACK/runtimes/RUNTIME_ID

次のように置き換えます。

  • REGION: 優先するリージョン(us-central1 など)
  • STACK: 優先オペレーティング システム スタック(google-22-full など)
  • RUNTIME_ID は、関数で使用されるランタイム ID(python310 など)に置き換えます。

たとえば、google-22-full スタックを使用して us-central1 でホストされている最新の Node.js 20 ベースイメージは、次の URL で参照されます: us-central1-docker.pkg.dev/serverless-runtimes/google-22-full/runtimes/nodejs22

Node.js

ランタイム 生成 ランタイム ID スタック ランタイム ベースイメージ
Node.js 22
(プレビュー版のみ)
関数の実行 nodejs22 google-22-full google-22-full/nodejs22
Node.js 20 第 1 世代、Run 関数 nodejs20 google-22-full google-22-full/nodejs20
Node.js 18 第 1 世代、Run 関数 nodejs18 google-22-full google-22-full/nodejs18
Node.js 16 第 1 世代、Run 関数 nodejs16 google-18-full google-18-full/nodjes16
Node.js 14 第 1 世代、Run 関数 nodejs14 google-18-full google-18-full/nodjes14
Node.js 12 第 1 世代、Run 関数 nodejs12 google-18-full google-18-full/nodjes14
Node.js 10 第 1 世代、Run 関数 nodejs10 google-18-full google-18-full/nodjes10
Node.js 8 第 1 世代、Run 関数 nodejs8 廃止 廃止
Node.js 6 第 1 世代、Run 関数 nodejs6 廃止 廃止

Python

ランタイム 生成 ランタイム ID スタック ランタイム ベースイメージ
Python 3.12 第 1 世代、Run 関数 python312 google-22-full google-22-full/python312
Python 3.11 第 1 世代、Run 関数 python311 google-22-full google-22-full/python311
Python 3.10 第 1 世代、Run 関数 python310 google-22-full google-22-full/python310
Python 3.9 第 1 世代、Run 関数 python39 google-18-full google-18-full/python39
Python 3.8 第 1 世代、Run 関数 python38 google-18-full google-18-full/python38
Python 3.7 第 1 世代、Run 関数 python37 google-18-full google-18-full/python37

Go

ランタイム 生成 ランタイム ID スタック ランタイム ベースイメージ
Go 1.22 関数の実行 go122 google-22-full google-22-full/go122
Go 1.21 関数の実行 go121 google-22-full google-22-full/go121
Go 1.20 関数の実行 go120 google-22-full google-22-full/go120
Go 1.19 第 1 世代、Run 関数 go119 google-22-full google-22-full/go119
Go 1.18 第 1 世代、Run 関数 go118 google-22-full google-22-full/go120
Go 1.16 第 1 世代、Run 関数 go116 google-18-full google-18-full/go116
Go 1.13 第 1 世代、Run 関数 go113 google-18-full google-18-full/go113
Go 1.11 第 1 世代、Run 関数 go111 廃止 廃止

Java

ランタイム 生成 ランタイム ID スタック ランタイム ベースイメージ
Java 21 関数の実行 java21 google-22-full google-22-full/java21
Java 17 第 1 世代、Run 関数 java17 google-22-full google-22-full/java17
Java 11 第 1 世代、Run 関数 java11 google-18 google-18/java11

Ruby

ランタイム 生成 ランタイム ID スタック ランタイム ベースイメージ
Ruby 3.3 第 1 世代、Run 関数 ruby33 google-22-full google-22-full/ruby33
Ruby 3.2 第 1 世代、Run 関数 ruby32 google-22-full google-22-full/ruby32
Ruby 3.0 第 1 世代、Run 関数 ruby30 google-18-full google-18-full/ruby30
Ruby 2.7 第 1 世代、Run 関数 ruby27 google-18-full google-18-full/ruby27
Ruby 2.6 第 1 世代、Run 関数 ruby26 google-18-full google-18-full/ruby26

PHP

ランタイム 生成 ランタイム ID スタック ランタイム ベースイメージ
PHP 8.3 関数の実行 php83 google-22-full google-22-full/php83
PHP 8.2 第 1 世代、Run 関数 php82 google-22-full google-22-full/php82
PHP 8.1 第 1 世代、Run 関数 php81 google-18-full google-18-full/php81
PHP 7.4 第 1 世代、Run 関数 php74 google-18-full google-18-full/php74

.NET Core

ランタイム 生成 ランタイム ID スタック ランタイム ベースイメージ
.NET Core 8 関数の実行 dotnet8 google-22-full google-22-full/dotnet8
.NET Core 6 第 1 世代、Run 関数 dotnet6 google-22-full google-22-full/dotnet6
.NET Core 3 第 1 世代、Run 関数 dotnet3 google-18-full google-18-full/dotnet3

自動スケーリングの動作

Cloud Run functions はサーバーレス パラダイムを実装しています。このパラダイムでは、サーバーや仮想マシンなどの基礎となるインフラストラクチャを意識せずにコードを実行できます。デプロイ後、関数は自動的に管理され、スケーリングされます。

Cloud Run functions は、受信したリクエストを関数のインスタンスに割り当てて処理します。リクエストの量と既存の関数インスタンスの数に応じて、Cloud Run functions は既存のインスタンスに要求を割り当てるか、新しいインスタンスを作成します。

インバウンド リクエストの量が既存のインスタンス数を超えた場合、Cloud Run functions は複数の新しいインスタンスを開始し、リクエストを処理します。この自動スケーリングにより、Cloud Run functions は関数の異なるインスタンスを使用して、複数のリクエストを同時に処理できるようになります。

無制限のスケーリングが好ましくない場合もあります。これに対応するため、Cloud Run functions では、特定の関数について任意の時点で共存可能な最大インスタンス数を構成できます。

ステートレス性

関数の自動管理とスケーリングを有効にするには、関数がステートレスである必要があります。つまり、1 つの関数呼び出しが、前の呼び出しで設定されたメモリ内の状態に依存しないようにする必要があります。呼び出しは、グローバル変数、メモリ、ファイル システムなどの状態を共有しない別の関数インスタンスによって処理されます。

関数呼び出し間で状態を共有する必要がある場合は、関数で MemorystoreDatastoreFirestoreCloud Storage などのサービスを使用してデータを保持する必要があります。Google Cloud が提供するデータベースとストレージ オプションの詳細については、Google Cloud データベースGoogle Cloud ストレージ プロダクトをご覧ください。

同時実行

Cloud Run functions

Cloud Run 関数では、1 つの関数インスタンスで複数の同時リクエストを処理できます。これは、すでにウォーム状態のインスタンスが複数のリクエストを同時に処理できるため、コールド スタートの発生を防ぎ、全体的なレイテンシを短縮するのに役立ちます。詳しくは、同時実行をご覧ください。

Cloud Run functions(第 1 世代)

Cloud Run functions(第 1 世代)では、関数の各インスタンスは一度に 1 つの同時リクエストを処理します。コードが 1 つのリクエストを処理している間、次のリクエストが同じインスタンスにルーティングされることはありません。元のリクエストは、割り当てられたリソース(メモリと CPU)のすべてを使用できます。

Cloud Run functions(第 1 世代)の同時リクエストはさまざまな関数インスタンスで処理されるため、変数やローカルメモリは共有されません。詳細については、ステートレス性関数インスタンスの寿命をご覧ください。

コールド スタート

新しい関数インスタンスは、次の 2 つのケースで開始されます。

  • 関数がデプロイされた時点

  • 負荷をスケールアップするため、または、場合によっては既存のインスタンスを置き換えるために、新しい関数インスタンスが自動的に作成された時点

新しい関数インスタンスを開始すると、ランタイムとコードが読み込まれます。関数インスタンスのスタートアップ(コールド スタート)を含むリクエストは、既存の関数インスタンスに送られたリクエストより遅くなる可能性があります。ただし、関数にかかる負荷が安定している場合は、関数が頻繁にクラッシュして、関数環境の再起動が必要にならない限り、コールド スタートの回数は無視できます。

関数コードがキャッチされていない例外をスローしたか、現在のプロセスをクラッシュさせた場合、関数インスタンスが再起動されることがあります。これにより、コールド スタートが増え、レイテンシが増加する可能性があります。例外をキャッチし、現在のプロセスの終了を回避することをおすすめします。Cloud Run functions でエラーを処理して報告する方法については、エラーの報告をご覧ください。

関数がレイテンシの影響を受けやすい場合は、コールド スタートを回避できるようインスタンスの最小数を設定することを検討してください。

関数インスタンスの寿命

一般に、関数インスタンスは、持続トラフィックの不足や関数のクラッシュによってインスタンス数がスケールダウンされない限り、回復力があり、後続の関数呼び出しで再利用されます。つまり、ある関数の実行が終了すると、別の関数呼び出しが同じ関数インスタンスによって処理されます。

関数スコープとグローバル スコープ

単一の関数呼び出しでは、エントリ ポイントとして宣言された関数の本体だけが実行されます。関数のソースコードのグローバル スコープは、コールド スタートでのみ実行されます。すでに初期化されているインスタンスでは実行されません。

Node.js

const functions = require('@google-cloud/functions-framework');

// TODO(developer): Define your own computations
const {lightComputation, heavyComputation} = require('./computations');

// Global (instance-wide) scope
// This computation runs once (at instance cold-start)
const instanceVar = heavyComputation();

/**
 * HTTP function that declares a variable.
 *
 * @param {Object} req request context.
 * @param {Object} res response context.
 */
functions.http('scopeDemo', (req, res) => {
  // Per-function scope
  // This computation runs every time this function is called
  const functionVar = lightComputation();

  res.send(`Per instance: ${instanceVar}, per function: ${functionVar}`);
});

Python

import time

import functions_framework


# Placeholder
def heavy_computation():
    return time.time()


# Placeholder
def light_computation():
    return time.time()


# Global (instance-wide) scope
# This computation runs at instance cold-start
instance_var = heavy_computation()


@functions_framework.http
def scope_demo(request):
    """
    HTTP Cloud Function that declares a variable.
    Args:
        request (flask.Request): The request object.
        <http://flask.pocoo.org/docs/1.0/api/#flask.Request>
    Returns:
        The response text, or any set of values that can be turned into a
        Response object using `make_response`
        <http://flask.pocoo.org/docs/1.0/api/#flask.Flask.make_response>.
    """

    # Per-function scope
    # This computation runs every time this function is called
    function_var = light_computation()
    return f"Instance: {instance_var}; function: {function_var}"

Go


// h is in the global (instance-wide) scope.
var h string

// init runs during package initialization. So, this will only run during an
// an instance's cold start.
func init() {
	h = heavyComputation()
	functions.HTTP("ScopeDemo", ScopeDemo)
}

// ScopeDemo is an example of using globally and locally
// scoped variables in a function.
func ScopeDemo(w http.ResponseWriter, r *http.Request) {
	l := lightComputation()
	fmt.Fprintf(w, "Global: %q, Local: %q", h, l)
}

Java


import com.google.cloud.functions.HttpFunction;
import com.google.cloud.functions.HttpRequest;
import com.google.cloud.functions.HttpResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;

public class Scopes implements HttpFunction {
  // Global (instance-wide) scope
  // This computation runs at instance cold-start.
  // Warning: Class variables used in functions code must be thread-safe.
  private static final int INSTANCE_VAR = heavyComputation();

  @Override
  public void service(HttpRequest request, HttpResponse response)
      throws IOException {
    // Per-function scope
    // This computation runs every time this function is called
    int functionVar = lightComputation();

    var writer = new PrintWriter(response.getWriter());
    writer.printf("Instance: %s; function: %s", INSTANCE_VAR, functionVar);
  }

  private static int lightComputation() {
    int[] numbers = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    return Arrays.stream(numbers).sum();
  }

  private static int heavyComputation() {
    int[] numbers = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    return Arrays.stream(numbers).reduce((t, x) -> t * x).getAsInt();
  }
}

Ruby

# Global (instance-wide) scope.
# This block runs on cold start, before any function is invoked.
#
# Note: It is usually best to run global initialization in an on_startup block
# instead at the top level of the Ruby file. This is because top-level code
# could be executed to verify the function during deployment, whereas an
# on_startup block is run only when an actual function instance is starting up.
FunctionsFramework.on_startup do
  instance_data = perform_heavy_computation

  # To pass data into function invocations, the best practice is to set a
  # key-value pair using the Ruby Function Framework's built-in "set_global"
  # method. Functions can call the "global" method to retrieve the data by key.
  # (You can also use Ruby global variables or "toplevel" local variables, but
  # they can make it difficult to isolate global data for testing.)
  set_global :my_instance_data, instance_data
end

FunctionsFramework.http "tips_scopes" do |_request|
  # Per-function scope.
  # This method is called every time this function is called.
  invocation_data = perform_light_computation

  # Retrieve the data computed by the on_startup block.
  instance_data = global :my_instance_data

  "instance: #{instance_data}; function: #{invocation_data}"
end

パフォーマンスを最適化するためにグローバル変数を使用できますが、以前の関数呼び出しでグローバル スコープに設定された状態に依存しないでください。詳細については、ステートレス性をご覧ください。

関数インスタンスごとに、関数コードの呼び出し前にグローバル スコープが 1 回だけ実行されていると想定できますが、グローバル スコープの総実行回数やタイミングは自動スケーリングのアクティビティによって異なる可能性があるため、これらに依存しないようにしてください。

関数実行タイムライン

関数は、その実行期間にのみ、割り当てられたリソース(メモリと CPU)にアクセスできます。実行期間外に実行されるコードは必ず実行されるとは限りません。これらのコードはいつでも停止できます。そのため、必ず、関数実行の終了を正確に通知して、それを超えたコードの実行を回避する必要があります。詳細については、HTTP 関数バックグラウンド関数CloudEvent 関数をご覧ください。

関数の実行には、関数のタイムアウト時間も適用されます。詳細については、関数のタイムアウトをご覧ください。

アプリケーションを初期化する場合は、実行タイムラインを考慮してください。バックグラウンド タスクは初期化時にグローバル スコープで作成しないでください。作成すると、リクエストがリクエストの処理時間外に実行されます。

実行保証

通常、関数は、送られてきたイベントごとに 1 回ずつ呼び出されます。ただし、Cloud Run functions は、エラーシナリオに違いがあるため、すべてのケースで単一の呼び出しを保証するわけではありません。

1 つのイベントで関数が呼び出される最大回数または最小回数は、関数の種類によって異なります。

  • HTTP 関数は、多くても 1 回しか呼び出されません。これは HTTP 呼び出しの同期性によるもので、関数呼び出し中に発生したエラーは再試行されずに返されることを意味します。HTTP 関数の呼び出し側は、エラーを処理し、必要に応じて再試行する必要があります。

  • イベント ドリブン関数は少なくとも 1 回呼び出されます。イベントの処理は基本的に非同期で行われます。つまり、呼び出し側がレスポンスを待つ必要はありません。まれなケースですが、イベントを確実に処理するため、イベント ドリブン関数が 2 回以上呼び出されることもあります。イベント ドリブン関数の呼び出しがエラーで失敗した場合、その関数に対する失敗時の再試行が有効になっていない限り、再び呼び出されることはありません。

関数が再実行時に正しく動作することを保証するには、イベントが複数回発生した場合でも望ましい結果(および副作用)をもたらすように関数を実装することで、関数をべき等にする必要があります。HTTP 関数の場合は、呼び出し側が HTTP 関数エンドポイントに対する呼び出しを再試行した場合でも、関数が望ましい値を返すことも意味します。関数をべき等にする方法の詳細については、イベント ドリブン関数の再試行をご覧ください。

メモリとファイル システム

各関数には一定量のメモリが割り当てられます。デプロイ時にメモリ容量を構成できます。詳細については、メモリ上限をご覧ください。

関数の実行環境には、関数でデプロイされたソースファイルとディレクトリを含むインメモリ ファイル システムが含まれています(ソースコードの構造化をご覧ください)。ソースファイルを含むディレクトリは読み取り専用ですが、ファイル システムの残りの部分は書き込み可能です(オペレーティング システムで使用されるファイルを除く)。ファイル システムの使用は、関数のメモリ使用量にカウントされます。

関数は、各プログラミング言語の標準メソッドを使用して、ファイル システムを操作できます。

ネットワーク

関数は、ランタイムに提供される組み込みライブラリか、依存関係として含まれるサードパーティ ライブラリを使用して、各プログラミング言語の標準メソッドを使用して公共のインターネットにアクセスできます。

ネットワークの最適化で説明されているように、関数呼び出し間でネットワーク接続を再利用してみてください。ただし、システムが 10 分以上未使用状態の接続を閉じた後、切断された接続を再利用しようとすると、「接続のリセット」エラーが発生することがあります。コードは、閉じられた接続を適切に処理するライブラリを使用するか、低レベルのネットワーキング構造を使用している場合は、閉じられた接続を明示的に処理する必要があります。

関数の分離

デプロイされた関数は他のすべての関数から分離されます。これには、同じソースファイルからデプロイされたものも含まれます。特に、メモリ、グローバル変数、ファイル システムなどの状態は共有されません。

デプロイされた関数間でデータを共有するには、MemorystoreDatastoreFirestoreCloud Storage などのサービスを使用します。また、関数で適切なトリガーを使用して必要なデータを渡し、別の関数を呼び出すこともできます。たとえば、HTTP 関数のエンドポイントに HTTP リクエストを送信します。また、Pub/Sub トピックにメッセージをパブリッシュして Pub/Sub 関数をトリガーします。