The English version of quarkus.io is the official project site. Translated sites are community supported on a best-effort basis.

Google Cloud Functions (サーバーレス)

quarkus-google-cloud-functions エクステンションを使用すると、Quarkusを使用してGoogle Cloud Functionsを構築することができます。関数では、CDIやSpringからのインジェクションアノテーションや、必要に応じて他のQuarkusの機能を使用できます。

この技術は、previewと考えられています。

preview では、下位互換性やエコシステムでの存在は保証されていません。具体的な改善には設定や API の変更が必要になるかもしれませんが、 stable になるための計画は現在進行中です。フィードバックは メーリングリストGitHub の課題管理 で受け付けています。

とりうるステータスの完全なリストについては、 FAQの項目 を参照してください。

前提条件

このガイドを完成させるには、以下が必要です:

ソリューション

このガイドでは、Quarkus で HttpFunctionBackgroundFunction 、および RawBackgroundFunction を実装する方法を示す複数の関数を作成した後、サンプル プロジェクトを生成する方法について説明します。ビルド後は、プロジェクトをGoogle Cloudにデプロイすることができます。

これらの手順を順にすべて実行しない場合、完成したサンプルを以下で確認できます。

Gitリポジトリをクローンするか git clone https://github.com/quarkusio/quarkus-quickstarts.gitアーカイブ をダウンロードが可能です

このガイドでのソリューションは google-cloud-functions-quickstart ディレクトリ にあります。

デプロイ用のMavenプロジェクトを作成する

quarkus-google-cloud-functions のエクステンションを持つアプリケーションを作成します。以下のMavenコマンドを使って作成します。

コマンドラインインタフェース
quarkus create app org.acme:google-cloud-functions \
    --extension='google-cloud-functions' \
    --no-code
cd google-cloud-functions

Gradleプロジェクトを作成するには、 --gradle または --gradle-kotlin-dsl オプションを追加します。

Quarkus CLIのインストール方法や使用方法については、<a href="cli-tooling.html">Quarkus CLIガイド</a> を参照してください。

Maven
mvn io.quarkus.platform:quarkus-maven-plugin:2.14.2.Final:create \
    -DprojectGroupId=org.acme \
    -DprojectArtifactId=google-cloud-functions \
    -Dextensions='google-cloud-functions' \
    -DnoCode
cd google-cloud-functions

Gradleプロジェクトを作成するには、 -DbuildTool=gradle または -DbuildTool=gradle-kotlin-dsl オプションを追加します。

Googleクラウドにログインする

アプリケーションのデプロイにはGoogle Cloudへのログインが必要となるため、以下のコマンドでログインします。

gcloud auth login

Cloud Functions の関数を作成する

このプロジェクトの例では、 HttpFunctionBackgroundFunction (ストレージイベント)、 RawBackgroundFunction (PubSubイベント)、 CloudEventsFunction (Cloud Events 仕様を使用したストレージイベント)の4つの関数を作成します。

Quarkusは、Cloud Functionsの第1世代と第2世代をサポートしています。第2世代Cloud Functionsの概要については、Google Cloud Functionsドキュメントの こちらのページを参照してください。第2世代を使用するには、 --gen2 パラメータを追加する必要があります。

Cloud Functions の関数を選択する

quarkus-google-cloud-functions エクステンションは、プロジェクト内からGoogle Cloud HttpFunctionBackgroundFunction 、または RawBackgroundFunctionCloudEventsFunction インターフェイスを直接実装しているクラスをプロジェクト内でスキャンします。プロジェクト内でこれらのインターフェイスを実装しているクラスが見つからなければ、ビルド時にエラーがスローされます。 複数の関数クラスが見つかった場合は、ビルド時の例外がスローされます。

しかし、同じコードを利用するCloud Functionの関数クラスが複数あるような場合に、個別maven モジュールを作成することは手間となります。このQuarkusエクステンションを使うと、複数のCloud Function関数を一つのプロジェクトにバンドルし、設定や環境変数を使ってデプロイしたい関数を選択することができます。

Cloud Functions の関数に名前を設定するには、以下の設定プロパティーを使用します。

quarkus.google-cloud-functions.function=test

quarkus.google-cloud-functions.function プロパティーは、デプロイする関数をQuarkusに伝えます。これは環境変数でオーバーライドすることもできます。

Cloud Functions の関数となるクラスの CDI 名は、 quarkus.google-cloud-functions.function プロパティー内で指定された値と一致している必要があります。これは @Named アノテーションを使用して行う必要があります。

@Named("test")
public class TestHttpFunction implements HttpFunction {
}

HttpFunction

import java.io.Writer;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.inject.Named;
import com.google.cloud.functions.HttpFunction;
import com.google.cloud.functions.HttpRequest;
import com.google.cloud.functions.HttpResponse;
import io.quarkus.gcp.function.test.service.GreetingService;

