タグ別アーカイブ: Azure

Azure Key Vault

このエントリは2019/09/11現在の情報に基づくもので、将来の機能変更に伴い記載内容との乖離が発生する可能性があります。

Azure Key Vaultとは

Azure Key Vault は、次の問題の解決に役立ちます。
シークレットの管理 – Azure Key Vault を使用すると、トークン、パスワード、証明書、API キー、その他のシークレットを安全に格納し、それらへのアクセスを厳密に制御できます。
キー管理 – Azure Key Vault は、キー管理ソリューションとしても使用できます。 Azure Key Vault により、データの暗号化に使用される暗号化キーの作成と制御が簡単になります。
証明書の管理 – Azure Key Vault は、Azure および内部の接続されているリソースで使用するためのパブリックおよびプライベートの Secure Sockets Layer/Transport Layer Security (SSL/TLS) 証明書を簡単にプロビジョニング、管理、デプロイすることができるサービスでもあります。
ハードウェア セキュリティ モジュールに基づくシークレットの格納 – シークレットとキーは、ソフトウェアまたは FIPS 140-2 レベル 2 検証済み HSM で保護できます。

Azure Key Vault とは
https://docs.microsoft.com/ja-jp/azure/key-vault/key-vault-overview

上記引用文の通り、機密情報(パスワード、証明書、暗号鍵など)を格納し、アクセス管理できるもの。キーはハードウェア セキュリティ モジュール(Hardware Security Module、以下HSM)を使って保護することもできる。なお、HSMを使った保護をしたい場合には、SKUとしてPremiumを選択する必要がある(Standardではソフトウェアによる保護しか選択できない)点に注意。

サービスレベルと価格に関する情報は以下。

Key Vault の価格
https://azure.microsoft.com/ja-jp/pricing/details/key-vault/
Key Vault pricing
https://azure.microsoft.com/en-us/pricing/details/key-vault/

Keyの作成

Azure Key Vaultで作成できるKeyはEC(楕円暗号)もしくはRSA。AESは対応していないため、AESのKeyは別途作成のうえ、シークレットとしてAzure Key Vaultで管理するしかない。

シークレットや証明書の保管

シークレットや証明書は、キーとは異なりHSMに保存するオプションはない。その代わり、シークレット等のオブジェクトはAzure Key Vaultに格納するタイミングでHSMに紐付く保存用の暗号鍵を使って暗号化される。取り出し時には復号化される。この考え方は以下のData Encryption-at-Restに記載の通りである。

Azure Data Encryption-at-Rest
https://docs.microsoft.com/ja-jp/azure/security/fundamentals/encryption-atrest
https://docs.microsoft.com/en-us/azure/security/fundamentals/encryption-atrest

Oracle WebLogic Server on Microsoft Azure IaaS

このエントリは以下のエントリを基にしています。
This entry is based on the following one written by Jacob Thomas (Software Development Manager, Oracle).
https://blogs.oracle.com/weblogicserver/oracle-weblogic-server-on-microsoft-azure-iaas

2019年6月初旬にOracleとMicrosoftは両社のクラウドの相互接続のパートナーシップを発表しました。

Microsoft and Oracle to interconnect Microsoft Azure and Oracle Cloud
https://news.microsoft.com/2019/06/05/microsoft-and-oracle-to-interconnect-microsoft-azure-and-oracle-cloud/

このたび、OracleとMicrosoft間のパートナーシップのもう一つの側面として、Oracle WebLogic Server on Microsoft Azure IaaSというもう一つの重要なピースを発表いたします。

WebLogic Kubernetes OperatorやCoherence Kubernetes Operatorへのこれまでの作業に加えて、OracleのWebLogicチームは、WebLogic ServerをMicrosoft AzureのIaaSリソースにデプロイするという最もよくあるニーズをカバーするため、いくつかの相互運用するAzure ARM (Azure Resource Manager) テンプレートとそれに対応するAzure Marketplaceでのアイテムを作成するという作業に現在取り組んでいます。

