ローカル関数の開発

Cloud Run functions は、ターゲット デプロイ環境の外部で関数を実行する複数のメソッドをサポートしています。これは、反復型開発や、デプロイ前に関数をテストする必要がある状況で特に有用です。

関数をデプロイすることなく実行できる機能により、ローカルテスト、データの局所性の制限の遵守、マルチクラウド デプロイを簡素化できます。

  • データの局所性の制限: 本番環境データにアクセスせずにローカルで関数をテストし、組織のデータの局所性ルールに違反しないようにします。

  • マルチクラウド デプロイ: マルチクラウド関数のデプロイは、信頼性が重要となる環境でダウンタイムのリスクを軽減するために確立されたパターンです。Cloud Run functions 自体以外の環境に関数をデプロイすると、アプリケーションに対する計画外のダウンタイムによるリスクを軽減できます。

Functions Framework を使用して関数をローカルで開発する

Functions Framework を使用して、関数をローカルで開発してテストできます。関数をローカルで開発すると、関数コンテナを再ビルドしなくてもコードをテストできます。これにより、時間を節約し、関数のテストを容易にできます。

Cloud Run は、オープンソースの Functions Framework ライブラリを使用して、デプロイされた関数を永続的な HTTP アプリケーションでラップします。

Functions Framework は、ローカルマシン、オンプレミス サーバー、Compute Engine など、言語自体をサポートする他のプラットフォームでも実行できます。

依存関係のインストール

関数のディレクトリに、使用する言語の Functions Framework ライブラリをインストールします。

Node.js

npm install --save-dev @google-cloud/functions-framework

Python

pip3 install functions-framework

Go

go install github.com/GoogleCloudPlatform/functions-framework-go/funcframework

Java

Maven

Maven を使用している場合は、次のものを pom.xml ファイルに追加します。

<dependency>
  <groupId>com.google.cloud.functions</groupId>
  <artifactId>functions-framework-api</artifactId>
  <version>1.1.0</version>
  <scope>provided</scope>
</dependency>

Gradle

Gradle を使用している場合は、次のものを build.gradle ファイルに追加します。

dependencies {
  // Every function needs this dependency to get the Functions Framework API.
  compileOnly 'com.google.cloud.functions:functions-framework-api:1.1.0'

  // To run function locally using Functions Framework's local invoker
  invoker 'com.google.cloud.functions.invoker:java-function-invoker:1.3.1'
}

詳細については、Java Functions Framework ライブラリをご覧ください。

C#

次のコマンドは、.NET Templates を使用して、.NET Functions Framework ライブラリを依存関係とする.NET 関数の新しいコードベースを作成します。

# HTTP functions
dotnet new gcf-http

# CloudEvent functions
dotnet new gcf-event

Ruby

Ruby では、Cloud Run にデプロイするために Functions Framework を関数の依存関係に追加する必要があります

bundle add functions_framework

PHP

composer require google/cloud-functions-framework

Functions Framework を構成する

Functions Framework を使用して関数を実行する前に、実行する関数のタイプと名前を指定する必要があります。これらの属性は、コマンドライン インターフェース(CLI)のフラグまたは環境変数として指定できます。

サポートされる関数のタイプ

Functions Framework は、Cloud Run functions でサポートされている両方のタイプの関数をサポートしています。すべての言語ランタイムは、httpcloudevent の両方の署名タイプをサポートしています。

関数タイプ 署名タイプ 説明 サポート ランタイム
HTTP でトリガーされる関数 http HTTP リクエストを受信して応答する関数。 すべてのランタイム
CloudEvent 関数 cloudevent 業界標準のイベント形式。 すべてのランタイム

実行する関数を指定する

Functions Framework で関数を実行する前に、コード内のどの関数を実行するかを指定する必要があります。ほとんどの言語では、以下の表にあるターゲット モデルのメソッド名を指定します。ただし、Java ランタイムと .NET ランタイムには例外があります。

言語ごとの手順

各言語でサポートされている構成オプションの一覧については、次の表をご覧ください。

Node.js

