带有上游设置的 ARM 脚本 ServerLess SignalR 到 Function App
ARM scripting ServerLess SignalR with Upstream Setting to Function App
我有一个 'ServerLess' SignalR 资源,其上游设置可与支持功能应用程序对话。一切正常。问题是如何自动创建这些资源,因为两者之间似乎存在循环引用。
SignalR 上游设置需要功能应用中的 'signalr_extension' 应用密钥以包含在上游 URL 模板中。相反,功能应用程序需要 'AzureSignalRConnectionString' 应用程序设置。因此循环引用。
使事情复杂化的是,'signalr_extension' App Key 似乎仅在您将 SignalR 触发的函数部署到 Function App 时创建。是否可以在 ARM 模板创建时在 Function App 中设置随机应用密钥 'manually',然后用于构建 SignalR 资源上游设置?
我已经尝试 'dump' 使用 listkeys/listsecrets 将一个有效的函数应用程序作为 ARM 模板中的输出,但是 Host/App 键似乎没有暴露。
是否可以编写脚本(使用 ARM 或 Azure CLI)创建这些资源?
经过一些试验,我想我已经解决了这个问题。以下是步骤:
在ARM模板中,创建Function App和SignalR。使 Function App 依赖于 (dependsOn) Signal。将 SignalR AzureSignalRConnectionString appsetting 注入 Function App。
将函数代码部署到函数应用
使用 Azure CLI 提取 'signalr_extension':
az functionapp keys list --name --resource-group
将生成的 systemKeys/signalr_extension 值放入另一个 Azire CLI 命令中:
az signalr 上游更新 --name --resource-group --template url-template="https://.azurewebsites.net/runtime/webhooks/signalr?code=<步骤 3 中的代码"
至少这一切都可以编写到 DevOps 管道中。
使用 Azure Bicep,我设法一步完成:
仅在 windows.
上测试了函数应用程序 v4 dotnet6
- 创建存储帐户
- 创建应用服务计划(windows)
- 创建没有应用设置的函数应用
- 创建
signalr_extension
系统密钥
- 使用
signalr_extension
系统密钥创建 signalR 服务
- 使用
AzureSignalRConnectionString
连接字符串部署函数应用程序设置。
main.bicep:
param location string = resourceGroup().location
param storageName string
param appServicePlanName string
param functionAppName string
param signalRName string
// Create storage
resource storage 'Microsoft.Storage/storageAccounts@2021-09-01' = {
name: storageName
location: location
kind: 'StorageV2'
sku: {
name: 'Standard_LRS'
}
properties: {
supportsHttpsTrafficOnly: true
minimumTlsVersion: 'TLS1_2'
}
}
// Create serverless app service plan
resource appServicePlan 'Microsoft.Web/serverfarms@2021-03-01' = {
name: appServicePlanName
location: location
sku: {
name: 'Y1'
tier: 'Dynamic'
size: 'Y1'
family: 'Y'
capacity: 0
}
properties: {
reserved: false
}
}
// Create the function app without the app settings
resource functionApp 'Microsoft.Web/sites@2021-03-01' = {
name: functionAppName
location: location
kind: 'functionapp'
properties: {
serverFarmId: appServicePlan.id
clientAffinityEnabled: false
clientCertEnabled: false
httpsOnly: true
siteConfig: {
ftpsState: 'Disabled'
minTlsVersion: '1.2'
cors: {
allowedOrigins: [
'https://portal.azure.com'
]
supportCredentials: false
}
}
}
}
// Create the signalr key
var signalrKeyName = 'signalr_extension'
resource signalRKey 'Microsoft.Web/sites/host/systemkeys@2021-03-01' = {
name: '${functionApp.name}/default/${signalrKeyName}'
properties: {
name: signalrKeyName
}
}
// Create the signalR service and inject the signalr_extension key
resource signalR 'Microsoft.SignalRService/signalR@2022-02-01' = {
name: signalRName
location: location
dependsOn: [
signalRKey
]
sku: {
name: 'Free_F1'
tier: 'Free'
capacity: 1
}
properties: {
features: [
{
flag: 'ServiceMode'
value: 'Serverless'
}
{
flag: 'EnableConnectivityLogs'
value: 'true'
}
]
cors: {
allowedOrigins: [
'*'
]
}
tls: {
clientCertEnabled: false
}
upstream: {
templates: [
{
hubPattern: '*'
eventPattern: '*'
categoryPattern: '*'
auth: {
type: 'None'
}
urlTemplate: 'https://${functionApp.name}.azurewebsites.net/runtime/webhooks/signalr?code=${listKeys(resourceId('Microsoft.Web/sites/host', functionApp.name, 'default'), '2022-03-01').systemkeys.signalr_extension}'
}
]
}
}
}
// Deploy the app settings at the end with the storage and signalR connectionstring
resource functionAppAppSettings 'Microsoft.Web/sites/config@2020-09-01' = {
name: '${functionApp.name}/appsettings'
properties: {
FUNCTIONS_EXTENSION_VERSION: '~4'
FUNCTIONS_WORKER_RUNTIME: 'dotnet'
WEBSITE_RUN_FROM_PACKAGE: '1'
AzureWebJobsStorage: 'DefaultEndpointsProtocol=https;AccountName=${storage.name};AccountKey=${listKeys(storage.id, '2019-06-01').keys[0].value};EndpointSuffix=core.windows.net;'
WEBSITE_CONTENTAZUREFILECONNECTIONSTRING: 'DefaultEndpointsProtocol=https;AccountName=${storage.name};AccountKey=${listKeys(storage.id, '2019-06-01').keys[0].value};EndpointSuffix=core.windows.net;'
WEBSITE_CONTENTSHARE: functionApp.name
AzureSignalRConnectionString: listkeys(signalR.id, signalR.apiVersion).primaryConnectionString
}
}
我有一个 'ServerLess' SignalR 资源,其上游设置可与支持功能应用程序对话。一切正常。问题是如何自动创建这些资源,因为两者之间似乎存在循环引用。
SignalR 上游设置需要功能应用中的 'signalr_extension' 应用密钥以包含在上游 URL 模板中。相反,功能应用程序需要 'AzureSignalRConnectionString' 应用程序设置。因此循环引用。
使事情复杂化的是,'signalr_extension' App Key 似乎仅在您将 SignalR 触发的函数部署到 Function App 时创建。是否可以在 ARM 模板创建时在 Function App 中设置随机应用密钥 'manually',然后用于构建 SignalR 资源上游设置?
我已经尝试 'dump' 使用 listkeys/listsecrets 将一个有效的函数应用程序作为 ARM 模板中的输出,但是 Host/App 键似乎没有暴露。
是否可以编写脚本(使用 ARM 或 Azure CLI)创建这些资源?
经过一些试验,我想我已经解决了这个问题。以下是步骤:
在ARM模板中,创建Function App和SignalR。使 Function App 依赖于 (dependsOn) Signal。将 SignalR AzureSignalRConnectionString appsetting 注入 Function App。
将函数代码部署到函数应用
使用 Azure CLI 提取 'signalr_extension':
az functionapp keys list --name
--resource-group 将生成的 systemKeys/signalr_extension 值放入另一个 Azire CLI 命令中:
az signalr 上游更新 --name
--resource-group --template url-template="https:// .azurewebsites.net/runtime/webhooks/signalr?code=<步骤 3 中的代码"
至少这一切都可以编写到 DevOps 管道中。
使用 Azure Bicep,我设法一步完成:
仅在 windows.
- 创建存储帐户
- 创建应用服务计划(windows)
- 创建没有应用设置的函数应用
- 创建
signalr_extension
系统密钥 - 使用
signalr_extension
系统密钥创建 signalR 服务 - 使用
AzureSignalRConnectionString
连接字符串部署函数应用程序设置。
main.bicep:
param location string = resourceGroup().location
param storageName string
param appServicePlanName string
param functionAppName string
param signalRName string
// Create storage
resource storage 'Microsoft.Storage/storageAccounts@2021-09-01' = {
name: storageName
location: location
kind: 'StorageV2'
sku: {
name: 'Standard_LRS'
}
properties: {
supportsHttpsTrafficOnly: true
minimumTlsVersion: 'TLS1_2'
}
}
// Create serverless app service plan
resource appServicePlan 'Microsoft.Web/serverfarms@2021-03-01' = {
name: appServicePlanName
location: location
sku: {
name: 'Y1'
tier: 'Dynamic'
size: 'Y1'
family: 'Y'
capacity: 0
}
properties: {
reserved: false
}
}
// Create the function app without the app settings
resource functionApp 'Microsoft.Web/sites@2021-03-01' = {
name: functionAppName
location: location
kind: 'functionapp'
properties: {
serverFarmId: appServicePlan.id
clientAffinityEnabled: false
clientCertEnabled: false
httpsOnly: true
siteConfig: {
ftpsState: 'Disabled'
minTlsVersion: '1.2'
cors: {
allowedOrigins: [
'https://portal.azure.com'
]
supportCredentials: false
}
}
}
}
// Create the signalr key
var signalrKeyName = 'signalr_extension'
resource signalRKey 'Microsoft.Web/sites/host/systemkeys@2021-03-01' = {
name: '${functionApp.name}/default/${signalrKeyName}'
properties: {
name: signalrKeyName
}
}
// Create the signalR service and inject the signalr_extension key
resource signalR 'Microsoft.SignalRService/signalR@2022-02-01' = {
name: signalRName
location: location
dependsOn: [
signalRKey
]
sku: {
name: 'Free_F1'
tier: 'Free'
capacity: 1
}
properties: {
features: [
{
flag: 'ServiceMode'
value: 'Serverless'
}
{
flag: 'EnableConnectivityLogs'
value: 'true'
}
]
cors: {
allowedOrigins: [
'*'
]
}
tls: {
clientCertEnabled: false
}
upstream: {
templates: [
{
hubPattern: '*'
eventPattern: '*'
categoryPattern: '*'
auth: {
type: 'None'
}
urlTemplate: 'https://${functionApp.name}.azurewebsites.net/runtime/webhooks/signalr?code=${listKeys(resourceId('Microsoft.Web/sites/host', functionApp.name, 'default'), '2022-03-01').systemkeys.signalr_extension}'
}
]
}
}
}
// Deploy the app settings at the end with the storage and signalR connectionstring
resource functionAppAppSettings 'Microsoft.Web/sites/config@2020-09-01' = {
name: '${functionApp.name}/appsettings'
properties: {
FUNCTIONS_EXTENSION_VERSION: '~4'
FUNCTIONS_WORKER_RUNTIME: 'dotnet'
WEBSITE_RUN_FROM_PACKAGE: '1'
AzureWebJobsStorage: 'DefaultEndpointsProtocol=https;AccountName=${storage.name};AccountKey=${listKeys(storage.id, '2019-06-01').keys[0].value};EndpointSuffix=core.windows.net;'
WEBSITE_CONTENTAZUREFILECONNECTIONSTRING: 'DefaultEndpointsProtocol=https;AccountName=${storage.name};AccountKey=${listKeys(storage.id, '2019-06-01').keys[0].value};EndpointSuffix=core.windows.net;'
WEBSITE_CONTENTSHARE: functionApp.name
AzureSignalRConnectionString: listkeys(signalR.id, signalR.apiVersion).primaryConnectionString
}
}