快速入門:使用 Bicep 建立和發佈 Azure 受控應用程式定義
本快速入門說明如何使用 Bicep 在服務類別目錄中建立和發佈 Azure 受控應用程式定義。 服務類別目錄中的定義可供組織成員使用。
若要建立受控應用程式定義並發佈至您的服務類別目錄,請執行下列工作:
- 使用 Bicep 來開發您的範本,並將其轉換為 Azure Resource Manager 範本 (ARM 範本)。 此範本會定義受控應用程式所部署的 Azure 資源。
- 使用 Bicep
build
命令將 Bicep 轉換為 JSON。 將檔案轉換成 JSON 之後,建議您確認程式碼的正確性。 - 部署受控應用程式時,定義入口網站的使用者介面元素。
- 建立包含必要 JSON 檔案的 .zip 套件。 .zip 套件檔案對於服務類別目錄的受控應用程式定義具有 120 MB 限制。
- 發佈受控應用程式定義,使其可在您的服務類別目錄中使用。
如果您的受控應用程式定義超過 120 MB,或基於組織的合規性原因而想使用自己的儲存體帳戶,請移至快速入門:自備儲存體來建立及發佈 Azure 受控應用程式定義。
您也可以使用 Bicep 從服務類別目錄部署受控應用程式定義。 如需詳細資訊,請移至快速入門:使用 Bicep 部署 Azure 受控應用程式定義。
必要條件
若要完成這篇文章中的工作,您需要下列項目︰
- 具有作用中訂用帳戶,以及對 Microsoft Entra 資源 (例如使用者、群組或服務主體) 具有權限的 Azure 帳戶。 如果您沒有帳戶,請在開始之前建立免費帳戶。
- Visual Studio Code 搭配最新的 Azure Resource Manager 工具延伸模組。 針對 Bicep 檔案,請安裝適用於 Visual Studio Code 的 Bicep 延伸模組。
- 安裝最新版的 Azure PowerShell 或 Azure CLI。
建立 Bicep 檔案
每個受控應用程式定義都包含名為 mainTemplate.json 的檔案。 此範本會定義要部署的 Azure 資源,而且與一般 ARM 範本不同。 您可以使用 Bicep 來開發範本,然後將 Bicep 檔案轉換成 JSON。
開啟 Visual Studio Code,建立具有區分大小寫名稱 mainTemplate.bicep 的檔案,並加以儲存。
新增下列 Bicep 程式碼並儲存檔案。 它會定義受控應用程式的資源,以部署 App Service、App Service 方案和儲存體帳戶。
param location string = resourceGroup().location
@description('App Service plan name.')
@maxLength(40)
param appServicePlanName string
@description('App Service name prefix.')
@maxLength(47)
param appServiceNamePrefix string
@description('Storage account name prefix.')
@maxLength(11)
param storageAccountNamePrefix string
@description('Storage account type allowed values')
@allowed([
'Premium_LRS'
'Standard_LRS'
'Standard_GRS'
])
param storageAccountType string
var appServicePlanSku = 'F1'
var appServicePlanCapacity = 1
var appServiceName = '${appServiceNamePrefix}${uniqueString(resourceGroup().id)}'
var storageAccountName = '${storageAccountNamePrefix}${uniqueString(resourceGroup().id)}'
var appServiceStorageConnectionString = 'DefaultEndpointsProtocol=https;AccountName=${storageAccount.name};EndpointSuffix=${environment().suffixes.storage};Key=${storageAccount.listKeys().keys[0].value}'
resource appServicePlan 'Microsoft.Web/serverfarms@2022-03-01' = {
name: appServicePlanName
location: location
sku: {
name: appServicePlanSku
capacity: appServicePlanCapacity
}
}
resource appServiceApp 'Microsoft.Web/sites@2022-03-01' = {
name: appServiceName
location: location
properties: {
serverFarmId: appServicePlan.id
httpsOnly: true
siteConfig: {
appSettings: [
{
name: 'AppServiceStorageConnectionString'
value: appServiceStorageConnectionString
}
]
}
}
}
resource storageAccount 'Microsoft.Storage/storageAccounts@2022-09-01' = {
name: storageAccountName
location: location
sku: {
name: storageAccountType
}
kind: 'StorageV2'
properties: {
accessTier: 'Hot'
}
}
output appServicePlan string = appServicePlan.name
output appServiceApp string = appServiceApp.properties.defaultHostName
output storageAccount string = storageAccount.properties.primaryEndpoints.blob
將 Bicep 轉換為 JSON
使用 PowerShell 或 Azure CLI 來建置 mainTemplate.json 檔案。 移至儲存 Bicep 檔案的目錄並執行 build
命令。
bicep build mainTemplate.bicep
若要深入了解,請移至 Bicep build。
將 Bicep 檔案轉換成 JSON 之後,您的 mainTemplate.json 檔案應該符合下列範例。 在 version
和 templateHash
的 metadata
屬性中,您可能有不同的值。
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"metadata": {
"_generator": {
"name": "bicep",
"version": "0.17.1.54307",
"templateHash": "1234567891234567890"
}
},
"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-03-01",
"name": "[parameters('appServicePlanName')]",
"location": "[parameters('location')]",
"sku": {
"name": "[variables('appServicePlanSku')]",
"capacity": "[variables('appServicePlanCapacity')]"
}
},
{
"type": "Microsoft.Web/sites",
"apiVersion": "2022-03-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')), '2022-09-01').keys[0].value)]"
}
]
}
},
"dependsOn": [
"[resourceId('Microsoft.Web/serverfarms', parameters('appServicePlanName'))]",
"[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]"
]
},
{
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2022-09-01",
"name": "[variables('storageAccountName')]",
"location": "[parameters('location')]",
"sku": {
"name": "[parameters('storageAccountType')]"
},
"kind": "StorageV2",
"properties": {
"accessTier": "Hot"
}
}
],
"outputs": {
"appServicePlan": {
"type": "string",
"value": "[parameters('appServicePlanName')]"
},
"appServiceApp": {
"type": "string",
"value": "[reference(resourceId('Microsoft.Web/sites', variables('appServiceName')), '2022-03-01').defaultHostName]"
},
"storageAccount": {
"type": "string",
"value": "[reference(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2022-09-01').primaryEndpoints.blob]"
}
}
}
定義入口網站體驗
身為發行者,您可以定義用來建立受控應用程式的入口網站體驗。 createUiDefinition.json 檔案會產生入口網站的使用者介面。 您可以使用下拉式清單和文字輸入框等控制項元素,定義使用者為每個參數提供輸入的方式。
在此範例中,使用者介面會提示您輸入 App Service 名稱前置詞、App Service 方案的名稱、儲存體帳戶前置詞和儲存體帳戶類型。 在部署期間,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 個字元,且只有小寫字母和數字。 在命令中,以您唯一的儲存體帳戶名稱取代包括角括弧 (<>
) 的預留位置 <demostorageaccount>
。
在 Visual Studio Code 中,開啟新的 PowerShell 終端機並登入您的 Azure 訂用帳戶。
Connect-AzAccount
此命令會開啟您的預設瀏覽器,並提示您登入 Azure。 如需詳細資訊,請移至使用 Azure PowerShell 登入。
在您連線之後,請執行下列命令。
New-AzResourceGroup -Name packageStorageRG -Location westus3
$storageAccount = New-AzStorageAccount `
-ResourceGroupName packageStorageRG `
-Name "<demostorageaccount>" `
-Location westus3 `
-SkuName Standard_LRS `
-Kind StorageV2 `
-AllowBlobPublicAccess $true
$ctx = $storageAccount.Context
New-AzStorageContainer -Name appcontainer -Context $ctx -Permission blob
Set-AzStorageBlobContent `
-File "app.zip" `
-Container appcontainer `
-Blob "app.zip" `
-Context $ctx
使用下列命令,將封裝檔案的 URI 儲存在名為 packageuri
的變數中。 您部署受控應用程式定義時,將會使用變數的值。
$packageuri=(Get-AzStorageBlob -Container appcontainer -Blob app.zip -Context $ctx).ICloudBlob.StorageUri.PrimaryUri.AbsoluteUri
建立受控應用程式定義
在本節中,您會從 Microsoft Entra ID 取得身分識別資訊、建立資源群組,以及部署受控應用程式定義。
取得群組識別碼和角色定義識別碼
下一個步驟是選取要為客戶管理資源的使用者、安全性群組或應用程式。 此身分識別會根據指派的角色,取得受控資源群組的權限。 角色可以是任何內建的 Azure 角色,例如擁有者或參與者。
此範例會使用安全性群組,而您的 Microsoft Entra 帳戶應是群組的成員。 若要取得群組的物件識別碼,請使用群組的名稱取代包括角括弧 (<>
) 的預留位置 <managedAppDemo>
。 您部署受控應用程式定義時,將會使用變數的值。
若要建立新的 Microsoft Entra 群組,請移至管理 Microsoft Entra 群組和群組成員資格。
$principalid=(Get-AzADGroup -DisplayName <managedAppDemo>).Id
接下來,取得您想要授與使用者、群組或應用程式存取權的 Azure 內建角色的角色定義識別碼。 您部署受控應用程式定義時,將會使用變數的值。
$roleid=(Get-AzRoleDefinition -Name Owner).Id
建立定義部署範本
使用 Bicep 檔案在服務類別目錄中部署受控應用程式定義。
開啟 Visual Studio Code,建立名稱為 deployDefinition.bicep 的檔案並加以儲存。
新增下列 Bicep 程式碼並儲存檔案。
param location string = resourceGroup().location
@description('Name of the managed application definition.')
param managedApplicationDefinitionName string
@description('The URI of the .zip package file.')
param packageFileUri string
@description('Publishers Principal ID that needs permissions to manage resources in the managed resource group.')
param principalId string
@description('Role ID for permissions to the managed resource group.')
param roleId string
var definitionLockLevel = 'ReadOnly'
var definitionDisplayName = 'Sample Bicep managed application'
var definitionDescription = 'Sample Bicep managed application that deploys web resources'
resource managedApplicationDefinition 'Microsoft.Solutions/applicationDefinitions@2021-07-01' = {
name: managedApplicationDefinitionName
location: location
properties: {
lockLevel: definitionLockLevel
description: definitionDescription
displayName: definitionDisplayName
packageFileUri: packageFileUri
authorizations: [
{
principalId: principalId
roleDefinitionId: roleId
}
]
}
}
如需範本屬性的詳細資訊,請移至 Microsoft.Solutions/applicationDefinitions。
受控資源群組上的 lockLevel
會防止客戶在此資源群組上執行不想要的作業。 目前唯一支援的鎖定等級是 ReadOnly
。 ReadOnly
指定客戶只能讀取受控資源群組中存在的資源。 獲授與受控資源群組存取權的發行者身分識別不受鎖定等級的限制。
建立參數檔案
受控應用程式定義的部署範本要求為多個參數輸入值。 部署命令會提示您輸入值,您也可以為值建立參數檔案。 在此範例中,我們使用參數檔案將參數值傳遞至部署命令。
在 Visual Studio Code 中,建立名為 deployDefinition.parameters.json 的新檔案,並加以儲存。
將下列內容新增至參數檔案並加以儲存。 然後,使用您的值取代包括角括弧 (<>
) 的 <placeholder values>
。
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"managedApplicationDefinitionName": {
"value": "sampleBicepManagedApplication"
},
"packageFileUri": {
"value": "<placeholder for the packageFileUri>"
},
"principalId": {
"value": "<placeholder for principalid value>"
},
"roleId": {
"value": "<placeholder for roleid value>"
}
}
}
下表描述受控應用程式定義的參數值。
參數 | 值 |
---|---|
managedApplicationDefinitionName |
受控應用程式定義的名稱。 在此範例中,請使用 sampleBicepManagedApplication。 |
packageFileUri |
輸入 .zip 封裝檔案的 URI。 使用變數 packageuri 的值。 格式為 https://yourStorageAccountName.blob.core.windows.net/appcontainer/app.zip 。 |
principalId |
需要管理受控資源群組中資源之權限的發行者主體 ID。 使用變數 principalid 的值。 |
roleId |
具有受控資源群組權限的角色識別碼。 例如擁有者、參與者、讀者。 使用變數 roleid 的值。 |
若要取得變數值:
- Azure PowerShell:在 PowerShell 中,輸入
$variableName
以顯示變數的值。 - Azure CLI:在 Bash 中,輸入
echo $variableName
以顯示變數的值。
部署定義
您部署受控應用程式的定義時,它會在您的服務類別目錄中變成可用。 此處理不會部署受控應用程式的資源。
建立名為 bicepDefinitionRG 的資源群組,並部署受控應用程式定義。
New-AzResourceGroup -Name bicepDefinitionRG -Location westus3
New-AzResourceGroupDeployment `
-ResourceGroupName bicepDefinitionRG `
-TemplateFile deployDefinition.bicep `
-TemplateParameterFile deployDefinition.parameters.json
驗證結果
執行下列命令來確認定義已發佈在您的服務類別目錄中。
Get-AzManagedApplicationDefinition -ResourceGroupName bicepDefinitionRG
Get-AzManagedApplicationDefinition
會列出指定資源群組 (例如 sampleBicepManagedApplication) 中所有可用的定義。
請確定使用者可以存取您的定義
您可以存取受控應用程式定義,但您想確保您組織中的其他使用者可以存取它。 至少在定義上將讀者角色授與給他們。 他們可能已從訂用帳戶或資源群組繼承此存取層級。 若要查看可存取定義和新增使用者或群組的人員,請移至使用 Azure 入口網站指派 Azure 角色。
清除資源
如果您要部署定義,請繼續移至後續步驟一節,其連結到使用 Bicep 部署定義的文章。
如果您已完成受控應用程式定義,可以刪除您所建立且名為 packageStorageRG 和 bicepDefinitionRG 的資源群組。
命令會提示您確認要移除資源群組。
Remove-AzResourceGroup -Name packageStorageRG
Remove-AzResourceGroup -Name bicepDefinitionRG
下一步
您已發佈受控應用程式定義。 下一個步驟是了解如何部署該定義的執行個體。