Краткое руководство. Создание и публикация определения управляемого приложения Azure с помощью Bicep

В этом кратком руководстве описывается, как использовать Bicep для создания и публикации определения управляемого приложения Azure в каталоге служб. Определение в каталоге служб доступно членам вашей организации.

Чтобы создать и опубликовать определение управляемого приложения в каталоге служб, выполните следующие задачи:

  • Используйте Bicep для разработки шаблона и его преобразования в шаблон Azure Resource Manager (шаблон ARM). Шаблон определяет ресурсы Azure, развернутые управляемым приложением.
  • Преобразуйте Bicep в JSON с помощью команды Bicep build . После преобразования файла в JSON рекомендуется проверить код на точность.
  • Определите элементы пользовательского интерфейса для портала при развертывании управляемого приложения.
  • Создайте ZIP-пакет, содержащий необходимые JSON-файлы. Размер ZIP-файла пакета для определения управляемого приложения каталога услуг не должен превышать 120 МБ.
  • Опубликуйте определение управляемого приложения, чтобы оно было доступно в каталоге служб.

Если определение управляемого приложения превышает 120 МБ или если вы хотите использовать собственную учетную запись хранения по соображениям соответствия вашей организации, перейдите в краткое руководство. Создание и публикация определения управляемого приложения Azure.

Вы также можете использовать Bicep для развертывания определения управляемого приложения из каталога служб. Дополнительные сведения см. в кратком руководстве. Использование Bicep для развертывания определения управляемого приложения Azure.

Необходимые компоненты

Чтобы выполнить задачи в этой статье, вам потребуется следующее:

Создание BICEP-файла

В каждом определении управляемого приложения указан файл с именем mainTemplate.json. Шаблон определяет ресурсы Azure для развертывания и не отличается от обычного шаблона ARM. Вы можете разработать шаблон с помощью Bicep, а затем преобразовать файл Bicep в JSON.

Откройте Visual Studio Code, создайте файл с учетом регистра mainTemplate.bicep и сохраните его.

Добавьте следующий код Bicep и сохраните файл. Он определяет ресурсы управляемого приложения для развертывания Служба приложений, плана Служба приложений и учетной записи хранения.

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.

После преобразования Bicep-файла в JSON файл mainTemplate.json должен соответствовать следующему примеру. У вас могут быть разные значения в metadata свойствах и templateHashversion .

{
  "$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 создает пользовательский интерфейс портала. Вы определяете, как пользователи предоставляют входные данные для каждого параметра с помощью элементов управления, таких как раскрывающийся список и текстовые поля.

В этом примере пользовательский интерфейс предложит ввести префикс имени Служба приложений, имя плана Служба приложений, префикс учетной записи хранения и тип учетной записи хранения. Во время развертывания переменные в 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 Введите универсальный код ресурса (URI) для ZIP-файла пакета. packageuri Используйте значение переменной. Формат — https://yourStorageAccountName.blob.core.windows.net/appcontainer/app.zip.
principalId Идентификатор субъекта-издателя, которому требуются разрешения на управление ресурсами в управляемой группе ресурсов. 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.

Если вы закончите работу с определением управляемого приложения, можно удалить созданные вами группы ресурсов служба хранилища RG и bicepDefinitionRG.

В командной строке вы убедитесь, что вы хотите удалить группу ресурсов.

Remove-AzResourceGroup -Name packageStorageRG

Remove-AzResourceGroup -Name bicepDefinitionRG

Следующие шаги

Вы опубликовали определение управляемого приложения. Следующий шаг — узнать, как развернуть экземпляр этого определения.

Краткое руководство. Развертывание определения управляемого приложения Azure с помощью Bicep.