CLI の引数 環境変数 説明
--port PORT リクエストをリッスンするポート。(デフォルト: 8080
--target FUNCTION_TARGET 呼び出される export 関数の名前。(デフォルト: function
--signature-type FUNCTION_SIGNATURE_TYPE 関数で使用される署名タイプ。http(デフォルト)または cloudevent を指定できます。

Python

CLI の引数 環境変数 説明
--port PORT リクエストをリッスンするポート。(デフォルト: 8080
--target FUNCTION_TARGET 呼び出される export 関数の名前。(デフォルト: function
--signature-type FUNCTION_SIGNATURE_TYPE 関数で使用される署名タイプ。http(デフォルト)または cloudevent を指定できます。

Go

環境変数 説明
PORT リクエストをリッスンするポート。(デフォルト: 8080

Java

引数名 環境変数 説明
run.port PORT リクエストをリッスンするポート。(デフォルト: 8080
run.functionTarget FUNCTION_TARGET 呼び出される export 関数の名前。(デフォルト: function

C#

CLI の引数 環境変数 説明
--port PORT リクエストをリッスンするポート。(デフォルト: 8080
--target(または引数のみ) FUNCTION_TARGET 呼び出される関数の classname。(デフォルト: function

Ruby

CLI の引数 環境変数 説明
--port PORT リクエストをリッスンするポート。(デフォルト: 8080
--target FUNCTION_TARGET 呼び出される export 関数の名前。(デフォルト: function

PHP

環境変数 説明
FUNCTION_TARGET 呼び出される関数の名前。(デフォルト: function
FUNCTION_SIGNATURE_TYPE 関数で使用される署名タイプ。http(デフォルト)または cloudevent を指定できます。

Functions Framework を構成して実行する手順は次のとおりです。

Node.js

Node.js Functions Framework では、関数の名前と署名タイプをコマンドライン引数または環境変数で指定できます。

以下の例に示すように、必要な CLI 引数を指定した start スクリプトを追加して、これらの値を package.json ビルドファイルに指定することもできます。

"scripts": {
"start": "npx functions-framework --target=YOUR_FUNCTION_NAME [--signature-type=YOUR_SIGNATURE_TYPE]"
}

環境変数を使用しても同じことができます。

"scripts": {
"start": "FUNCTION_TARGET=YOUR_FUNCTION_NAME FUNCTION_SIGNATURE_TYPE=YOUR_SIGNATURE_TYPE npx functions-framework"
}

YOUR_FUNCTION_NAME は関数のメソッド名で置き換えます。YOUR_SIGNATURE_TYPE(該当する場合)は、サポートされている関数タイプに示すように、関数の署名タイプに置き換えます。

Python

Python Functions Framework では、関数の名前と署名タイプをコマンドライン引数または環境変数で指定できます。コマンドライン引数は、フレームワークを実行するときに指定する必要があります。

Go

Go Functions Framework では、funcframework.RegisterHTTPFunctionContext を使用して関数の対象と署名タイプを指定します。

Java

Java Functions Framework は、次の 3 つのソースから構成データを受け取ります(優先順位の最も高いものから順に示します)。

  • コマンドライン引数
  • ビルドファイル
  • 環境変数

コマンドライン引数

Maven

実行するコマンドラインを指定するには、次のコマンドライン インターフェース(CLI)フラグを mvn コマンドに追加します。

-Drun.functionTarget=YOUR_FUNCTION_NAME

同様の CLI フラグを追加して、ターゲット ポートを指定することもできます。

-Drun.port=12345

Gradle

Gradle の CLI フラグは、Maven の場合とほぼ同じです。Gradle の場合は、以下に示すように、各フラグの先頭の -D-P に置き換えます。

# Maven version

-Drun.functionTarget=...

# Gradle version

-Prun.functionTarget=...

ビルドファイル

実行する関数は、プロジェクトのビルドファイルで指定することもできます。Maven と Gradle には同様の CLI フラグがありますが、buildfile 句は大きく異なります。

Maven

Maven ビルドファイルの名前は pom.xml です。このファイルに次の句を追加して、ターゲット関数を指定します。

<plugin>
  <groupId>com.google.cloud.functions</groupId>
  <artifactId>function-maven-plugin</artifactId>
  <version>0.11.0</version>
  <configuration>
    <functionTarget>functions.HelloWorld</functionTarget>
  </configuration>
</plugin>

<functionTarget> は、関数のクラス名に置き換えますたとえば、パッケージ functions 内のクラス名が HelloCloudFunctions の場合、クラス名は functions.HelloCloudFunctions になります。これは、親のビルドファイル(pom.xml または build.gradle)からの相対パスです。

Gradle

Gradle ビルドファイルの名前は、build.gradle です。このファイルに次の句を追加して、ターゲット関数を指定します。

// Register a "runFunction" task to run the function locally
tasks.register("runFunction", JavaExec) {
  main = 'com.google.cloud.functions.invoker.runner.Invoker'
  classpath(configurations.invoker)
  inputs.files(configurations.runtimeClasspath, sourceSets.main.output)
  args(
    '--target', project.findProperty('run.functionTarget') ?: '',
    '--port', project.findProperty('run.port') ?: 8080
  )
  doFirst {
    args('--classpath', files(configurations.runtimeClasspath, sourceSets.main.output).asPath)
  }
}

C#

dotnet new と前述のいずれかのテンプレートを使用してプロジェクトを作成すると、.NET Functions Framework によって関数が自動的に検出されます。

プロジェクトに複数の関数がある場合は、フレームワークの実行セクションで関数の実行方法を確認してください。

Ruby

Ruby Functions Framework では、関数の名前と署名タイプをコマンドライン引数または環境変数で指定できます。コマンドライン引数は、フレームワークを実行するときに指定する必要があります。

PHP

PHP Functions Framework では、環境変数をコマンドライン環境変数として指定できます。

また、次の例に示すように、start スクリプトを追加することで、これらの値を composer.json ビルドファイルに指定することもできます。

"scripts": {
 "start": [
     "Composer\\Config::disableProcessTimeout",
     "FUNCTION_TARGET=YOUR_FUNCTION_NAME php -S localhost:${PORT:-8080} vendor/bin/router.php"
].
}

YOUR_FUNCTION_NAME は関数の名前に置き換えます。YOUR_SIGNATURE_TYPE(該当する場合)は、ここに示す例には含まれていません。

関数を実行する

Functions Framework を使用して関数を実行するには、次のコマンドを使用します。デフォルトでは、PORT 値を明示的に指定しない限り、関数には localhost:8080 でアクセスできます。

Node.js

npm start

Python

コマンドライン引数の使用:

functions-framework --target=YOUR_FUNCTION_NAME

環境変数の使用

FUNCTION_TARGET=YOUR_FUNCTION_NAME functions-framework

YOUR_FUNCTION_NAME は、関数のメソッド名に置き換えます。

Go

まず、Functions Framework for Go サイトの説明に沿って cmd/main.go ファイルを作成します。

cd cmd
go build
./cmd

環境変数の使用

cd cmd
go build
PORT=8080 ./cmd

Java

Maven

次のコマンドを使用して、pom.xml で指定された関数を実行します。

mvn function:run

コマンドライン引数で指定された関数を実行するには、次のコマンドを使用します。

mvn function:run -Drun.functionTarget=YOUR_FUNCTION_NAME

環境変数として指定された関数を実行するには、次のコマンドを使用します。

FUNCTION_TARGET=YOUR_FUNCTION_NAME mvn function:run

YOUR_FUNCTION_NAME は、関数のクラス名に置き換えます。

Gradle

次のコマンドを使用して、build.gradle で指定された関数を実行します。

./gradlew runFunction

コマンドライン引数で指定された関数を実行するには、次のコマンドを使用します。

./gradlew runFunction -Prun.functionTarget=YOUR_FUNCTION_NAME

環境変数として指定された関数を実行するには、次のコマンドを使用します。

FUNCTION_TARGET=YOUR_FUNCTION_NAME ./gradlew runFunction

YOUR_FUNCTION_NAME は、関数のクラス名に置き換えます。

C#

現在の .NET プロジェクトに関数が 1 つだけ存在する場合は、次のコマンドを使用して関数を実行しますこれは、テンプレートで作成されたプロジェクトのデフォルトの構造です。

dotnet run

.NET プロジェクトに複数の関数が含まれている場合は、次のコマンドを使用して特定の関数を実行します。YOUR_FUNCTION_CLASSNAME は、関数のクラス名(名前空間を含む)で置き換えます。

dotnet run YOUR_FUNCTION_CLASSNAME

複数の関数を同時に実行する場合は、複数の Functions Framework インスタンスを実行する必要があります。実行中のフレームワーク インスタンス間の競合を回避するため、各インスタンスで異なる PORT 値を使用する必要があります。次のコマンドは、PORT8080 で関数を実行する方法を示しています。

コマンドライン引数の使用:

dotnet run --target YOUR_FUNCTION_CLASSNAME --port 8080

環境変数の使用

FUNCTION_TARGET=YOUR_FUNCTION_CLASSNAME PORT=8080 dotnet run

Ruby

コマンドライン引数の使用:

bundle exec functions-framework-ruby --target YOUR_FUNCTION_NAME

環境変数の使用

FUNCTION_TARGET=YOUR_FUNCTION_NAME bundle exec functions-framework-ruby

YOUR_FUNCTION_NAME は、関数のメソッド名に置き換えます。

PHP

export FUNCTION_TARGET=YOUR_FUNCTION_NAME
php -S localhost:8080 vendor/bin/router.php

YOUR_FUNCTION_NAME は、関数の名前に置き換えます。

ローカルで実行中の関数を呼び出す

このセクションの演習では、Functions Framework を使用して、localhost でローカルで実行する関数を設定していることを前提としています。

ローカルで実行される関数をトリガーするには、ローカル処理プロセスを使用してルーティングされる HTTP リクエストを送信します。

HTTP 関数

開発環境から HTTP 関数をテストすると、通常は localhost:8080 でリクエストをリッスンします。このインターフェースには、関数が実行されているマシンまたは VM からのみアクセスできます。他のシステムから送信したリクエストからはアクセスできません。このため、関数が実行されているシステムから HTTP リクエストを発行する必要があります。次の例では、関数が 8080 以外のポートをリッスンしている場合は、この例の 8080 を関数のポート番号に置き換えます。

Cloud Shell を使用した HTTP 関数のテスト

Cloud Shell を使用して関数をビルドしてテストする場合は、Cloud Shell ターミナル ウィンドウで関数をローカルに起動し、次のようにブラウザまたは curl インスタンスから HTTP トリガー リクエストを発行します。

ブラウザ

Cloud Shell ツールバーの [ウェブでプレビュー] ボタン アイコンをクリックし、[ポート 8080] または [ポートを変更] を選択して別のポートを選択します。これにより、正しいシステムでブラウザ ウィンドウが開き、指定されたポートに対して GET リクエストが発行されます。

Curl

HTTP リクエストの形式を制御するか、形式設定されていないレスポンスを表示するには、curl を使用します。

  1. Cloud Shell メニューバーの [+] アイコンをクリックして、関数が実行されているシステムで新しいターミナル ウィンドウを開きます。
  2. そのウィンドウから curl コマンドを実行して関数をトリガーします。例:

    curl localhost:8080
    

デスクトップ サーバーでの HTTP 関数のテスト

ローカル デスクトップ システムで関数をビルドして実行する場合は、まず関数をローカルで起動してから、次のようにブラウザまたは curl インスタンスから HTTP トリガー リクエストを発行します。

ブラウザ

新しいブラウザ ウィンドウまたはタブを開き、ブラウザのアドレスバーに「http://localhost:8080」と入力します。これにより、デスクトップ サーバー上の localhost:8080 へのブラウザ ウィンドウが開き、関数がトリガーされます。

Curl

ローカル デスクトップで新しいターミナル ウィンドウを開き、そのウィンドウで curl コマンドを実行して関数をトリガーします。例:

 curl localhost:8080

これにより、指定された curl コマンドが実行されて関数がトリガーされ、形式設定されていないレスポンスが表示されます。

CloudEvent 関数

curl を使用して、サンプル イベントを CloudEvent 関数に送信できます。次の curl リクエストは、サンプルの Pub/Sub イベントと Cloud Storage イベントを localhost:8080 で実行中の CloudEvent 関数に送信する方法を示しています。

Pub/Sub

curl localhost:8080 \
  -X POST \
  -H "Content-Type: application/json" \
  -H "ce-id: 123451234512345" \
  -H "ce-specversion: 1.0" \
  -H "ce-time: 2020-01-02T12:34:56.789Z" \
  -H "ce-type: google.cloud.pubsub.topic.v1.messagePublished" \
  -H "ce-source: //pubsub.googleapis.com/projects/MY-PROJECT/topics/MY-TOPIC" \
  -d '{
        "message": {
          "data": "d29ybGQ=",
          "attributes": {
             "attr1":"attr1-value"
          }
        },
        "subscription": "projects/MY-PROJECT/subscriptions/MY-SUB"
      }'
    

Cloud Storage

curl localhost:8080 \
  -X POST \
  -H "Content-Type: application/json" \
  -H "ce-id: 123451234512345" \
  -H "ce-specversion: 1.0" \
  -H "ce-time: 2020-01-02T12:34:56.789Z" \
  -H "ce-type: google.cloud.storage.object.v1.finalized" \
  -H "ce-source: //storage.googleapis.com/projects/_/buckets/MY-BUCKET-NAME" \
  -H "ce-subject: objects/MY_FILE.txt" \
  -d '{
        "bucket": "MY_BUCKET",
        "contentType": "text/plain",
        "kind": "storage#object",
        "md5Hash": "...",
        "metageneration": "1",
        "name": "MY_FILE.txt",
        "size": "352",
        "storageClass": "MULTI_REGIONAL",
        "timeCreated": "2020-04-23T07:38:57.230Z",
        "timeStorageClassUpdated": "2020-04-23T07:38:57.230Z",
        "updated": "2020-04-23T07:38:57.230Z"
      }'