Portable WebLogic Domains Using Kubernetes Operator Configuration Overrides
https://blogs.oracle.com/weblogicserver/portable-weblogic-domains-using-kubernetes-operator-configuration-overrides
Coherence Operator 1.0 Released! Operate Coherence Clusters with Kubernetes.
https://blogs.oracle.com/oraclecoherence/coherence-operator-1-0-released

Marketplaceで選択できる以下のものは、全てOracle Linux 7.6で稼働するOracle WebLogic Server 12.2.1.3をベースにしています。

  • 事前構成済みのWebLogic管理サーバのみが動作する1個のVMを作成
  • 管理サーバが1個のVMで動作し、クラスタメンバは別のVMで動作する、N個のノードのWebLogicクラスタを作成
    プロビジョニングが完了すると、管理サーバと全ての管理対象サーバがデフォルトで起動している。管理サーバとノードマネージャはsystemdサービスとし起動されており、NodeManagerのCrashRecoveryEnabledプロパティにtrueが設定されているため、VMの再起動後、サーバは自動的に再起動される。Azure CLIを使ってクラスタにノードを追加できる。
  • 前述の通りN個のノードで構成されるWebLogicクラスタを作成すると、クラスタ用にAzure LoadBalancerが自動的に構成される。
  • 1個のVM上の管理サーバと、動的クラスタ内の他のノード上の管理対象サーバを使用して、N個のノードで構成されるWebLogic動的クラスタを作成する。WLS管理者は、管理コンソールまたはWLSTを使ってスケールアップし、利用可能なVMにて追加の管理対象サーバを起動できる。前述の通りサービスは自動開始するように構成されており、Azure CLIでさらにノードを追加できる。

この商品のリリース日などに関する今後のアップデートはこのブログで情報提供していきますので、是非チェックしてください。現時点では、2019年10末までにAzure Marketingpaceでご利用頂けるようにしたいと考えています。Azure Marketplaceの”Contact Me”使って、この機能が利用できるようになったことを通知するように仕込むこともできます。

Oracle WebLogic Server 12.2.1.3 — Azure Marketplace
https://azuremarketplace.microsoft.com/en-us/marketplace/apps/oracle.oraclelinux-wls-cluster

OracleとMicrosoftのパートナーシップに関する詳細情報は以下のURLをご覧ください。

Accelerate your cloud adoption with Microsoft and Oracle®
https://azure.microsoft.com/en-us/solutions/oracle/

Azure Service Busでカスタムプロパティをやりとりする (1)

このエントリは2019/09/12現在の情報に基づくものです。今後の機能追加や変更に伴い、記述内容との乖離が発生する可能性があります。

Azure Service Busはメッセージブローカーで、様々なメッセージをやりとりできるが、メッセージとともにカスタムプロパティを送受信することもできる。

今回はTopicを使って動作確認した。Queueでも基本的には同じである。例によって利用言語はJavaである。

SDKを使う場合

事前準備

pom.xmlに以下の依存関係を追加しておく。

<dependency>
  <groupId>com.microsoft.azure</groupId>
  <artifactId>azure-servicebus</artifactId>
  <version>3.0.0</version>
</dependency>

送信側

通常通りメッセージを作成するが、カスタムプロパティはMapに詰め込んでおき、Message#setProperties()でカスタムプロパティをメッセージに設定する。

Message message = new Message();
message.setMessageBody(MessageBody.fromValueData(messageString));
Map<String, Object> properties = new HashMap<>();
properties.put("account-id", "common");
properties.put("data-partition-id", "common");
properties.put("correlation-id", "12345-67890-abcde-fghij-klmno");
message.setContentType("application/json");
message.setCorrelationId("12345-67890-abcde-fghij");
message.setProperties(properties); // <---- Here!
topicClient.sendAsync(message).thenRunAsync(() -> topicClient.closeAsync());

受信側

messageインスタンスを取得後、Message#getProperties()を呼び出せば、カスタムプロパティを取得できる。

