Azure Functions を Java の App Service でサービスエンドポイント経由の Azure Storage Queue とバインドしてみました。
検証環境を準備
bash
# 環境変数をセットします
prefix=mnrfncjq
region=japaneast
# リソースグループを作成します
az group create \
--name ${prefix}-rg \
--location $region
# VNET を作成します
az network vnet create \
--name ${prefix}-vnet \
--resource-group ${prefix}-rg \
--address-prefixes 10.0.0.0/24
# NSG を作成します
az network nsg create \
--resource-group ${prefix}-rg \
--name ${prefix}-nsg
# サブネットを作成します
az network vnet subnet create \
--resource-group ${prefix}-rg \
--vnet-name ${prefix}-vnet \
--name fun-subnet \
--address-prefix 10.0.0.0/26 \
--network-security-group ${prefix}-nsg \
--service-endpoints Microsoft.Storage
# Azure Storage を作成します
az storage account create \
--name ${prefix}stor \
--resource-group ${prefix}-rg \
--sku Standard_LRS
# キューを作成します
az storage queue create \
--name messages \
--account-name ${prefix}stor
# Azure Storage をネットワーク制限します
az storage account update \
--name ${prefix}stor \
--resource-group ${prefix}-rg \
--default-action deny
# 自分の IP アドレスからのアクセスを許可します
az storage account network-rule add \
--account-name ${prefix}stor \
--resource-group ${prefix}-rg \
--ip-address $(curl -s inet-ip.info)
# サブネットからのアクセスを許可します
az storage account network-rule add \
--account-name ${prefix}stor \
--resource-group ${prefix}-rg \
--vnet-name ${prefix}-vnet \
--subnet fun-subnet
# Application Insights を作成します
az monitor app-insights component create \
--app ${prefix}-ai \
--location $region \
--resource-group ${prefix}-rg
# App Service Plan を作成します
az appservice plan create \
--name ${prefix}-funplan \
--resource-group ${prefix}-rg \
--sku B1
# Azure Functions を作成します
az functionapp create \
--name ${prefix}-fun \
--resource-group ${prefix}-rg \
--plan ${prefix}-funplan \
--runtime java \
--functions-version 4 \
--storage-account ${prefix}stor \
--app-insights ${prefix}-ai \
--https-only \
--os-type Windows \
--assign-identity
# FTP を無効にします
az webapp config set \
--name ${prefix}-fun \
--resource-group ${prefix}-rg \
--ftps-state Disabled
# 自分の IP アドレスからのアクセスを許可します
az webapp config access-restriction add \
--name ${prefix}-fun \
--resource-group ${prefix}-rg \
--priority 100 \
--rule-name MyIP \
--action Allow \
--ip-address $(curl -s inet-ip.info)
# VNET 統合して Functions から Azure Storage にアクセスできるようにします
az webapp vnet-integration add \
--name ${prefix}-fun \
--resource-group ${prefix}-rg \
--vnet ${prefix}-vnet \
--subnet fun-subnet
ローカルで Azure Functions を作成
bash
# Maven で Java 11 の Functions 雛形を作成します
mvn archetype:generate -DarchetypeGroupId=com.microsoft.azure -DarchetypeArtifactId=azure-functions-archetype -DjavaVersion=11
# 入力サンプル
# groupId: com.example
# artifactId: java-func-example
# version 1.0-SNAPSHOT
# package com.example
# 作成されたディレクトリに移動します
cd java-func-example
# Maven で Functions アプリをビルドします
mvn clean package
# Functions アプリをローカルで動かします
mvn azure-functions:run
Functions アプリに QueueOutput バインドを追加
src/main/java/com/example/Functions.java
package com.example;
// import com.microsoft.azure.functions.ExecutionContext;
// import com.microsoft.azure.functions.HttpMethod;
// import com.microsoft.azure.functions.HttpRequestMessage;
// import com.microsoft.azure.functions.HttpResponseMessage;
// import com.microsoft.azure.functions.HttpStatus;
// import com.microsoft.azure.functions.annotation.AuthorizationLevel;
// import com.microsoft.azure.functions.annotation.FunctionName;
// import com.microsoft.azure.functions.annotation.HttpTrigger;
import com.microsoft.azure.functions.annotation.*;
import com.microsoft.azure.functions.*;
import java.util.Optional;
/**
* Azure Functions with HTTP Trigger.
*/
public class Function {
/**
* This function listens at endpoint "/api/HttpExample". Two ways to invoke it using "curl" command in bash:
* 1. curl -d "HTTP Body" {your host}/api/HttpExample
* 2. curl "{your host}/api/HttpExample?name=HTTP%20Query"
*/
@FunctionName("HttpExample")
public HttpResponseMessage run(
@HttpTrigger(
name = "req",
methods = {HttpMethod.GET, HttpMethod.POST},
authLevel = AuthorizationLevel.ANONYMOUS)
HttpRequestMessage<Optional<String>> request,
@QueueOutput(
name = "msg",
queueName = "messages",
connection = "AzureWebJobsStorage")
OutputBinding<String> msg,
final ExecutionContext context) {
context.getLogger().info("Java HTTP trigger processed a request.");
// Parse query parameter
final String query = request.getQueryParameters().get("name");
final String name = request.getBody().orElse(query);
if (name == null) {
return request.createResponseBuilder(HttpStatus.BAD_REQUEST).body("Please pass a name on the query string or in the request body").build();
} else {
msg.setValue(name);
return request.createResponseBuilder(HttpStatus.OK).body("Hello, " + name).build();
}
}
}
Functions アプリのデプロイ設定
pom.xmlの該当箇所
<configuration>
<!-- function app name -->
<appName>mnrfncjq-fun</appName>
<!-- function app resource group -->
<resourceGroup>mnrfncjq-rg</resourceGroup>
<!-- function app service plan name -->
<appServicePlanName>mnrfncjq-funplan</appServicePlanName>
<!-- function app region-->
<!-- refers https://github.com/microsoft/azure-maven-plugins/wiki/Azure-Functions:-Configuration-Details#supported-regions for all valid values -->
<region>japaneast</region>
<!-- function pricingTier, default to be consumption if not specified -->
<!-- refers https://github.com/microsoft/azure-maven-plugins/wiki/Azure-Functions:-Configuration-Details#supported-pricing-tiers for all valid values -->
<pricingTier>B1</pricingTier>
<!-- Whether to disable application insights, default is false -->
<!-- refers https://github.com/microsoft/azure-maven-plugins/wiki/Azure-Functions:-Configuration-Details for all valid configurations for application insights-->
<!-- <disableAppInsights></disableAppInsights> -->
<runtime>
<!-- runtime os, could be windows, linux or docker-->
<os>windows</os>
<javaVersion>11</javaVersion>
</runtime>
<appSettings>
<property>
<name>FUNCTIONS_EXTENSION_VERSION</name>
<value>~4</value>
</property>
</appSettings>
</configuration>
Azure Functions にデプロイして動作確認
bash
# テスト用のコードを無効化します
mv src/test/java/com/example/FunctionTest.java src/test/java/com/example/FunctionTest.java.bak
mv src/test/java/com/example/HttpResponseMessageMock.java src/test/java/com/example/HttpResponseMessageMock.java.bak
# Functions アプリをビルドします
mvn package
# Functions アプリをデプロイします
mvn azure-functions:deploy
# Functions 経由でキューにメッセージを登録します
curl https://mnrfncjq-fun.azurewebsites.net/api/httpexample?name=HelloMessage
# キューにメッセージ登録されていれば成功
# Application Insights の trace ログにもメッセージが表示されていれば成功
参考