@Named("httpFunction") (1)
@ApplicationScoped (2)
public class HttpFunctionTest implements HttpFunction { (3)
    @Inject GreetingService greetingService; (4)

    @Override
    public void service(HttpRequest httpRequest, HttpResponse httpResponse) throws Exception { (5)
        Writer writer = httpResponse.getWriter();
        writer.write(greetingService.hello());
    }
}
1 @Named アノテーションでは、 quarkus.google-cloud-functions.function プロパティーで使用する CDI Beanに名前を付けることができますが、これはオプションです。
2 関数はCDI Beanでなければなりません。
3 これは通常の Google Cloud Function の実装なので、 com.google.cloud.functions.HttpFunction を実装する必要があります。
4 インジェクションはCloud Function関数クラスの中で動作します。
5 これは標準的な Google Cloud Function の実装であり、ここでは何も派手なことはしていません。

BackgroundFunction

この BackgroundFunction はストレージイベントによってトリガーされる以外にも、Google Cloud でサポートされているトリガーイベントを使用できます。

import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.inject.Named;
import com.google.cloud.functions.BackgroundFunction;
import com.google.cloud.functions.Context;
import io.quarkus.gcp.function.test.service.GreetingService;


@Named("storageTest") (1)
@ApplicationScoped (2)
public class BackgroundFunctionStorageTest implements BackgroundFunction<BackgroundFunctionStorageTest.StorageEvent> { (3)
    @Inject GreetingService greetingService;  (4)

    @Override
    public void accept(StorageEvent event, Context context) throws Exception { (5)
        System.out.println("Receive event: " + event);
        System.out.println("Be polite, say " + greetingService.hello());
    }

    //
    public static class StorageEvent { (6)
        public String name;
    }
}
1 @Named アノテーションでは、 quarkus.google-cloud-functions.function プロパティーで使用する CDI Beanに名前を付けることができますが、これはオプションです。
2 関数はCDI Beanでなければなりません。
3 これは通常のGoogle Cloud Functionの実装なので、com.google.cloud.functions.BackgroundFunction を実装する必要があります。
4 インジェクションはCloud Function関数クラスの中で動作します。
5 これは標準的な Google Cloud Function の実装であり、ここでは何も派手なことはしていません。
6 これはトリガーのイベントデータがデシリアライズされるクラスです。

RawBackgroundFunction

この RawBackgroundFunction は PubSub イベントでトリガーされる以外にも、Google Cloud でサポートされているトリガーイベントを使用することができます。

import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.inject.Named;
import com.google.cloud.functions.Context;
import com.google.cloud.functions.RawBackgroundFunction;
import io.quarkus.gcp.function.test.service.GreetingService;

@Named("rawPubSubTest") (1)
@ApplicationScoped (2)
public class RawBackgroundFunctionPubSubTest implements RawBackgroundFunction { (3)
    @Inject GreetingService greetingService; (4)

    @Override
    public void accept(String event, Context context) throws Exception { (5)
        System.out.println("PubSub event: " + event);
        System.out.println("Be polite, say " + greetingService.hello());
    }
}
1 @Named アノテーションでは、 quarkus.google-cloud-functions.function プロパティーで使用する CDI Beanに名前を付けることができますが、これはオプションです。
2 関数はCDI Beanでなければなりません。
3 これは通常のGoogle Cloud Functionの実装なので、com.google.cloud.functions.RawBackgroundFunction を実装する必要があります。
4 インジェクションはCloud Function関数クラスの中で動作します。
5 これは標準的な Google Cloud Function の実装であり、ここでは何も派手なことはしていません。

CloudEventsFunction

CloudEventsFunction は、第2世代のCloud Functionsのみの機能です。

この CloudEventsFunction は Cloud Events Storage イベントによってトリガーされる以外にも、Google Cloud でサポートされている任意のCloud Eventsを使用できます。

import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.inject.Named;

import com.google.cloud.functions.CloudEventsFunction;

import io.cloudevents.CloudEvent;
import io.quarkus.gcp.function.test.service.GreetingService;

@Named("cloudEventTest") (1)
@ApplicationScoped (2)
public class CloudEventStorageTest implements CloudEventsFunction { (3)
    @Inject
    GreetingService greetingService;  (4)