IMessageHandler messageHandler = new IMessageHandler() {
    @Override
    public CompletableFuture<Void> onMessageAsync(IMessage message) {
        if(message.getContentType().contentEquals("application/json")) {
            Map<String, Object> properties = message.getProperties(); // <---- !! Here !!
            String messageString = (String) message.getMessageBody().getValueData();
        }
        return subscriptionClient.completeAsync(message.getLockToken());
    }
    @Override
    public void notifyException(Throwable throwable, ExceptionPhase exceptionPhase) {
        System.out.println(exceptionPhase + "---" + throwable.getMessage());
    }
};

Functionsの場合

事前準備

pom.xmlに以下の依存関係を追加しておく。なお、Functionsのバージョンは2を使う。

<dependency>
  <groupId>com.microsoft.azure</groupId>
  <artifactId>azure-servicebus</artifactId>
  <version>3.0.0</version>
</dependency>

送信側(Output)

OutputBindingにMessageを指定すれば、 あとはSDKの場合と同様のお作法でカスタムプロパティを付加して送信できる。

@FunctionName("sboutput")
public HttpResponseMessage send2ServiceBus(
    @HttpTrigger(
            name = "req",
            methods = {HttpMethod.POST},
            authLevel = AuthorizationLevel.ANONYMOUS
    ) HttpRequestMessage<Optional<String>> request,
    @ServiceBusTopicOutput(
            name = "message",
            topicName = "%TOPIC_NAME%",
            subscriptionName = "%SUBSCRIPTION_NAME%",
            connection = "AzureServiceBusConnectionString"
    ) OutputBinding<Message> message,
    final ExecutionContext context) {
    Map<String, Object> properties = new HashMap<>();
    properties.put("account-id", "common");
    properties.put("data-partition-id", "common");
    properties.put("correlation-id", "12345-67890-abcde-fghij-klmno");
    String body = request.getBody().get();
    MessageBody.fromValueData(body);
    Message sendMessage = new Message();
    sendMessage.setMessageBody(MessageBody.fromValueData(body));
    sendMessage.setContentType("application/json");
    sendMessage.setCorrelationId("12345-67890-abcde-fghij");
    sendMessage.setProperties(properties);
    message.setValue(sendMessage);
    return request.createResponseBuilder(HttpStatus.ACCEPTED)
        .header("Content-Type","application/json")
        .body(body)
        .build();
}

受信側(Trigger)

FunctionsはデフォルトでReceiveMode.PEEKLOCKを使っており、成功すると自動的にSubscriptionClient#complete()、失敗するとSubscriptionClient#abandon()が呼ばれることに注意。Functions v2では、com.microsoft.azure.servicebus.Message をBinding変数に指定しておけば、SDKの場合と同じお作法で取得できる。もちろん通常のPOJOも可能。以下はContextTypeとしてapplication/jsonが指定されているメッセージのみ受け取る例。

@FunctionName("sbtrigger")
public void triggerFromServiceBus(
        @ServiceBusTopicTrigger(
                name = "message",
                topicName = "%TOPIC_NAME%",
                subscriptionName = "%SUBSCRIPTION_NAME%",
                connection = "AzureServiceBusConnectionString"
        ) Message message,
        final ExecutionContext context) {
    if (message.getContentType().contentEquals("application/json")) {
        context.getLogger().info(message.getMessageBody().getValueData().toString());
        Map<String, Object> properties = message.getProperties();
        context.getLogger().info(properties.toString());
    }
}

SDKとFunctionsを混在させる(例えば送信側がFunctions、受信側がSDK)というのは通常の方法ではできない。詳細は別のエントリに記載する予定。

Azure Databricksの集計結果をCosmos DB(MongoDB API)に書き込む

このエントリは2019/09/02現在の情報に基づくもので、将来の機能追加や廃止に伴い、記載内容との乖離が発生する可能性があります。

Cosmos DBには種々のAPIがあり、例えばMongoDBやCassandraなどを使っているアプリケーションをCosmos DBに置き換える場合、接続文字列を置き換えるだけで移行できる、ということになっているが、果たしてそれがApache Sparkの場合にでも言えるのかを確認した。

