アプリ設定を WebApps の構成のアプリケーション設定とは別に管理できる App Configuration を試してみました!
最近は ARM Template 書いてみるのがブームなので、以下のように ARM Template 作って下準備しました。
{"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": {"appName": {"type": "string" }}, "variables": {"storageAccountName": "[concat(parameters('appName'), 'storage')]", "storageAccountid": "[concat(resourceGroup().id,'/providers/','Microsoft.Storage/storageAccounts/', variables('storageAccountName'))]", "appInsightsName": "[concat(parameters('appName'), '-insights')]", "functionAppName": "[concat(parameters('appName'), '-func')]", "hostingPlanName": "[concat(parameters('appName'), '-plan')]", "appConfigurationName": "[concat(parameters('appName'), 'config')]", "appConfigurationId": "[concat(resourceGroup().id,'/providers/','Microsoft.AppConfiguration/configurationStores/', variables('appConfigurationName'))]" }, "resources": [{"type": "Microsoft.Storage/storageAccounts", "name": "[variables('storageAccountName')]", "apiVersion": "2019-04-01", "location": "[resourceGroup().location]", "kind": "StorageV2", "sku": {"name": "Standard_LRS" }}, {"apiVersion": "2015-05-01", "name": "[variables('appInsightsName')]", "type": "Microsoft.Insights/components", "kind": "web", "location": "[resourceGroup().location]", "tags": {"[concat('hidden-link:', resourceGroup().id, '/providers/Microsoft.Web/sites/', variables('functionAppName'))]": "Resource" }, "properties": {"Application_Type": "web", "ApplicationId": "[variables('appInsightsName')]" }}, {"type": "Microsoft.Web/serverfarms", "apiVersion": "2016-09-01", "name": "[variables('hostingPlanName')]", "location": "[resourceGroup().location]", "properties": {"name": "[variables('hostingPlanName')]", "computeMode": "Dynamic" }, "sku": {"name": "Y1", "tier": "Dynamic", "size": "Y1", "family": "Y", "capacity": 0}}, {"apiVersion": "2016-08-01", "type": "Microsoft.Web/sites", "name": "[variables('functionAppName')]", "location": "[resourceGroup().location]", "kind": "functionapp", "dependsOn": ["[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]" ], "properties": {"siteConfig": {"appSettings": [{"name": "AzureWebJobsStorage", "value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountName'), ';AccountKey=', listKeys(variables('storageAccountid'),'2015-05-01-preview').key1)]" }, {"name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING", "value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountName'), ';AccountKey=', listKeys(variables('storageAccountid'),'2015-05-01-preview').key1)]" }, {"name": "WEBSITE_CONTENTSHARE", "value": "[toLower(variables('functionAppName'))]" }, {"name": "FUNCTIONS_WORKER_RUNTIME", "value": "dotnet" }, {"name": "FUNCTIONS_EXTENSION_VERSION", "value": "~3" }, {"name": "WEBSITE_RUN_FROM_PACKAGE", "value": 1}, {"name": "APPINSIGHTS_INSTRUMENTATIONKEY", "value": "[reference(resourceId('microsoft.insights/components/', variables('appInsightsName')), '2015-05-01').InstrumentationKey]" }, {"name": "AppConfigurationConnectionString", "value": "[ListKeys(variables('appConfigurationId'), '2019-10-01').value[2].connectionString]" }]}}}, {"name": "[variables('appConfigurationName')]", "type": "Microsoft.AppConfiguration/configurationStores", "apiVersion": "2019-10-01", "location": "[resourceGroup().location]", "properties": {}, "sku": {"name": "standard" }}], "outputs": {}, "functions": []}
App Configuration の接続文字列は ListKeys 関数でプライマリー読み書き、セカンダリー読み書き、プライマリー読み込み専用、セカンダリー読み込み専用の順番で入った値が返ってくるので 3 番目の要素の connectionString で取れます。
App Configuratoin の ARM Template は以下のドキュメントを参考にしました。
接続文字列をとってくる関数は、以下のドキュメントを見て ListKeys なんだと確認しました。
とりあえず App Configuration を使わないケース
Azure Functions のプロジェクトを作って以下の NuGet パッケージを入れます。DIしたいので。
- Microsoft.Azure.Functions.Extensions
local.settings.json を以下のようにして…
{"IsEncrypted": false, "Values": {"AzureWebJobsStorage": "UseDevelopmentStorage=true", "FUNCTIONS_WORKER_RUNTIME": "dotnet", "Sample:Message": "Hello from local.settings.json" }}
そして、Startup.cs で SampleObject というクラスに Sample:Message が設定されるようにします。
using Microsoft.Azure.Functions.Extensions.DependencyInjection; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; [assembly: FunctionsStartup(typeof(AppConfigFunc.Startup))] namespace AppConfigFunc { publicclass Startup : FunctionsStartup { private IConfiguration Configuration { get; } public Startup() { var config = new ConfigurationBuilder() .AddEnvironmentVariables() .AddJsonFile("local.settings.json", true); // 後で App Configuration から取り込む予定 Configuration = config.Build(); } publicoverridevoid Configure(IFunctionsHostBuilder builder) { builder.Services.Configure<SampleObject>(Configuration.GetSection("Sample")); } } publicclass SampleObject { publicstring Message { get; set; } } }
適当に関数で使ってみましょう。SampleObject を DI して Message を返すだけの関数を作ります。
using System; using System.IO; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.Azure.WebJobs; using Microsoft.Azure.WebJobs.Extensions.Http; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; using Newtonsoft.Json; using Microsoft.Extensions.Options; namespace AppConfigFunc { publicclass SayHello { privatereadonly SampleObject _sampleObject; public SayHello(IOptions<SampleObject> sampleObject) { _sampleObject = sampleObject.Value; } [FunctionName("SayHello")] public IActionResult Run( [HttpTrigger(AuthorizationLevel.Function, "get", Route = null)] HttpRequest req, ILogger log) { returnnew OkObjectResult(_sampleObject); } } }
実行して SayHello 関数を呼び出すと…
思った通りですね。
App Configuration 対応
では、App Configuration 対応してみます。以下の NuGet パッケージを追加します。
- Microsoft.Extensions.Configuration.AzureAppConfiguration
Startup.cs を以下のようにして本番のときだけ App Configuration から値を取るようにしてみました。 今回はローカルでは local.settings.json を使う想定で
using Microsoft.Azure.Functions.Extensions.DependencyInjection; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; [assembly: FunctionsStartup(typeof(AppConfigFunc.Startup))] namespace AppConfigFunc { publicclass Startup : FunctionsStartup { public IConfiguration Configuration { get; } public Startup() { var config = new ConfigurationBuilder() .AddEnvironmentVariables() .AddJsonFile("local.settings.json", true); // App Configuration から取り込む var builtConfig = config.Build(); if (builtConfig["AZURE_FUNCTIONS_ENVIRONMENT"] != "Development") { config.AddAzureAppConfiguration(builtConfig["AppConfigurationConnectionString"]); } Configuration = config.Build(); } publicoverridevoid Configure(IFunctionsHostBuilder builder) { builder.Services.Configure<SampleObject>(Configuration.GetSection("Sample")); } } publicclass SampleObject { publicstring Message { get; set; } } }
コードは安定のしばやんの blog を参考にしました。
そして、App Configuration に以下のような値を設定します。
ARM Template で作った Function Apps にデプロイして実行すると、以下のような値になりました!やったね!
App Configuration の設定を動的に変更したい
その時用のメモとしてドキュメントへのリンクをぺたり。