    @Override
    public void accept(CloudEvent cloudEvent) throws Exception { (5)
        System.out.println("Receive event Id: " + cloudEvent.getId());
        System.out.println("Receive event Subject: " + cloudEvent.getSubject());
        System.out.println("Receive event Type: " + cloudEvent.getType());
        System.out.println("Receive event Data: " + new String(cloudEvent.getData().toBytes())); (6)
        System.out.println("Be polite, say " + greetingService.hello());
    }
}
1 @Named アノテーションでは、 quarkus.google-cloud-functions.function プロパティーで使用する CDI Beanに名前を付けることができますが、これはオプションです。
2 関数はCDI Beanでなければなりません。
3 これは通常のGoogle Cloud Functionの実装なので、com.google.cloud.functions.CloudEventsFunction を実装する必要があります。
4 インジェクションはCloud Function関数クラスの中で動作します。
5 これは標準的な Google Cloud Function の実装であり、io.cloudevents.CloudEvent を受け取る以外は何も派手なことはしていません。
6 Cloud Eventsの中のストレージイベントです。

アプリケーションのビルドとGoogle Cloudへのデプロイ

アプリケーションを構築するには、標準コマンドを使ってパッケージ化します。

コマンドラインインタフェース
quarkus build
Maven
./mvnw install
Gradle
./gradlew build

前のコマンドの結果、 target/deployment リポジトリ内に単一の JAR ファイルが生成されます。このJARファイルにはプロジェクト内のクラスと、依存関係のクラスが含まれています

これで gcloud beta functions deploy コマンドを使って Google Cloud に関数をデプロイすることができるようになります。

このコマンドを初めて起動したときには、以下のようなエラーメッセージが表示されることがあります。

ERROR: (gcloud.functions.deploy) OperationError: code=7, message=Build Failed: Cloud Build has not been used in project <project_name> before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/cloudbuild.googleapis.com/overview?project=<my-project> then retry.

これは、Cloud Buildがまだ有効化されていないことを意味します。このエラーを解決するには、エラーに表示されているURLを開き指示に従った後、数分待ってからコマンドを再試行してください。

HttpFunction

これは HttpFunction を Google Cloud にデプロイするためのコマンドの例です。

gcloud functions deploy quarkus-example-http \
  --entry-point=io.quarkus.gcp.functions.QuarkusHttpFunction \
  --runtime=java11 --trigger-http --allow-unauthenticated --source=target/deployment

エントリーポイントは常に io.quarkus.gcp.functions.QuarkusHttpFunction に設定する必要があります。このクラスはQuarkusとCloud Functionsを統合するクラスです。

また、gcloudのコマンドラインで --runtime=java17 を使用すると、新しいJava 17ランタイムを使用することができます。

このコマンドは、作成したCloud Functions 関数をトリガーするための httpsTrigger.url を出力します。

BackgroundFunction

関数をデプロイする前に、バケットを作成する必要があります。

gsutil mb gs://quarkus-hello

これは BackgroundFunction を Google Cloud にデプロイするためのコマンドの例です。この関数は Storage イベントによってトリガーされるため、 --trigger-event google.storage.object.finalize--trigger-resource パラメーターに先の手順で作成したバケットの名前を指定する必要があります。

gcloud functions deploy quarkus-example-storage \
    --entry-point=io.quarkus.gcp.functions.QuarkusBackgroundFunction \
    --trigger-resource quarkus-hello --trigger-event google.storage.object.finalize \
    --runtime=java11 --source=target/deployment

エントリーポイントは常に io.quarkus.gcp.functions.QuarkusBackgroundFunction に設定する必要があります。このクラスはQuarkusとCloud Functionsを統合するクラスです。

また、gcloudのコマンドラインで --runtime=java17 を使用すると、新しいJava 17ランタイムを使用することができます。

イベントをトリガーするには、GCS quarkus-hello バケットにファイルを送るか、gcloudコマンドを使ってシミュレートします。

gcloud functions call quarkus-example-storage  --data '{"name":"test.txt"}'
--data には GCS イベントを指定します。これは、バケットに追加されたファイル名を含む JSON形式のフォーマットです。

RawBackgroundFunction

これは RawBackgroundFunction を Google Cloud にデプロイするコマンドの例です。この関数は PubSub イベントによってトリガーされるので、 --trigger-event google.pubsub.topic.publish--trigger-resource パラメーターに、先の手順で作成したトピックの名前を指定する必要があります。

gcloud functions deploy quarkus-example-pubsub \
  --entry-point=io.quarkus.gcp.functions.QuarkusBackgroundFunction \
  --runtime=java11 --trigger-resource hello_topic --trigger-event google.pubsub.topic.publish --source=target/deployment

エントリーポイントは常に io.quarkus.gcp.functions.QuarkusBackgroundFunction に設定する必要があります。このクラスはQuarkusとCloud Functionsを統合するクラスです。

また、gcloudのコマンドラインで --runtime=java17 を使用すると、新しいJava 17ランタイムを使用することができます。

イベントをトリガーするには、 hello_topic トピックにファイルを送信するか、gcloudコマンドを使用してシミュレートします。

gcloud functions call quarkus-example-pubsub --data '{"data":{"greeting":"world"}}'