結論から言うと、確かにMongoDB Connector for Apache Sparkを設定し直すことで対応できた。以下に記録を残す。

Databricksで実施する処理

Azure SQL DatabaseのAdventureworksデータベース内にあるSalesLT.CustomerAddress、SalesLT.Address、SalesLT.CustomerをJoinし、_idとして、CustomerIDとAddressIDを組み合わせた文字列を生成する。単なるJoinなので、本来ならDatabase内で完結すべきなのは承知の上で、テスト目的で実施した。

準備するもの

  • Cosmos DB
    • MongoDB APIを選択
  • Azure Databricks
    • 今回は5.5 LTS (Apache Spark 2.4.3 / Scala 2.11) を選択
  • MongoDB Connector for Apache Spark
    • Maven Repositoryからorg.mongodb.spark:mongo-spark-connector_2.11の2.4.1を選択し、ライブラリとして登録しておく
    • Scalaのバージョンと整合しておく必要がある
  • Azure Databricks Notebook
    • 今回は動作確認のため、Notebookを使用。
    • 今回、言語はScalaを利用
  • サンプルデータソース
    • ファイルでも何でもよいが、今回はAzure SQL Databaseのサンプルデータベース(Adventureworks)を使用

Databricksにデータを取り込み、DataSetを生成

JDBCドライバを使ってAzure DatabricksでSQL Databaseからデータを取り込む。DataSetを作成する場合はCase Classが必要なので、こちらも作成しておく。

val driverClass = "com.microsoft.sqlserver.jdbc.SQLServerDriver"
connectionProperties.setProperty("Driver", driverClass)
// Case Classes
case class Address(AddressID: Int, AddressLine1: String, AddressLine2: String, City: String, StateProvince: String, CountryRegion: String, PostalCode: String, rowguid: String, ModifiedDate: String)
case class Customer(CustomerID: Int, NameStyle: Boolean, Title: String, FirstName: String, MiddleName: String, LastName: String, Suffix: String, CompanyName: String, SalesPerson: String, EmailAddress: String, Phone: String, PasswordHash: String, PasswordSalt: String, rowguid: String, ModifiedDate: String)
case class CustomerAddress(CustomerID: Int, AddressID: Int, AddressType: String, rowguid: String, ModifiedDate: String)
// Create DataSets and load data to them
val customerAddress_DS = spark.read.jdbc(jdbcUrl, "SalesLT.CustomerAddress", connectionProperties).as[CustomerAddress]
val address_DS = spark.read.jdbc(jdbcUrl, "SalesLT.Address", connectionProperties).as[Address]
val customer_DS = spark.read.jdbc(jdbcUrl, "SalesLT.Customer", connectionProperties).as[Customer]

DataSet間でJoinしDataFrameを生成

各DataSetをJoinする。このとき、列名を===でつなぐJoinだと同じ名称の列ができてしまうので、列名だけを指定するようにしている。

val tempDS = customerAddress_DS.join(customer_DS, "CustomerID")
                          .join(address_DS, "AddressID")
                          .withColumn("_id", concat($"CustomerID", lit("-"), $"AddressID"))
                          .select("_id", "AddressID", "AddressLine1", "CustomerID", "CompanyName", "AddressType")

この結果、以下の列を持つDataFrameができあがる。

  • _id:string
  • AddressID:integer
  • AddressLine1:string
  • CustomerID:integer
  • CompanyName:string
  • AddressType:string

SQLで記述すると、以下のような処理を実行している。

select B.CustomerID || '-' || A.AddressID as _id,
          A.AddressID as AddressID,
          A.AddressLine1 as AddressLine1,
          B.CustomerID as CustomerID,
          B.CompanyName as CompanyName,
          C.AddressType as AddressType
  from Address A, Customer B, CustomerAddress C
where A.AddressID = C.AddressID and C.CustomerID = B.CustomerID

Cosmos DB (MongoDB API) に格納

Connectorを使うためのお作法に則って、構成を作成し、saveメソッドを呼び出す。

