快速入门:创建和发布 Azure 托管应用程序定义
本快速入门简单介绍了如何使用 Azure 托管应用程序。 创建并发布托管应用程序定义,它存储在服务目录中并面向组织的成员。
要将托管应用程序发布到服务目录,请执行以下任务:
- 创建一个 Azure 资源管理器模板(ARM 模板),用于定义使用托管应用程序部署的资源。
- 部署托管应用程序时,请定义门户的用户界面元素。
- 创建包含必需 JSON 文件的 .zip 包。 该 .zip 包文件对于服务目录的托管应用程序定义具有 120 MB 的限制。
- 发布托管应用程序定义,使其在服务目录中可用。
如果你的托管应用程序定义超过 120 MB,或者出于组织的合规性原因你想要使用自己的存储帐户,请转到快速入门:使用自己的存储来创建和发布 Azure 托管应用程序定义。
可以使用 Bicep 开发托管应用程序定义,但必须先将其转换为 ARM 模板 JSON,然后才能在 Azure 中发布定义。 有关详细信息,请转到快速入门:使用 Bicep 创建和发布 Azure 托管应用程序定义。
还可以使用 Bicep 从服务目录部署托管应用程序定义。 有关详细信息,请转到快速入门:使用 Bicep 部署 Azure 托管应用程序定义。
先决条件
若要完成本快速入门,需要准备好以下各项:
- 具有活动订阅且有权访问 Microsoft Entra 资源(如用户、组或服务主体)的 Azure 帐户。 如果没有帐户,请在开始之前创建一个试用版帐户。
- 包含最新 Azure 资源管理器工具扩展的 Visual Studio Code。 对于 Bicep 文件,请安装适用于 Visual Studio Code 的 Bicep 扩展。
- 安装最新版本的 Azure PowerShell 或 Azure CLI。
创建 ARM 模板
每个托管应用程序定义均包含一个名为 mainTemplate.json 的文件。 该模板定义了要部署的 Azure 资源,与常规 ARM 模板没有什么不同。
打开 Visual Studio Code,创建一个名称区分大小写的文件 mainTemplate.json 并保存它。
添加以下 JSON 并保存文件。 它定义了用于部署应用程序服务、应用服务计划和应用程序存储帐户的资源。 此存储帐户不用于存储托管应用程序定义。
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]"
},
"appServicePlanName": {
"type": "string",
"maxLength": 40,
"metadata": {
"description": "App Service plan name."
}
},
"appServiceNamePrefix": {
"type": "string",
"maxLength": 47,
"metadata": {
"description": "App Service name prefix."
}
},
"storageAccountNamePrefix": {
"type": "string",
"maxLength": 11,
"metadata": {
"description": "Storage account name prefix."
}
},
"storageAccountType": {
"type": "string",
"allowedValues": [
"Premium_LRS",
"Standard_LRS",
"Standard_GRS"
],
"metadata": {
"description": "Storage account type allowed values"
}
}
},
"variables": {
"appServicePlanSku": "F1",
"appServicePlanCapacity": 1,
"appServiceName": "[format('{0}{1}', parameters('appServiceNamePrefix'), uniqueString(resourceGroup().id))]",
"storageAccountName": "[format('{0}{1}', parameters('storageAccountNamePrefix'), uniqueString(resourceGroup().id))]"
},
"resources": [
{
"type": "Microsoft.Web/serverfarms",
"apiVersion": "2022-09-01",
"name": "[parameters('appServicePlanName')]",
"location": "[parameters('location')]",
"sku": {
"name": "[variables('appServicePlanSku')]",
"capacity": "[variables('appServicePlanCapacity')]"
}
},
{
"type": "Microsoft.Web/sites",
"apiVersion": "2022-09-01",
"name": "[variables('appServiceName')]",
"location": "[parameters('location')]",
"properties": {
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', parameters('appServicePlanName'))]",
"httpsOnly": true,
"siteConfig": {
"appSettings": [
{
"name": "AppServiceStorageConnectionString",
"value": "[format('DefaultEndpointsProtocol=https;AccountName={0};EndpointSuffix={1};Key={2}', variables('storageAccountName'), environment().suffixes.storage, listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2023-01-01').keys[0].value)]"
}
]
}
},
"dependsOn": [
"[resourceId('Microsoft.Web/serverfarms', parameters('appServicePlanName'))]",
"[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]"
]
},
{
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2023-01-01",
"name": "[variables('storageAccountName')]",
"location": "[parameters('location')]",
"sku": {
"name": "[parameters('storageAccountType')]"
},
"kind": "StorageV2",
"properties": {
"accessTier": "Hot",
"allowSharedKeyAccess": false,
"minimumTlsVersion": "TLS1_2"
}
}
],
"outputs": {
"appServicePlan": {
"type": "string",
"value": "[parameters('appServicePlanName')]"
},
"appServiceApp": {
"type": "string",
"value": "[reference(resourceId('Microsoft.Web/sites', variables('appServiceName')), '2022-09-01').defaultHostName]"
},
"storageAccount": {
"type": "string",
"value": "[reference(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2023-01-01').primaryEndpoints.blob]"
}
}
}
定义门户体验
作为发布者,你需要定义创建托管应用程序的门户体验。 createUiDefinition.json 文件生成门户的用户界面。 使用控件元素(如下拉框和文本框)来定义用户如何为每个参数提供输入。
在此例中,用户界面会提示你输入应用程序服务名称前缀、应用服务计划的名称、存储帐户前缀和存储帐户类型。 在部署期间,mainTemplate.json 中的变量使用 uniqueString
函数将包含 13 个字符的字符串追加到名称前缀,以便名称在 Azure 中是全局唯一的。
打开 Visual Studio Code,创建一个名称区分大小写的文件 createUiDefinition.json 并保存它。
将以下 JSON 代码添加到文件并保存它。
{
"$schema": "https://schema.management.azure.com/schemas/0.1.2-preview/CreateUIDefinition.MultiVm.json#",
"handler": "Microsoft.Azure.CreateUIDef",
"version": "0.1.2-preview",
"parameters": {
"basics": [
{}
],
"steps": [
{
"name": "webAppSettings",
"label": "Web App settings",
"subLabel": {
"preValidation": "Configure the web app settings",
"postValidation": "Completed"
},
"elements": [
{
"name": "appServicePlanName",
"type": "Microsoft.Common.TextBox",
"label": "App Service plan name",
"placeholder": "App Service plan name",
"defaultValue": "",
"toolTip": "Use alphanumeric characters or hyphens with a maximum of 40 characters.",
"constraints": {
"required": true,
"regex": "^[a-z0-9A-Z-]{1,40}$",
"validationMessage": "Only alphanumeric characters or hyphens are allowed, with a maximum of 40 characters."
},
"visible": true
},
{
"name": "appServiceName",
"type": "Microsoft.Common.TextBox",
"label": "App Service name prefix",
"placeholder": "App Service name prefix",
"defaultValue": "",
"toolTip": "Use alphanumeric characters or hyphens with minimum of 2 characters and maximum of 47 characters.",
"constraints": {
"required": true,
"regex": "^[a-z0-9A-Z-]{2,47}$",
"validationMessage": "Only alphanumeric characters or hyphens are allowed, with a minimum of 2 characters and maximum of 47 characters."
},
"visible": true
}
]
},
{
"name": "storageConfig",
"label": "Storage settings",
"subLabel": {
"preValidation": "Configure the storage settings",
"postValidation": "Completed"
},
"elements": [
{
"name": "storageAccounts",
"type": "Microsoft.Storage.MultiStorageAccountCombo",
"label": {
"prefix": "Storage account name prefix",
"type": "Storage account type"
},
"toolTip": {
"prefix": "Enter maximum of 11 lowercase letters or numbers.",
"type": "Available choices are Standard_LRS, Standard_GRS, and Premium_LRS."
},
"defaultValue": {
"type": "Standard_LRS"
},
"constraints": {
"allowedTypes": [
"Premium_LRS",
"Standard_LRS",
"Standard_GRS"
]
},
"visible": true
}
]
}
],
"outputs": {
"location": "[location()]",
"appServicePlanName": "[steps('webAppSettings').appServicePlanName]",
"appServiceNamePrefix": "[steps('webAppSettings').appServiceName]",
"storageAccountNamePrefix": "[steps('storageConfig').storageAccounts.prefix]",
"storageAccountType": "[steps('storageConfig').storageAccounts.type]"
}
}
}
若要了解详细信息,请参阅 CreateUiDefinition 入门。
将文件打包
将这两个文件添加到名为 app.zip 的包文件中。 这两个文件必须都位于该 .zip 文件的根级别。 如果文件位于文件夹中,则当你创建托管应用程序定义时,你会收到一条错误消息,指出所需文件不存在。
将 app.zip 上传到 Azure 存储帐户,以便在部署托管应用程序的定义时使用它。 存储帐户名称在 Azure 中必须是全局唯一的,长度必须为 3-24 个字符,仅包含小写字母和数字。 在命令中,将占位符<pkgstorageaccountname>
(包括尖括号 (<>
)) 替换为唯一的存储帐户名称。
在 Visual Studio Code 中,打开新的 PowerShell 终端并登录到 Azure 订阅。
Connect-AzAccount
此命令会打开默认浏览器,并提示登录到 Azure。 有关详细信息,请转到使用 Azure PowerShell 登录。
New-AzResourceGroup -Name packageStorageGroup -Location chinanorth3
$pkgstorageparms = @{
ResourceGroupName = "packageStorageGroup"
Name = "<pkgstorageaccountname>"
Location = "chinanorth3"
SkuName = "Standard_LRS"
Kind = "StorageV2"
MinimumTlsVersion = "TLS1_2"
AllowBlobPublicAccess = $true
AllowSharedKeyAccess = $false
}
$pkgstorageaccount = New-AzStorageAccount @pkgstorageparms
$pkgstorageparms
变量使用 PowerShell splatting 来提高用于创建新存储帐户的命令中使用的参数值的可读性。 Splatting 可用于使用多个参数值的其他 PowerShell 命令。
创建存储帐户后,将角色分配存储 Blob 数据参与者添加到存储帐户范围中。 分配对 Microsoft Entra 用户帐户的访问权限。 根据 Azure 中的访问级别,你可能需要管理员分配的其他权限。 有关详细信息,请参阅分配用于访问 Blob 数据的 Azure 角色。
向存储帐户添加角色后,需要几分钟才能在 Azure 中激活。 然后,可以创建创建容器和上传文件所需的上下文。
$pkgstoragecontext = New-AzStorageContext -StorageAccountName $pkgstorageaccount.StorageAccountName -UseConnectedAccount
New-AzStorageContainer -Name appcontainer -Context $pkgstoragecontext -Permission blob
$blobparms = @{
File = "app.zip"
Container = "appcontainer"
Blob = "app.zip"
Context = $pkgstoragecontext
}
Set-AzStorageBlobContent @blobparms
创建托管应用程序定义
在本部分中,你将从 Microsoft Entra ID 获取标识信息、创建资源组并部署托管应用程序定义。
获取组 ID 和角色定义 ID
下一步是选择用于为客户管理资源的用户、安全组或应用程序。 此标识对受管理资源组的权限与所分配的角色相对应。 角色可以是任何 Azure 内置角色,例如所有者或参与者。
此示例使用安全组,并且 Microsoft Entra 帐户应是组的成员。 若要获取组的对象 ID,请将占位符<managedAppDemo>
((包括尖括号 (<>
)) 替换为组的名称。 你将在部署托管应用程序定义时使用此变量的值。
若要创建新的 Microsoft Entra 组,请转到管理 Microsoft Entra 组和组成员身份。
$principalid=(Get-AzADGroup -DisplayName <managedAppDemo>).Id
接下来,获取希望将其访问权限授予用户、组或应用程序的 Azure 内置角色的角色定义 ID。 你将在部署托管应用程序定义时使用此变量的值。
$roleid=(Get-AzRoleDefinition -Name Owner).Id
发布托管应用程序定义
为托管应用程序定义创建资源组。
New-AzResourceGroup -Name appDefinitionGroup -Location chinanorth3
blob
命令将创建一个变量来存储包 .zip 文件的 URL。 该变量用于创建托管应用程序定义的命令。
$blob = Get-AzStorageBlob -Container appcontainer -Blob app.zip -Context $pkgstoragecontext
$publishparms = @{
Name = "sampleManagedApplication"
Location = "chinanorth3"
ResourceGroupName = "appDefinitionGroup"
LockLevel = "ReadOnly"
DisplayName = "Sample managed application"
Description = "Sample managed application that deploys web resources"
Authorization = "${principalid}:$roleid"
PackageFileUri = $blob.ICloudBlob.StorageUri.PrimaryUri.AbsoluteUri
}
New-AzManagedApplicationDefinition @publishparms
命令完成后,资源组中会有一个托管应用程序定义。
前述示例中使用的部分参数包括:
ResourceGroupName
:在其中创建托管应用程序定义的资源组的名称。LockLevel
:受管理资源组上的lockLevel
可防止客户对此资源组执行不良操作。 目前,ReadOnly
是唯一受支持的锁定级别。ReadOnly
指定客户只能读取受管理资源组中存在的资源。 授予对受管理资源组的访问权限的发布者标识不受该锁定级别控制。Authorization
:描述用于授予对托管资源组权限的主体 ID 和角色定义 ID。"${principalid}:$roleid"
或者可以为每个变量"${principalid}:${roleid}"
使用大括号。- 使用逗号分隔多个值:
"${principalid1}:$roleid1", "${principalid2}:$roleid2"
。
PackageFileUri
:包含所需文件的 .zip 包文件的位置。
请确保用户可以看到你的定义
你可以访问托管应用程序定义,但你希望确保组织中的其他用户可以访问它。 至少授予他们对定义的读者角色。 他们可能已从订阅或资源组继承了此级别的访问权限。 若要检查谁有权访问定义并添加用户或组,请参阅使用 Azure 门户分配 Azure 角色。
清理资源
如果要部署定义,请继续阅读链接到该文章的“后续步骤”部分来部署定义。
如果已完成托管应用程序定义,则可以删除创建的名为 packageStorageGroup 和 appDefinitionGroup 的资源组。
命令会提示你确认删除资源组。
Remove-AzResourceGroup -Name packageStorageGroup
Remove-AzResourceGroup -Name appDefinitionGroup
后续步骤
已发布托管应用程序定义。 下一步是了解如何部署该定义的实例。