CloudEventsFunction

CloudEventsFunction は、第2世代のCloud Functionsのみの機能です。

これは CloudEventsFunction を Google Cloud にデプロイするコマンドの例です。この関数は Storage イベントをトリガーとしているので、--trigger-bucket パラメータにあらかじめ作成した Bucket 名を指定しておく必要があります。

gcloud functions deploy quarkus-example-cloud-event --gen2 \
  --entry-point=io.quarkus.gcp.functions.QuarkusCloudEventsFunction \
  --runtime=java11 --trigger-bucket=example-cloud-event --source=target/deployment

エントリーポイントは常に io.quarkus.gcp.functions.QuarkusCloudEventsFunction に設定する必要があります。これは、Cloud Functions と Quarkus を統合するクラスです。

また、gcloudのコマンドラインで --runtime=java17 を使用すると、新しいJava 17ランタイムを使用することができます。

イベントをトリガーするには、GCS example-cloud-event バケットにファイルを送ります。

ローカルでのテスト

関数をローカルでテストする最も簡単な方法は、Cloud Function invoker JAR を使用することです。

以下のコマンドでMaven経由でダウンロードできます。

mvn dependency:copy \
  -Dartifact='com.google.cloud.functions.invoker:java-function-invoker:1.1.1' \
  -DoutputDirectory=.

インボーカーを使用する前に、まずは関数をビルドする必要があります。

コマンドラインインタフェース
quarkus build
Maven
./mvnw install
Gradle
./gradlew build

HttpFunction

HttpFunction をテストするために、以下のコマンドを使用しローカルで関数を起動することができます。

java -jar java-function-invoker-1.1.1.jar \
  --classpath target/google-cloud-functions-1.0.0-SNAPSHOT-runner.jar \
  --target io.quarkus.gcp.functions.QuarkusHttpFunction
--classpath パラメーターには、関数クラスとQuarkus関連のすべてのクラスを含む、先の手順でパッケージ化されたJARを指定する必要があります。

エンドポイントは http://localhost:8080 で利用できます。

BackgroundFunction

BackgroundFunction関数の場合は、 io.quarkus.gcp.functions.BackgroundFunction のターゲットクラスでinvokerを起動します。

java -jar java-function-invoker-1.1.1.jar \
  --classpath target/google-cloud-functions-1.0.0-SNAPSHOT-runner.jar \
  --target io.quarkus.gcp.functions.QuarkusBackgroundFunction
--classpath パラメーターには、関数クラスとQuarkus関連のすべてのクラスを含む、先の手順でパッケージ化されたJARを指定する必要があります。

起動後、HTTP 呼び出しにイベントを含むペイロードを付与することでバックグラウンド関数を呼び出すことができます。

curl localhost:8080 -d '{"data":{"name":"hello.txt"}}'

このコマンドにより、イベント {"name":"hello.txt"} でBackgroundFunctionを呼び出します。これは、`hello.txt`をCloud Storageに保存した際のイベントをテストするのと同じです。

RawBackgroundFunction

BackgroundFunction関数の場合は、 io.quarkus.gcp.functions.BackgroundFunction のターゲットクラスでinvokerを起動します。

java -jar java-function-invoker-1.1.1.jar \
  --classpath target/google-cloud-functions-1.0.0-SNAPSHOT-runner.jar \
  --target io.quarkus.gcp.functions.QuarkusBackgroundFunction
--classpath パラメーターには、関数クラスとQuarkus関連のすべてのクラスを含む、先の手順でパッケージ化されたJARを指定する必要があります。

起動後、HTTP 呼び出しにイベントを含むペイロードを付与することでバックグラウンド関数を呼び出すことができます。

curl localhost:8080 -d '{"data":{"greeting":"world"}}'

このコマンドは、PubSubのBackgroundFunctionを次のPubSubMessageで呼び出します {"greeting":"world"}

CloudEventsFunction

CloudEventsFunction は、第2世代のCloud Functionのみの機能です。

CloudEventsFunctionの場合は、 io.quarkus.gcp.functions.QuarkusCloudEventsFunction のターゲットクラスでinvokerを起動します。

java -jar java-function-invoker-1.1.1.jar \
  --classpath target/google-cloud-functions-1.0.0-SNAPSHOT-runner.jar \
  --target io.quarkus.gcp.functions.QuarkusCloudEventsFunction
--classpath パラメーターには、関数クラスとQuarkus関連のすべてのクラスを含む、先の手順でパッケージ化されたJARを指定する必要があります。

イベントを含むペイロードを持つHTTPコールを介して、CloudEventsFunctionを呼び出すことができます。

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"
      }'

”MY_FILE.txt ファイルに対するイベントで、CloudEventsFunctionを呼び出します。