val writeConfigMap = Map(
    "database" -> "{database name}", 
    "collection" -> "{collection name}", 
    "uri" -> "mongodb://...", 
    "writeConcern.w" -> "majority")
val writeConfig: WriteConfig = WriteConfig(writeConfigMap, Some(WriteConfig(sc)))
MongoSpark.save(tempDF.write.mode(SaveMode.Overwrite), writeConfig)

注意すべきこと

Cosmos DB側のスループット設定が不足していると、最後の書き込みでエラーが発生することがある(HTTP 429)。これは書き込むデータ量に依存するので、単純な推奨値はない。そのため、適切なスループットの割り当てや、整合性の変更などを考慮する必要がある。もしどうしてもスループットが足りない場合は、何らかのスロットリング機構が必要である。

Cosmos DB SDK v3で冗長化されたインスタンスのリージョンやURLを取得する

このエントリは2019/08/26現在の情報を基にしており、将来の機能追加や廃止に伴い、記載内容との乖離が発生する可能性があります。また、この内容はSDK v3をベースにしています。


以前、以下のエントリを記載したが、SDK v2ベースだったため、v3を基にした内容を別途記載しておく。

Cosmos DBの地理冗長化に関するあれこれ (v2)
https://logico-jp.io/2019/05/09/cosmos-db-distributed-across-multi-regions-v2/

各Regionに冗長化されたCosmos DBのURIを取得する

v2で利用しているAPIは以下の場所に移動した。Package名称からもわかるように、将来隠蔽される可能性があるので注意が必要。

Package com.azure.data.cosmos.internal
https://azure.github.io/azure-sdk-for-java/track1reports/com/azure/data/cosmos/internal/package-summary.html

基本的にはv2と同じメソッドを呼び出すことができるが、少々異なる箇所もあるので以下に記載しておく。

地理冗長化先のリージョンとURL

AsyncCosmosClientクラスのインスタンスを作成する。getDatabaseAccount()はFlux<DatabaseAccount>を返すので、今回はListで受け取るようにしている。もちろんStreamで受け取ることもできる。

AsyncDocumentClient tempClient = new AsyncDocumentClient.Builder()
        .withServiceEndpoint(ENDPOINT)
        .withMasterKeyOrResourceToken(KEY)
        .build();

List<DatabaseAccount> databaseAccountList = tempClient.getDatabaseAccount().buffer().blockLast();

あとは、取得したDatabaseAccountに設定されているリージョンとURLを調べればよい。

databaseAccountList.forEach(databaseAccount -> {
    Iterator<DatabaseAccountLocation> it = databaseAccount.getReadableLocations().iterator();
    while (it.hasNext()) {
        DatabaseAccountLocation loc = it.next();
        System.out.println(loc.getName() + "---" + loc.getEndpoint());
    }
});

Cosmos DB Java SDK v3でマルチマスタを構成する

これは2019/08/21現在の情報を基にしたものです。将来の機能追加や廃止に伴って記載内容との乖離が発生する可能性があります。


Cosmos DBのSDKを使ってマルチマスタを構成する方法は以下のドキュメントに記載がある。

Azure Cosmos DB を使用するアプリケーションでマルチマスターを構成する
https://docs.microsoft.com/ja-jp/azure/cosmos-db/how-to-multi-master
Configure multi-master in your applications that use Azure Cosmos DB
https://docs.microsoft.com/en-us/azure/cosmos-db/how-to-multi-master

ただ、2019/08/21時点において、Java SDKを使った例は、v2のAsync Java SDK(CompletableFutureを使った実装)についてのみ紹介されており、SDK v3のReactorを使った実装を基にした記述にはなっていない。そのため、V3の場合の例を以下にまとめておく(当然、将来ドキュメントの記載が変更されるはず)。

v2の場合

v2の場合、以下のようにConnectionPolicyのプロパティを設定することで、マルチマスタ構成を設定していた。

