Automatikoと連携した関数フローとしてのワークフロー ¶
公開日:2021-12-17、改訂日:2024-01-17
Automatikoと連携した関数フローとしてのワークフロー¶
著者:Maciej Swiderski、OpenEnterpriseソフトウェアエンジニア
様々な組織が、クラウドを活用できるビジネスロジック構築手段としてサーバーレスに着目し始めています。一見するとそうではないかもしれませんが、独立したロジック部分を表す関数に厳密に依存するのは容易ではありません。全体像を見失い、日々の運用を完全に制御できなくなるリスクがあります。
Knativeは、サーバーレス、関数、イベントについて考える際の優れた基盤を提供します。特にKnative Eventingは、Cloud Eventsとの統合と、イベント配信の観点から様々な特性を提供する様々なブローカー実装のおかげで、その輝きを放っています。
同時に、様々な形式のワークフローは、全体像の理解を可能にするビジネスロジックを表現する良い方法として認識されてきました。ワークフローとKnative Eventingを組み合わせることが、この記事の主なトピックです。
関数フローとしてのワークフロー¶
ワークフローは、BPEL、そしてBPMNなどの標準が導入されたサービス指向アーキテクチャ(SOA)時代から存在しています。様々なベンダーが、ワークフロー概念を中心に構築されたプラットフォーム(プロセス管理スイートやビジネスプロセス管理(BPM)と呼ばれることが多い)を構築し始めました。
これらのプラットフォームは、多くの場合、大規模で中央集権化されたサーバーであり、標準化された方法ですべての他のシステムをオーケストレーションすることを目的としています。これは価値をもたらすには複雑すぎるということが判明し、多くの場合、従来のBPMと呼ばれ、既に時代遅れになっていますが、現在でも使用されています。
新しいアプローチでは、ワークフローは完全に分散化され、ワークフローの各アクティビティは個別のコンテナとして実行されます。
これは、ビジネスロジックを可能な限り完全にモデル化できる関数フローとしてのワークフローという概念につながります。ユーザーは、ビジネスユースケースの最初から最後までを定義し、Knativeなどのサーバーレスプラットフォームの機能を活用できます。つまり、ランタイム時にワークフローロジックは、以下の特性を持つ関数セットとして実行されます。
- 自己完結型 - ビジネスロジックの「1つの」側面に焦点を当てます。
- 独立型 - 定義されたロジックを実行し、同じインスタンスを処理しているかどうかに関係なく出力を返します。
- いつでも呼び出し可能 - ワークフローの先頭から常に開始する必要はなく、相関属性(Cloud Eventのtype属性)に基づいて着信イベントに反応するだけです。
- スケーラブル - 関数は需要に合わせて簡単にスケールアップおよびスケールダウンできます。
関数フローとしてのワークフロー
Automatikoプロジェクトは、Knative Eventing、Cloud Events、ワークフロー定義を活用して、サービスを完全なビジネスユースケースとして構築し、ワークフロー定義によって制御されるが、公開されたイベントによって呼び出される関数フローとして実行する方法を提供する、この概念の実装を提供します。
Automatikoは、以下のタイプのワークフローをサポートしています。
ワークフローを関数に分割する¶
関数は、ワークフローステートとデータを変更できるアクティビティを実行することに基づいて構築されます。このようなアクティビティは、関数としてカプセル化される特定のビジネスロジックの断片を表します。
アクティビティの実行は、
- 単一のアクティビティである可能性があります。
- ロジックを制御するために他のアクティビティを含めることができます。
- 継続を形成するために他の実行アクティビティと組み合わせることができます。
関数は、ワークフローまたはアクティビティ名に基づいて自動的に名前付けられるか、カスタム属性を使用してユーザーによって明示的に名前付けられます。
各関数は、専用のエントリポイントになり、
- ワークフローデータに基づいて構築された入力を持っています。
- 1つ以上の出力を生成できます。
- 関数に関連付けられたKnativeトリガーを持っています。
ワークフローを関数に分割する
Cloud Eventsとしての入力と出力¶
関数がワークフローから派生した後、常に1つのイベントを入力として持ち、1つ以上のイベントを出力として生成します。ワークフローに定義されたロジックと、特定のワークフローインスタンスの実際のデータコンテキストが、生成されるイベントの数を決定します。
イベントが入力か出力かに関係なく、
- ワークフローで定義されたデータオブジェクトに基づいて構築されます。
- 実行コンテキストに基づいて自動的にファイル化されます。
- type属性を関数へのリンクとして使用します。
- source属性を、相関のためにワークフローインスタンスの一意の識別子を含む、実行されている関数の識別子として使用します。
イベントとしての入力と出力
関数は常にKnative Eventingブローカーを通じてイベントを交換します。互いを直接呼び出すことはなく、完全にデカップリングされ、イベント駆動型であることが保証されます。これにより、各関数呼び出しをサービスの別のレプリカが処理できるため、スケーラビリティが向上します。
デプロイメント¶
ワークフロー定義の解析、関数とイベントへの分割、デプロイ可能な単位へのパッケージ化を必要とする重い作業は、ビルド時に実行されます。
Automatikoプロジェクトはこの概念を実装しています。これはJavaベースの実装であり、GraalVMを活用してネイティブ実行ファイルにコンパイルすることで、ランタイム時のメモリフットプリントが小さく、起動時間が非常に速くなります。
Automatikoを使用した関数フローとしてのワークフローは、単一のサービス、つまり単一のコンテナイメージにコンパイルされ、すべての関数が含まれます。各関数は、サービスの任意のレプリカでいつでも呼び出すことができます。
同時に、ビルド時にKnativeマニフェストファイルが生成され、クラスタへのデプロイが容易になります。Knativeマニフェストファイルには、
- Knativeサービス
- ブローカーの場所を挿入するためのシンクバインディング
- ワークフローから作成された各関数用のトリガー
これは、ビルド直後に完全に実行可能なサービスを作成するための出発点として機能します。クラスタ内のKnativeの特定の構成に合わせてさらに修正できます。
ユーザー登録の例¶
この例では、さまざまなチェックを実行し、Swagger PetStoreサービスにユーザーを登録する簡単なユーザー登録を示します。
この例の詳細については、Automatikoドキュメントを参照してください。
この例には、ワークフロー定義の作成に使用されるDSLに応じて、2つのフレーバーがあります。
BPMN
Serverless Workflow Spec
自分で例を試すには、この例プロジェクトのフレーバーのいずれかを複製します。
プロジェクトを複製したら、複製されたリポジトリで次のコマンドを実行してアプリケーションをビルドします。
mvn clean package -Pcontainer-native
このコマンドは、GraalVMでビルドされたネイティブ実行可能ファイルを使用するサービスを含むコンテナをビルドします。ビルドプロセスには時間がかかる場合があります。
ビルドされたコンテナをレジストリにプッシュ¶
コンテナイメージがビルドされた後、Knativeクラスタがプルできる外部レジストリにプッシュします。
Knativeクラスタへのデプロイ¶
-
たとえば、次のコマンドを使用してKnativeイベントングブローカーを作成します。
kubectl apply -f - << EOF apiVersion: eventing.knative.dev/v1 kind: broker metadata: name: default namespace: knative-eventing EOF
完全なデプロイメントファイルは、ビルドの一部として生成され、
target/functions/user-registration-{version}.yaml
にあります。デプロイするには、次のコマンドを実行します。kubectl apply -f target/functions/user-registration-{version}.yaml
これにより、完全なサービスとすべてのKnative Eventingトリガーがプロビジョニングされます。さらに、サービスをイベントソースにして関数実行からイベントを公開できるように、シンクバインディングも作成されます。
-
オプションで、次のコマンドを使用して、ブローカーを流れるすべてのイベントを表示する
cloudevents-player
をデプロイします。kubectl apply -n knative-eventing -f - << EOF apiVersion: serving.knative.dev/v1 kind: Service metadata: name: cloudevents-player spec: template: metadata: annotations: autoscaling.knative.dev/minScale: "1" spec: containers: - image: quay.io/ruben/cloudevents-player:latest env: - name: PLAYER_MODE value: KNATIVE - name: PLAYER_BROKER value: default --- apiVersion: eventing.knative.dev/v1 kind: Trigger metadata: name: cloudevents-player annotations: knative-eventing-injection: enabled spec: broker: default subscriber: ref: apiVersion: serving.knative.dev/v1 kind: Service name: cloudevents-player EOF
-
次のコマンドを使用して、デフォルトブローカーのURLを取得します。
kubectl get broker default
-
ブローカーにリクエストを送信してユーザー登録を開始します。
curl -v "http://broker-ingress.knative-eventing.svc.cluster.local/knative-eventing/default" \ -X POST \ -H "Ce-Id: 1234" \ -H "Ce-Specversion: 1.0" \ -H "Ce-Type: io.automatiko.examples.userRegistration" \ -H "Ce-Source: curl" \ -H "Content-Type: application/json" \ -d '{"user" : {"email" : "mike.strong@email.com", "firstName" : "mike", "lastName" : "strong"}}'
これは、Knativeブローカーを介して交換されるイベントの数と、ワークフローで定義された関数の呼び出しによって実行されます。Swagger PetStore REST APIも使用するため、ユーザー登録が成功した場合、Swagger PetStoreに新しいユーザーとして表示されます。
注記
Swagger PetStoreには信頼できるストレージがないため、そこに表示するには、いくつかの取得リクエストを発行する必要がある場合があります。
クリーンアップ¶
クリーンアップするには、次のコマンドを実行します。
kubectl delete -f target/functions/user-registration-1.0.0.yaml
Google Cloud Run用のコンテナイメージとしてサービスをビルドする¶
Google Cloud Runで同じサービスを使用するには、さらに2つの手順が必要です。
-
pom.xml
に依存関係を追加します。<dependency> <groupId>io.automatiko.extras</groupId> <artifactId>automatiko-gcp-pubsub-sink</artifactId> </dependency>
-
src/main/resources/application.properties
ファイルに2つのプロパティを追加します。quarkus.automatiko.target-deployment=gcp-pubsub quarkus.google.cloud.project-id=CHANGE_ME
注記
CHANGE_ME
をGoogle Cloudプロジェクトの実際のプロジェクトIDに変更することを忘れないでください。 -
次のMavenコマンドでアプリケーションをビルドします。
mvnw clean package -Pcontainer-native
このコマンドは、GraalVMでビルドされたネイティブ実行可能ファイルを使用するサービスを含むコンテナをビルドします。ビルドプロセスには時間がかかる場合があります。
ビルドされたコンテナをGoogle Cloud Container Registryにプッシュ¶
コンテナイメージがビルドされたら、Google Cloud RunがプルできるGoogle Cloud Container Registryにプッシュします。
PubSubを使用してGoogle Cloud Runにデプロイ¶
ビルドとプッシュが完了したら、完全なスクリプトがビルドの一部として生成され、target/scripts
にあります。デプロイするには、Google Cloud Consoleにログインするか(またはgcloud
がインストールされているターミナルを使用します)、gcloud
ツールを使用できる場所でdeploy-user-registration-gcp-cloudrun-{version}.txt
のすべてのコマンドを実行します。
スクリプトの内容は次のようになります。
gcloud pubsub topics create io.automatiko.examples.userRegistration.registrationfailed --project=CHANGE_ME
gcloud pubsub topics create io.automatiko.examples.userRegistration.notifyservererror --project=CHANGE_ME
gcloud pubsub topics create io.automatiko.examples.userRegistration.userregistered --project=CHANGE_ME
gcloud pubsub topics create io.automatiko.examples.userRegistration.notifyregistered --project=CHANGE_ME
gcloud pubsub topics create io.automatiko.examples.userRegistration.registeruser --project=CHANGE_ME
gcloud pubsub topics create io.automatiko.examples.userRegistration.invaliddata --project=CHANGE_ME
gcloud pubsub topics create io.automatiko.examples.userRegistration.generateusernameandpassword --project=CHANGE_ME
gcloud pubsub topics create io.automatiko.examples.userRegistration.alreadyregistered --project=CHANGE_ME
gcloud pubsub topics create io.automatiko.examples.userRegistration.getuser --project=CHANGE_ME
gcloud pubsub topics create io.automatiko.examples.userRegistration --project=CHANGE_ME
gcloud eventarc triggers create notifyservererror --event-filters="type=google.cloud.pubsub.topic.v1.messagePublished" --destination-run-service=user-registration-gcp-cloudrun --destination-run-path=/ --transport-topic=io.automatiko.examples.userRegistration.notifyservererror --location=us-central1
gcloud eventarc triggers create notifyregistered --event-filters="type=google.cloud.pubsub.topic.v1.messagePublished" --destination-run-service=user-registration-gcp-cloudrun --destination-run-path=/ --transport-topic=io.automatiko.examples.userRegistration.notifyregistered --location=us-central1
gcloud eventarc triggers create registeruser --event-filters="type=google.cloud.pubsub.topic.v1.messagePublished" --destination-run-service=user-registration-gcp-cloudrun --destination-run-path=/ --transport-topic=io.automatiko.examples.userRegistration.registeruser --location=us-central1
gcloud eventarc triggers create generateusernameandpassword --event-filters="type=google.cloud.pubsub.topic.v1.messagePublished" --destination-run-service=user-registration-gcp-cloudrun --destination-run-path=/ --transport-topic=io.automatiko.examples.userRegistration.generateusernameandpassword --location=us-central1
gcloud eventarc triggers create getuser --event-filters="type=google.cloud.pubsub.topic.v1.messagePublished" --destination-run-service=user-registration-gcp-cloudrun --destination-run-path=/ --transport-topic=io.automatiko.examples.userRegistration.getuser --location=us-central1
gcloud eventarc triggers create userregistration --event-filters="type=google.cloud.pubsub.topic.v1.messagePublished" --destination-run-service=user-registration-gcp-cloudrun --destination-run-path=/ --transport-topic=io.automatiko.examples.userRegistration --location=us-central1
gcloud run deploy user-registration-gcp-cloudrun --platform=managed --image=gcr.io/CHANGE_ME/user/user-registration-gcp-cloudrun:1.0.0 --region=us-central1
注記
CHANGE_ME
は、ビルド中にsrc/main/resources/application.properties
で構成されたGoogle CloudプロジェクトIDに置き換えられます。
これにより、次のコンポーネントがすべてプロビジョニングされます。
- PubSubトピック
- Eventarcトリガー
- サービスデプロイメント
Google Cloud Runでサービスを実行する¶
サービスがデプロイされた後、最初のメッセージを公開できます。たとえば、次のio.automatiko.examples.userRegistration
トピックを使用してGoogle Consoleを使用します。
{"user" : {"email" : "mike.strong@email.com", "firstName" : "mike", "lastName" : "strong"}}
これは、Google Cloud PubSubトピックを介して交換されるイベントの数と、ワークフローで定義された関数の呼び出しによって実行されます。
まとめ¶
関数フローとしてのワークフローは、個々の関数が完全なビジネスケースを構築するサーバーレスの使用における一般的なシナリオを実装します。これにより、ワークフローを使用して完全なビジネスロジックを設計し、ワークフロー定義によって定義された実際のロジックに基づいて、関数フローに構成される関数に分割できます。ただし、各関数はいつでも呼び出すことができるため、ワークフローは、任意の場所で開始し、定義された関数のフローに従って続行できるブループリントとして機能します。
関数フローとしてのワークフローは、Knative Eventingをコミュニケーションのバックボーンとして活用して、以下を実現します。
- スケーラビリティ(各関数はKnativeブローカーを使用して呼び出されます)。
- すべてのデータ交換はCloud Eventsを使用して行われます。
- ワークフロー定義インスタンスのどのポイントから開始するかという点での柔軟性。
- 全体的なパフォーマンスに影響を与える長時間実行されるアクションを回避するために、「自分自身を聞く」原則を使用します。
同時に、単一のサービスと自動的に定義されたトリガーに依存してKnativeブローカーと統合するため、デプロイメントが簡単です。
リンク/参照¶
関数フローとしてのワークフローは、Knativeコミュニティミートアップで発表されました。詳細に関心のある方は、ご覧ください。