以前Azure Blob Storage上に静的サイトとしてClient side Blazorをデプロイする記事を書きました。
Azure CLIに慣れる目的で、今回はServer side BlazorをAzure上にデプロイしたいと思います。
使うサービスはAzureのWeb Apps, Key Vault, SignalR Serviceです。
目次
Azureの設定手順
プロビジョニングはWindows環境のAzure CLI(ver2.0.78)を使用します。
AzureへLogin
ターミナルを起動しaz login
を実行しAzureにログインします。
ResourceGroupの設定
Resource Groupを作成します。
ロケーションは東日本のjapaneast
を指定します。
< >
で括られた値は任意の値に変更してください。
az group create --name <GroupName> --location japaneast
備考:Locationの調べ方
下記コマンドで調べることができます。
az account list-locations --output table
App Serviceの設定
Web Apps
を使用するためにApp Service
を作成します。
こちらの記事に記載した通りAzure CLIでWindowsのApp Serviceを作成すると.NET CoreのRuntimeが選べません。仕方がないので今回はLinuxを選択します。
※Azure Portalで手動で作る場合はWindowsでも.NET Coreが選べるのに…。
SKUはとりあえずFREEで。
az appservice plan create --resource-group <GroupName> --name <AppServicePlanName> --location japaneast --sku FREE --is-linux
Web Appsの設定
Web Apps
を作成します。
Deploy用のリポジトリなどを用意する場合は適宜--deployment-source-url
などのオプションを付与しましょう。
今回はVisual Studio Codeの拡張機能Azure App Service
を使用してDeployするのでオプションは指定しません。
az webapp create --resource-group <GroupName> --name <WebAppsName> --plan <AppServicePlanName> --runtime "DOTNETCORE|LTS"
Powershellで上記コマンドを実行すると|
の部分がエラーとなります。
一時的にcmdに切り替えて実行してください。
Managed Service Identityの設定
WebAppsにADのManaged Idをアサインします。
az webapp identity assign --name <WebAppsName> --resource-group <GroupName>
登録後に下記コマンドでprincipalId
を調べます。
az webapp identity show --name <WebAppsName> --resource-group <GroupName>
以下のようなJsonが吐かれるので、principalId
をコピーしておきます。
※以下は例です。
{ "principalId": "abcdefgh-0000-9999-1234-hogefuga", "tenantId": "piyopiyo-1234-5678-9012-foobarhogefuga", "type": "SystemAssigned", "userAssignedIdentities": null }
SignalR Serviceの設定
SignalR Serviceを利用せずとも、Web Appsの設定でWeb sockets
を有効化すればBlazorは動きます。
az webapp config set --web-sockets-enabled true --resource-group <GroupName> --name <WebAppsName>
しかし接続ユーザが増えてくるとパフォーマンスが悪くなる"らしい"ので、Azure SignalR Serviceを使用して左記問題を回避します。
下記コマンドでAzure SignalR Serviceのサービスを作成します。
SKUは無料のFree_F1
にします。
az signalr create --resource-group <GroupName> --name <SignalRName> --sku Free_F1
SignalRのConnectionStringを調べる
Server side BlazorからSinalRに接続するために必要なConnectionString
を調べます。
az signalr key list --resource-group <GroupName> --name <SignalRName>
以下のようなJsonが吐かれるので、primaryConnectionString
をコピーしておきます。
※以下は例です。
{ "primaryConnectionString": "Endpoint=https://xxx.service.signalr.net;AccessKey=yyyzzz1=;Version=1.0;", "primaryKey": "yyyzzz1=", "secondaryConnectionString": "Endpoint=https://yyy.service.signalr.net;AccessKey=yyyzzz2=;Version=1.0;", "secondaryKey": "yyyzzz2=" }
Azure Key Vaultの設定
Key Vaultを設定します。
<SecretValue>
は先程調べたSignalRのConnectionStringであるprimaryConnectionString
を指定します。
ポリシーの割り当て先は先程ADに登録したWeb AppsのprincipalId
を--object-id
で指定します。
az provider register -n Microsoft.KeyVault az keyvault create --resource-group <GroupName> --name <VaultName> --location japaneast az keyvault secret set --vault-name <VaultName> --name <SecretName> --value <SecretValue> az keyvault set-policy --name <VaultName> --object-id <PrincipalId> --secret-permissions get list
以上でAzure側の設定は完了です。
Server side Blazorの作成
Server side Blazorを作成します。
SignalRやKeyVault関連のPackageを追加します。
dotnet new blazorserver -o SampleBlazor cd SampleBlazor dotnet add package Microsoft.Azure.SignalR dotnet add package Microsoft.Azure.KeyVault dotnet add package Microsoft.Azure.Services.AppAuthentication dotnet add package Microsoft.Extensions.Configuration.AzureKeyVault
appsettings.jsonの編集
Azure KeyVaultのEndPointと、SignalRのEndPointを格納したSecret名を記載します。
※Key VaultのEndPointはaz keyvault show --resource-group <GroupName> -n <VaultName>
で表示されるvaultUri
がそれに該当します。
{ + "KeyVault": { + "EndPoint": "Azure KeyVaultのEndPoint URL", + "SignalRConnectionStringSecret": "Azure KeyVaultに追加した<SecretName>" + }, "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" } }, "AllowedHosts": "*" }
ConfigurationBuilderにKeyVaultを追加
Program.cs
のCreateHostBuilder
でAzure KeyVaultのデータを取得し、builderに組込みます。
+ public class KeyVaultSetting + { + public string EndPoint { get; set; } + public string SignalRConnectionStringSecret { get; set; } + } public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) + .ConfigureAppConfiguration((ctx, builder) => + { + var config = builder.Build(); + var keyVaultSetting = new KeyVaultSetting(); + config.GetSection("KeyVault").Bind(keyVaultSetting); + if (!string.IsNullOrEmpty(keyVaultSetting.EndPoint)) + { + var azureServiceTokenProvider = + new AzureServiceTokenProvider(); + var keyVaultClient = new KeyVaultClient( + new KeyVaultClient.AuthenticationCallback( + azureServiceTokenProvider.KeyVaultTokenCallback)); + builder.AddAzureKeyVault(keyVaultSetting.EndPoint, + keyVaultClient, + new DefaultKeyVaultSecretManager()); + } + }) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); });
SignalRのServiceの設定
Startup.cs
を編集し、SignalRのサービスを追加します。
public void ConfigureServices(IServiceCollection services) { services.AddRazorPages(); services.AddServerSideBlazor(); services.AddSingleton<IConfiguration>(Configuration); services.AddSingleton<WeatherForecastService>(); + var keyVaultSetting = new KeyVaultSetting(); + Configuration.GetSection("KeyVault").Bind(keyVaultSetting); + var signalREndPoint = Configuration.GetSection(keyVaultSetting.SignalRConnectionStringSecret).Value; + services.AddSignalR().AddAzureSignalR(cfg => + { + cfg.ConnectionString = signalREndPoint; + }); }
余談:Azure Key Vaultを使用しない場合
とりあえずで動かしたいときはappsettings.json
にSignalR用の設定を記述しConfigureServices
にservices.AddSignalR().AddAzureSignalR();
と追記するだけで動きます。
{ + "Azure":{ + "SignalR":{ + "Enabled": true, + "ConnectionString":"Endpoint=https://xxx.service.signalr.net;AccessKey=hogefugapiyofoobar___yWtbjObiDBZwunDFH4MpNk=;Version=1.0;" + } + }, "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" } }, "AllowedHosts": "*" }
RuntimeIdentifierの設定
App Serviceで--is-linux
を指定したため、Web Appsの中身はLinuxです。
よって、.csproj
にRuntimeIdentifier
の定義を追加します。
<Project Sdk="Microsoft.NET.Sdk.Web"> <PropertyGroup> <TargetFramework>netcoreapp3.1</TargetFramework> + <RuntimeIdentifier>linux-x64</RuntimeIdentifier> </PropertyGroup> <ItemGroup> <PackageReference Include="Microsoft.Azure.Cosmos.Table" Version="1.0.6" /> <PackageReference Include="Microsoft.Azure.SignalR" Version="1.2.3" /> <PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="3.1.0" /> </ItemGroup> </Project>
以上です。
Web AppsへのDeploy
任意の方法でDeployします。
今回はVisual Studio Codeの拡張機能のAzure App Service
を使用したいと思います。
Azure App Service
F1を押下しAzure App Service: Deploy to Web App...
を選択します。
Deployするコードがあるフォルダを選択し、Deploy先のWeb Appsを選択します。
この時点で設定ファイルが作成され、以下のダイアログが表示されます。
ここでいったんキャンセルを押下します。
Publishするフォルダは先程作成されたsetting.json
ファイルに記載されています。
デフォルトだとsrc/bin/Release/netcoreapp3.1/publish
になっているのでパスを変更します。
{ "appService.preDeployTask": "publish-release", - "appService.deploySubpath": "src/bin/Release/netcoreapp3.1/publish" + "appService.deploySubpath": "src/bin/Release/netcoreapp3.1/linux-x64/publish" }
準備完了です。
F1を押下しAzure App Service: Deploy to Web App...
を選択しDeployします。