ConnectionPolicy policy = new ConnectionPolicy();
policy.setUsingMultipleWriteLocations(true);
policy.setPreferredLocations(Collections.singletonList(region));
AsyncDocumentClient client =
    new AsyncDocumentClient.Builder()
        .withMasterKeyOrResourceToken(this.accountKey)
        .withServiceEndpoint(this.accountEndpoint)
        .withConsistencyLevel(ConsistencyLevel.Eventual)
        .withConnectionPolicy(policy).build();

v3の場合

v3でも同様のプロパティは存在する。設定方法はほぼ同じだが、メソッドが異なるので注意。

// String[] REGION = {"Japan East", "Japan West"};
ConnectionPolicy policy = new ConnectionPolicy()
        .usingMultipleWriteLocations(true)
        .preferredLocations(Arrays.asList(REGION));
CosmosClient client = CosmosClient.builder()
        .endpoint(ENDPOINT)
        .key(KEY)
        .consistencyLevel(ConsistencyLevel.EVENTUAL)
        .connectionPolicy(policy)
        .build();

ConnectionPolicy#usingMultipleWriteLocations(true) でマルチマスタの利用を宣言し、ConnectionPolicy#preferredLocations() を呼び出して、アクセス先のリージョン(Cosmos DBがレプリケートされている、書き込み可能なリージョン)を指定する。preferredLocationsへ渡す引数はListであることに注意(配列ではない)。ここで、1個だけリージョンを指定すると、当該リージョンが障害でアクセスできない場合は例外が発生するが、アプリケーションのデプロイ先リージョンを指定することで、プライマリリージョンに書き込みが集中しないように構成できる。

また、preferredLocationsに複数個のリージョンを指定すると、明示的にフォールバック時のアクセス順序を指定できる。ConnectionPolicyクラスのjavadocは以下。

com.azure.data.cosmos.ConnectionPolicy
https://azure.github.io/azure-cosmosdb-java/3.0.0/com/azure/data/cosmos/ConnectionPolicy.html

Azure SignalR ServiceとEvent Gridを組み合わせる

このエントリは2019/08/14現在の情報に基づくもので、将来の機能追加・廃止によって、記載内容との乖離が発生する可能性があります。

以前、以下のエントリを記載した。

Azure SignalR Serviceを試す
https://logico-jp.io/2019/07/12/try-azure-signalr-service/

最近、Azure SignalR ServiceがEvent Gridと接続ができるようになった。これを使うとクライアントからのイベントを捕捉してEvent Gridへ送出し、イベントをサブスクライブしている別のサービスが対応できる。

Azure SignalR Service now supports Event Grid!
https://devblogs.microsoft.com/aspnet/azure-signalr-service-now-supports-event-grid/

上記エントリは例によってC#やJavaScriptのみなので、前記のエントリに追記する形で、Javaの例を記載しておく。

準備

Azure SignalR Service

インスタンスを作成する。これは以前のエントリに記載した通り。Settings > Feature Flag でServerlessを設定しておく(これはインスタンス作成時に設定することも可能)。

Functions

Event Grid TriggerのFunction Appを作成する。Javaの場合、ArcheTypeを使ってMavenでコードを生成する。

mvn archetype:generate \
-DarchetypeGroupId=com.microsoft.azure \
-DarchetypeArtifactId=azure-functions-archetype \
-DappName={resourceGroup} \
-DappRegion={region} \
-DresourceGroup={resourceGroup} \
-DgroupId=com.{functionAppName}.group \
-DartifactId={functionAppName}-functions \
-Dpackage=com.{functionAppName} \
-DinteractiveMode=false

Azure SignalR ServiceをFunctionsで操作する場合、pom.xmlに依存関係を追加する必要がある。

<dependency>
    <groupId>com.microsoft.signalr</groupId>
    <artifactId>signalr</artifactId>
    <version>1.0.0</version>
</dependency>
<dependency>
    <groupId>com.microsoft.azure.functions</groupId>
    <artifactId>azure-functions-java-library-signalr</artifactId>
    <version>1.0.0</version>
</dependency>

同様に、Event Gridを操作する場合には、以下の依存関係を追加する必要がある。

<dependency>
    <groupId>com.microsoft.azure</groupId>
    <artifactId>azure-eventgrid</artifactId>
    <version>1.2.0</version>
</dependency>

Azure SignalR Serviceの接続文字列は、構成 > アプリケーション設定 で設定する。この例では名前をAzureSignalRConnectionString としている。設定後、Javaのコードを生成したディレクトリ配下(pom.xmlのあるディレクトリ)で、以下のコマンドを実行してローカル環境でもテストできるよう、local.settings.jsonを作成しておく。必要であれば、local.setteings.jsonにCORSの設定をいれる。以下はCORS設定を入れた例。

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "...",
    "FUNCTIONS_WORKER_RUNTIME": "java",
    "APPINSIGHTS_INSTRUMENTATIONKEY": "...",
    "AzureSignalRConnectionString": "Endpoint=https://...Version=1.0;",
    "FUNCTIONS_EXTENSION_VERSION": "~2",
    "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING": "DefaultEndpointsProtocol=https;AccountName=...",
    "WEBSITE_CONTENTSHARE": "...",
    "WEBSITE_NODE_DEFAULT_VERSION": "10.14.1"
  },
  "ConnectionStrings": {
    "AzureCosmosDBConnection": {
      "ConnectionString": "..."
    }
  },
  "Host": {
    "CORS": "*"
  }
}

続いて、以前のAzure SingnalR Serviceを試したときの例にEvent Grid用のFunctionを追加する。Event Gridへのバインドを設定したFunctionは以下の通り。

    @FunctionName("eventGridMonitor")
    public void logEvent(
            @EventGridTrigger(name = "event") String event,
            final ExecutionContext context) {
        // log
        context.getLogger().info("Event content: " + event);
    }

作成したらデプロイしておく。

Event Grid

大枠は以下のドキュメントに記載の通りなので、記載内容に従って作業を行うが、今回はFunctionsを使うため、少々異なる点は意識しておく必要がある。

イベントを Azure SignalR Service から Event Grid に送信する方法
https://docs.microsoft.com/ja-jp/azure/azure-signalr/signalr-howto-event-grid-integration
How to send events from Azure SignalR Service to Event Grid
https://docs.microsoft.com/en-us/azure/azure-signalr/signalr-howto-event-grid-integration

初めてEvent Gridを使う場合、以下のドキュメントに記載の通り、Event Grid リソース プロバイダーを有効化しておく。

Event Grid リソース プロバイダーを有効にする
https://docs.microsoft.com/ja-jp/azure/azure-signalr/signalr-howto-event-grid-integration#enable-event-grid-resource-provider
Enable Event Grid Resource Provider
https://docs.microsoft.com/en-us/azure/azure-signalr/signalr-howto-event-grid-integration#enable-event-grid-resource-provider

イベントサブスクリプション作成は、Azure SignalR Service > イベント で実施する(元のエントリではFunction Appの設定から実施しているが、Javaで作成するFunctionの場合、Function Appの設定はRead onlyになるため設定を反映できない)。今回、Event GridをサブスクライブするFunctionとしてeventGridMonitorというFunctionを作成、デプロイ済みなので、このタイミングでEvent Gridとの紐付けを行う。赤で囲んだwebhookをクリックする。

Azure SignalR Serviceへの接続、切断イベントのフィルタリングや、リソース指定は自動設定されているが、エンドポイントの詳細は設定する必要がある。ここでは webhook を指定し、サブスクライバーエンドポイントはEvent Gridバインドを設定したFunctionの 統合 > Event GridのサブスクリプションURL (下図) をコピーし、Event Gridのエンドポイントに転記する(下図)。

設定が完了したら、 [作成] をクリック。

以上で終了。

イベントの確認

以前のエントリで作成したクライアントを使って接続・切断を実施する。イベントを拾えているかどうかを確認するため、ログストリーミングを使う。Function App > プラットフォーム機能 > ログストリーミング をクリックして、[アプリケーション ログ] を表示しておく。

クライアントからの接続・切断をしてみると、以下のようなログが現れた。Azure SignalR Serviceへの接続イベントを拾っていることを確認できる。