Упражнение. Добавление параметров в сценарии развертывания

Завершено

После того как вы использовали сценарий развертывания для переноса операций, выполняемых вручную, в шаблон Azure Resource Manager (ARM), другая партнерская группа приложений в вашей организации попросила вас о помощи.

Процесс команды предъявляет аналогичные требования, но группе необходимо развернуть несколько файлов в своей учетной записи хранения. У команды есть сценарий PowerShell, который может принять список файлов в качестве параметра и передать их, как и сценарий, который уже использовался в шаблоне.

В этом упражнении вы будете использовать предыдущий шаблон в качестве отправной точки и обновите сценарий PowerShell, чтобы использовать его из партнерской команды. Затем добавьте способ, позволяющий пользователю, который развертывает шаблон, указать, какие файлы конфигурации (один или несколько) следует развернуть.

В процессе вы:

  • Обновите сценарий развертывания.
  • Добавьте переменную среды и параметр шаблона и передайте их в сценарий развертывания.
  • Добавьте выходные данные в сценарий развертывания.
  • Добавьте файл параметров.
  • Разверните шаблон и проверьте результат.

Создание начального шаблона

Начнем с шаблона, созданного в предыдущем упражнении.

  1. Откройте Visual Studio Code и создайте новый файл с именем azuredeploy.json.

  2. Скопируйте следующий начальный шаблон в azuredeploy.json.

    {
        "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
        "contentVersion": "1.0.0.1",
        "apiProfile": "",
        "parameters": {},
        "variables": {
            "storageAccountName": "[concat('storage', uniqueString(resourceGroup().id))]",
            "storageBlobContainerName": "config",
            "userAssignedIdentityName": "configDeployer",
            "roleAssignmentName": "[guid(concat(resourceGroup().id, 'contributor'))]",
            "contributorRoleDefinitionId": "[resourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]",
            "deploymentScriptName": "CopyConfigScript"
        },
        "functions": [],
        "resources": [
            {
                "name": "[variables('storageAccountName')]",
                "type": "Microsoft.Storage/storageAccounts",
                "apiVersion": "2023-01-01",
                "tags": {
                    "displayName": "[variables('storageAccountName')]"
                },
                "location": "[resourceGroup().location]",
                "kind": "StorageV2",
                "sku": {
                    "name": "Standard_LRS",
                    "tier": "Standard"
                },
                "properties": {
                    "allowBlobPublicAccess": true,
                    "encryption": {
                        "services": {
                            "blob": {
                                "enabled": true
                            }
                        },
                        "keySource": "Microsoft.Storage"
                    },
                    "supportsHttpsTrafficOnly": true
                }
            },
            {
                "type": "Microsoft.Storage/storageAccounts/blobServices",
                "apiVersion": "2019-04-01",
                "name": "[concat(variables('storageAccountName'), '/default')]",
                "dependsOn": [
                    "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]"
                ]
            },
            {
                "type": "Microsoft.Storage/storageAccounts/blobServices/containers",
                "apiVersion": "2019-04-01",
                "name": "[concat(variables('storageAccountName'),'/default/',variables('storageBlobContainerName'))]",
                "dependsOn": [
                    "[resourceId('Microsoft.Storage/storageAccounts/blobServices', variables('storageAccountName'), 'default')]",
                    "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]"
                ],
                "properties": {
                    "publicAccess": "Blob"
                }
            },
            {
                "type": "Microsoft.ManagedIdentity/userAssignedIdentities",
                "apiVersion": "2018-11-30",
                "name": "[variables('userAssignedIdentityName')]",
                "location": "[resourceGroup().location]"
            },
            {
                "type": "Microsoft.Authorization/roleAssignments",
                "apiVersion": "2020-04-01-preview",
                "name": "[variables('roleAssignmentName')]",
                "dependsOn": [ "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('userAssignedIdentityName'))]" ],
                "properties": {
                    "roleDefinitionId": "[variables('contributorRoleDefinitionId')]",
                    "principalId": "[reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('userAssignedIdentityName')), '2015-08-31-preview').principalId]",
                    "scope": "[resourceGroup().id]",
                    "principalType": "ServicePrincipal"
                }
            },
            {
                "type": "Microsoft.Resources/deploymentScripts",
                "apiVersion": "2020-10-01",
                "name": "[variables('deploymentScriptName')]",
                "location": "[resourceGroup().location]",
                "kind": "AzurePowerShell",
                "dependsOn": [
                    "[resourceId('Microsoft.Authorization/roleAssignments', variables('roleAssignmentName'))]",
                    "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', variables('storageAccountName'), 'default', variables('storageBlobContainerName'))]"
                ],
                "identity": {
                    "type": "UserAssigned",
                    "userAssignedIdentities": {
                        "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities',variables('userAssignedIdentityName'))]": {}
                    }
                },
                "properties": {
                    "azPowerShellVersion": "3.0",
                    "scriptContent": "
                        Invoke-RestMethod -Uri 'https://raw.githubusercontent.com/Azure/azure-docs-json-samples/master/mslearn-arm-deploymentscripts-sample/appsettings.json' -OutFile 'appsettings.json'
                        $storageAccount = Get-AzStorageAccount -ResourceGroupName 'learndeploymentscript_exercise_1' | Where-Object { $_.StorageAccountName -like 'storage*' }
                        $blob = Set-AzStorageBlobContent -File 'appsettings.json' -Container 'config' -Blob 'appsettings.json' -Context $StorageAccount.Context
                        $DeploymentScriptOutputs = @{}
                        $DeploymentScriptOutputs['Uri'] = $blob.ICloudBlob.Uri
                        $DeploymentScriptOutputs['StorageUri'] = $blob.ICloudBlob.StorageUri
                    ",
                    "retentionInterval": "P1D"
                }
            }
        ],
        "outputs": {
            "fileUri": {
                "type": "string",
                "value": "[reference(variables('deploymentScriptName')).outputs.Uri]"
            }
        }
    }
    
  3. Сохраните шаблон.

  1. Откройте Visual Studio Code и создайте новый файл с именем main.bicep.

  2. Скопируйте следующий начальный шаблон в main.bicep.

    var storageAccountName = 'storage${uniqueString(resourceGroup().id)}'
    var storageBlobContainerName = 'config'
    var userAssignedIdentityName = 'configDeployer'
    var roleAssignmentName = guid(resourceGroup().id, 'contributor')
    var contributorRoleDefinitionId = resourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')
    var deploymentScriptName = 'CopyConfigScript'
    
    resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = {
      name: storageAccountName
      tags: {
        displayName: storageAccountName
      }
      location: resourceGroup().location
      kind: 'StorageV2'
      sku: {
        name: 'Standard_LRS'
        tier: 'Standard'
      }
      properties: {
        allowBlobPublicAccess: true
        encryption: {
          services: {
            blob: {
              enabled: true
            }
          }
          keySource: 'Microsoft.Storage'
        }
        supportsHttpsTrafficOnly: true
      }
    
      resource blobService 'blobServices' existing = {
        name: 'default'
      }
    }
    
    resource blobContainer 'Microsoft.Storage/storageAccounts/blobServices/containers@2019-04-01' = {
      parent: storageAccount::blobService
      name: storageBlobContainerName
      properties: {
        publicAccess: 'Blob'
      }
    }
    
    resource userAssignedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = {
      name: userAssignedIdentityName
      location: resourceGroup().location
    }
    
    resource roleAssignment 'Microsoft.Authorization/roleAssignments@2020-04-01-preview' = {
      name: roleAssignmentName
      properties: {
        roleDefinitionId: contributorRoleDefinitionId
        principalId: userAssignedIdentity.properties.principalId
        principalType: 'ServicePrincipal'
      }
    }
    
    resource deploymentScript 'Microsoft.Resources/deploymentScripts@2020-10-01' = {
      name: deploymentScriptName
      location: resourceGroup().location
      kind: 'AzurePowerShell'
      identity: {
        type: 'UserAssigned'
        userAssignedIdentities: {
          '${userAssignedIdentity.id}': {}
        }
      }
      properties: {
        azPowerShellVersion: '3.0'
        scriptContent: '''
          Invoke-RestMethod -Uri 'https://raw.githubusercontent.com/Azure/azure-docs-json-samples/master/mslearn-arm-deploymentscripts-sample/appsettings.json' -OutFile 'appsettings.json'
          $storageAccount = Get-AzStorageAccount -ResourceGroupName 'learndeploymentscript_exercise_1' | Where-Object { $_.StorageAccountName -like 'storage*' }
          $blob = Set-AzStorageBlobContent -File 'appsettings.json' -Container 'config' -Blob 'appsettings.json' -Context $storageAccount.Context
          $DeploymentScriptOutputs = @{}
          $DeploymentScriptOutputs['Uri'] = $blob.ICloudBlob.Uri
          $DeploymentScriptOutputs['StorageUri'] = $blob.ICloudBlob.StorageUri
        '''
        retentionInterval: 'P1D'
      }
      dependsOn: [
        roleAssignment
        blobContainer
      ]
    }
    
    output fileUri string = deploymentScript.properties.outputs.Uri
    
  3. Сохраните шаблон.

Запуск сценария PowerShell

Поскольку другая команда уже решила сложную задачу по созданию сценария PowerShell для копирования нескольких файлов, вы решили использовать этот сценарий в шаблоне.

Измените scriptContent в разделе properties, чтобы включить сценарий, предоставленный вашей группой партнеров.

param([string]$File)
$fileList = $File -replace '(\[|\])' -split ',' | ForEach-Object { $_.trim() }
$storageAccount = Get-AzStorageAccount -ResourceGroupName $env:ResourceGroupName -Name $env:StorageAccountName -Verbose
$count = 0
$DeploymentScriptOutputs = @{}
foreach ($fileName in $fileList) {
    Write-Host \"Copying $fileName to $env:StorageContainerName in $env:StorageAccountName.\"
    Invoke-RestMethod -Uri \"https://raw.githubusercontent.com/Azure/azure-docs-json-samples/master/mslearn-arm-deploymentscripts-sample/$fileName\" -OutFile $fileName
    $blob = Set-AzStorageBlobContent -File $fileName -Container $env:StorageContainerName -Blob $fileName -Context $storageAccount.Context
    $DeploymentScriptOutputs[$fileName] = @{}
    $DeploymentScriptOutputs[$fileName]['Uri'] = $blob.ICloudBlob.Uri
    $DeploymentScriptOutputs[$fileName]['StorageUri'] =$blob.ICloudBlob.StorageUri
    $count++
}
Write-Host \"Finished copying $count files.\"
param([string]$File)
$fileList = $File -replace '(\[|\])' -split ',' | ForEach-Object { $_.trim() }
$storageAccount = Get-AzStorageAccount -ResourceGroupName $env:ResourceGroupName -Name $env:StorageAccountName -Verbose
$count = 0
$DeploymentScriptOutputs = @{}
foreach ($fileName in $fileList) {
    Write-Host "Copying $fileName to $env:StorageContainerName in $env:StorageAccountName."
    Invoke-RestMethod -Uri "https://raw.githubusercontent.com/Azure/azure-docs-json-samples/master/mslearn-arm-deploymentscripts-sample/$fileName" -OutFile $fileName
    $blob = Set-AzStorageBlobContent -File $fileName -Container $env:StorageContainerName -Blob $fileName -Context $storageAccount.Context
    $DeploymentScriptOutputs[$fileName] = @{}
    $DeploymentScriptOutputs[$fileName]['Uri'] = $blob.ICloudBlob.Uri
    $DeploymentScriptOutputs[$fileName]['StorageUri'] = $blob.ICloudBlob.StorageUri
    $count++
}
Write-Host "Finished copying $count files."

Добавление переменной среды

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

  1. Добавьте свойство environmentVariables в раздел properties сценария развертывания.

    "environmentVariables": [
    ],
    
  2. Добавьте переменную среды для ResourceGroupName.

    "environmentVariables": [
        {
            "name": "ResourceGroupName",
            "value": "[resourceGroup().name]"
        }
    ],
    
  3. Добавьте переменную среды для StorageAccountName.

    "environmentVariables": [
        {
            "name": "ResourceGroupName",
            "value": "[resourceGroup().name]"
        },
        {
            "name": "StorageAccountName",
            "value": "[variables('storageAccountName')]"
        }
    ],
    
  4. Добавьте переменную среды для StorageContainerName.

    "environmentVariables": [
        {
            "name": "ResourceGroupName",
            "value": "[resourceGroup().name]"
        },
        {
            "name": "StorageAccountName",
            "value": "[variables('storageAccountName')]"
        },
        {
            "name": "StorageContainerName",
            "value": "[variables('storageBlobContainerName')]"
        }
    ],
    

Совет

Используйте функции шаблона для доступа к общим значениям, таким как [resourceGroup().name] и [variables()].

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

  1. Добавьте свойство environmentVariables в раздел properties сценария развертывания.

    environmentVariables: [
    ]
    
  2. Добавьте переменную среды для ResourceGroupName.

    environmentVariables: [
      {
        name: 'ResourceGroupName'
        value: resourceGroup().name
      }
    ]
    
  3. Добавьте переменную среды для StorageAccountName.

    environmentVariables: [
      {
        name: 'ResourceGroupName'
        value: resourceGroup().name
      }
      {
        name: 'StorageAccountName'
        value: storageAccountName
      }
    ]
    
  4. Добавьте переменную среды для StorageContainerName.

    environmentVariables: [
      {
        name: 'ResourceGroupName'
        value: resourceGroup().name
      }
      {
        name: 'StorageAccountName'
        value: storageAccountName
      }
      {
        name: 'StorageContainerName'
        value: storageBlobContainerName
      }
    ]
    

Добавление параметра шаблона

Чтобы упростить использование шаблона для двух команд, можно добавить в шаблон параметр, чтобы каждая команда могла указать файлы, которые требуется скопировать.

Добавьте параметр в шаблон, чтобы получить массив имен файлов.

"parameters": {
    "filesToCopy": {
        "type": "array",
        "metadata": {
            "description": "List of files to copy to application storage account."
        }
    }
},

Кроме того, можно указать значение по умолчанию, чтобы команда по-прежнему могла использовать шаблон без изменений процесса развертывания. Хотя это не обязательно, при вводе нового значения по умолчанию вы можете понять шаблон упрощения внедрения новых версий шаблонов, если они продолжают вести себя по мере их выполнения, с новыми функциональными возможностями, являясь наградой. Иными словами, на этом шаге показано, как сохранить существующее поведение при внесении изменений для поддержки работы в будущем.

Добавьте параметр в шаблон, чтобы получить массив имен файлов.

@description('List of files to copy to application storage account.')
param filesToCopy array

Кроме того, можно указать значение по умолчанию, чтобы команда по-прежнему могла использовать шаблон без изменений процесса развертывания. Хотя это не обязательно, при вводе нового значения по умолчанию вы можете понять шаблон упрощения внедрения новых версий шаблонов, если они продолжают вести себя по мере их выполнения, с новыми функциональными возможностями, являясь наградой. Иными словами, на этом шаге показано, как сохранить существующее поведение при внесении изменений для поддержки работы в будущем.

Добавление аргумента для передачи копируемых файлов

Затем можно принять только что определенный параметр и передать его в сценарий развертывания. Передача аргументов командной строки может быть непростой задачей, так как строки оцениваются на нескольких уровнях. Избегание кавычек надлежащим образом и выбор правильных кавычек для задания является обязательным для успешного достижения результата.

Совет

Используйте функции шаблона для доступа к общим функциям, таким как, например [string()], чтобы преобразовать значения одного типа в строку.

  1. Добавьте свойство arguments в сценарий развертывания. Сценарий PowerShell принимает параметр с именем File, представляющий собой строку имен файлов, которые должны поступать из параметры шаблона filesToCopy. Убедитесь, что весь аргумент заключен в кавычки, чтобы он передавался должным образом.

    Внимание

    Это свойство arguments не является допустимым. Если вы используете расширение Azure Resource Manager в Visual Studio Code, можно пометить эту строку флагом. Эту проблему можно устранить на следующих шагах.

    "arguments": "[concat( '-File '', string(parameters('filesToCopy')), ''' )]",
    

    Совет

    Заключить что-то в кавычки в JSON может быть сложно, особенно при передаче аргументов командной строки. Можно использовать переменную шаблона для представления символа, которого трудно избежать.

  2. Добавьте переменную шаблона, которая будет представлять символ одинарной кавычки.

    "variables": {
        "singleQuote": "'",
        "storageAccountName": "[concat('storage', uniqueString(resourceGroup().id))]",
        "storageBlobContainerName": "config",
        "userAssignedIdentityName": "configDeployer",
        "roleAssignmentName": "[guid(concat(resourceGroup().id, 'contributor'))]",
        "contributorRoleDefinitionId": "[resourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]",
        "deploymentScriptName": "CopyConfigScript"
    },
    
  3. Замените одинарные кавычки в свойстве arguments только что определенной переменной.

    "arguments": "[concat( '-File ', variables('singleQuote'), string(parameters('filesToCopy')), variables('singleQuote'))]",
    

Затем можно принять только что определенный параметр и передать его в сценарий развертывания. Передача аргументов командной строки может быть непростой задачей, так как строки оцениваются на нескольких уровнях. Избегание кавычек надлежащим образом и выбор правильных кавычек для задания является обязательным для успешного достижения результата.

Добавьте свойство arguments в сценарий развертывания. Сценарий PowerShell принимает параметр с именем File, представляющий собой строку имен файлов, которые должны поступать из параметры шаблона filesToCopy.

arguments: '-File \'${string(filesToCopy)}\''

Обратите внимание, что здесь используется несколько функций Bicep:

  • Интерполяция строк для объединения строк.
  • \ Для включения одного символа кавычки (') в строку используется escape-символ, так как одинарный кавычки обычно является зарезервированным символом в Bicep.
  • Мы используем функцию string() для преобразования массива filesToCopy в строку.

Обновление выходных данных шаблона

Поскольку вы изменяете сценарий развертывания для развертывания одного или нескольких файлов, необходимо обновить выходные данные шаблона, чтобы указать все необходимые сведения.

  1. Обновите outputs в шаблоне, чтобы вернуть весь объект, который будет содержать URI в каждом файле.

    $DeploymentScriptOutputs = @{}
    foreach ($fileName in $fileList) {
        Write-Host \"Copying $fileName to $env:StorageContainerName in $env:StorageAccountName.\"
        Invoke-RestMethod -Uri \"https://raw.githubusercontent.com/Azure/azure-docs-json-samples/master/mslearn-arm-deploymentscripts-sample/$fileName\" -OutFile $fileName
        $blob = Set-AzStorageBlobContent -File $fileName -Container $env:StorageContainerName -Blob $fileName -Context $storageAccount.Context
        $DeploymentScriptOutputs[$fileName] = @{}
        $DeploymentScriptOutputs[$fileName]['Uri'] = $blob.ICloudBlob.Uri
        $DeploymentScriptOutputs[$fileName]['StorageUri'] =$blob.ICloudBlob.StorageUri
        $count++
    }
    
  2. Добавьте еще одни выходные данные с именем учетной записи хранения (с произвольным идентификатором). Эти данные можно использовать позднее, чтобы убедиться в том, что сценарий развертывания работает, как ожидалось.

    $DeploymentScriptOutputs = @{}
    foreach ($fileName in $fileList) {
        Write-Host \"Copying $fileName to $env:StorageContainerName in $env:StorageAccountName.\"
        Invoke-RestMethod -Uri \"https://raw.githubusercontent.com/Azure/azure-docs-json-samples/master/mslearn-arm-deploymentscripts-sample/$fileName\" -OutFile $fileName
        $blob = Set-AzStorageBlobContent -File $fileName -Container $env:StorageContainerName -Blob $fileName -Context $storageAccount.Context
        $DeploymentScriptOutputs[$fileName] = @{}
        $DeploymentScriptOutputs[$fileName]['Uri'] = $blob.ICloudBlob.Uri
        $DeploymentScriptOutputs[$fileName]['StorageUri'] =$blob.ICloudBlob.StorageUri
        $count++
    }
    
  1. Обновите выходные данные в шаблоне, чтобы вернуть весь объект, который будет содержать URI в каждом файле.

    output fileUri object = deploymentScript.properties.outputs
    
  2. Добавьте еще одни выходные данные с именем учетной записи хранения (с произвольным идентификатором). Эти данные можно использовать позднее, чтобы убедиться в том, что сценарий развертывания работает, как ожидалось.

    output storageAccountName string = storageAccountName
    

Проверка шаблона

Шаблон должен иметь примерно такой вид:

{
    "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.1",
    "apiProfile": "",
    "parameters": {
        "filesToCopy": {
            "type": "array",
            "defaultValue": [ "appsettings.json" ],
            "metadata": {
                "description": "List of files to copy to application storage account."
            }
        }
    },
    "variables": {
        "singleQuote": "'",
        "storageAccountName": "[concat('storage', uniqueString(resourceGroup().id))]",
        "storageBlobContainerName": "config",
        "userAssignedIdentityName": "configDeployer",
        "roleAssignmentName": "[guid(concat(resourceGroup().id, 'contributor'))]",
        "contributorRoleDefinitionId": "[resourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]",
        "deploymentScriptName": "CopyConfigScript"
    },
    "functions": [],
    "resources": [
        {
            "name": "[variables('storageAccountName')]",
            "type": "Microsoft.Storage/storageAccounts",
            "apiVersion": "2023-01-01",
            "tags": {
                "displayName": "[variables('storageAccountName')]"
            },
            "location": "[resourceGroup().location]",
            "kind": "StorageV2",
            "sku": {
                "name": "Standard_LRS",
                "tier": "Standard"
            },
            "properties": {
                "allowBlobPublicAccess": true,
                "encryption": {
                    "services": {
                        "blob": {
                            "enabled": true
                        }
                    },
                    "keySource": "Microsoft.Storage"
                },
                "supportsHttpsTrafficOnly": true
            }
        },
        {
            "type": "Microsoft.Storage/storageAccounts/blobServices",
            "apiVersion": "2019-04-01",
            "name": "[concat(variables('storageAccountName'), '/default')]",
            "dependsOn": [
                "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]"
            ]
        },
        {
            "type": "Microsoft.Storage/storageAccounts/blobServices/containers",
            "apiVersion": "2019-04-01",
            "name": "[concat(variables('storageAccountName'),'/default/',variables('storageBlobContainerName'))]",
            "dependsOn": [
                "[resourceId('Microsoft.Storage/storageAccounts/blobServices', variables('storageAccountName'), 'default')]",
                "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]"
            ],
            "properties": {
                "publicAccess": "Blob"
            }
        },
        {
            "type": "Microsoft.ManagedIdentity/userAssignedIdentities",
            "apiVersion": "2018-11-30",
            "name": "[variables('userAssignedIdentityName')]",
            "location": "[resourceGroup().location]"
        },
        {
            "type": "Microsoft.Authorization/roleAssignments",
            "apiVersion": "2020-04-01-preview",
            "name": "[variables('roleAssignmentName')]",
            "dependsOn": [ "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('userAssignedIdentityName'))]" ],
            "properties": {
                "roleDefinitionId": "[variables('contributorRoleDefinitionId')]",
                "principalId": "[reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('userAssignedIdentityName')), '2015-08-31-preview').principalId]",
                "scope": "[resourceGroup().id]",
                "principalType": "ServicePrincipal"
            }
        },
        {
            "type": "Microsoft.Resources/deploymentScripts",
            "apiVersion": "2020-10-01",
            "name": "[variables('deploymentScriptName')]",
            "location": "[resourceGroup().location]",
            "kind": "AzurePowerShell",
            "dependsOn": [
                "[resourceId('Microsoft.Authorization/roleAssignments', variables('roleAssignmentName'))]",
                "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', variables('storageAccountName'), 'default', variables('storageBlobContainerName'))]"
            ],
            "identity": {
                "type": "UserAssigned",
                "userAssignedIdentities": {
                    "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities',variables('userAssignedIdentityName'))]": {}
                }
            },
            "properties": {
                "arguments": "[concat( '-File ', variables('singleQuote'), string(parameters('filesToCopy')), variables('singleQuote'))]",
                "environmentVariables": [
                    {
                        "name": "ResourceGroupName",
                        "value": "[resourceGroup().name]"
                    },
                    {
                        "name": "StorageAccountName",
                        "value": "[variables('storageAccountName')]"
                    },
                    {
                        "name": "StorageContainerName",
                        "value": "[variables('storageBlobContainerName')]"
                    }
                ],
                "azPowerShellVersion": "3.0",
                "scriptContent": "
                    param([string]$File)
                    $fileList = $File -replace '(\[|\])' -split ',' | ForEach-Object { $_.trim() }
                    $storageAccount = Get-AzStorageAccount -ResourceGroupName $env:ResourceGroupName -Name $env:StorageAccountName -Verbose
                    $count = 0
                    $DeploymentScriptOutputs = @{}
                    foreach ($fileName in $fileList) {
                        Write-Host \"Copying $fileName to $env:StorageContainerName in $env:StorageAccountName.\"
                        Invoke-RestMethod -Uri \"https://raw.githubusercontent.com/Azure/azure-docs-json-samples/master/mslearn-arm-deploymentscripts-sample/$fileName\" -OutFile $fileName
                        $blob = Set-AzStorageBlobContent -File $fileName -Container $env:StorageContainerName -Blob $fileName -Context $storageAccount.Context
                        $DeploymentScriptOutputs[$fileName] = @{}
                        $DeploymentScriptOutputs[$fileName]['Uri'] = $blob.ICloudBlob.Uri
                        $DeploymentScriptOutputs[$fileName]['StorageUri'] =$blob.ICloudBlob.StorageUri
                        $count++
                    }
                    Write-Host \"Finished copying $count files.\"                    
                ",
                "retentionInterval": "P1D"
            }
        }
    ],
    "outputs": {
        "fileUri": {
            "type": "object",
            "value": "[reference(variables('deploymentScriptName')).outputs]"
        },
        "storageAccountName": {
            "type": "string",
            "value": "[variables('storageAccountName')]"
        }
    }
}
@description('List of files to copy to application storage account.')
param filesToCopy array = [
  'appsettings.json'
]

var storageAccountName = 'storage${uniqueString(resourceGroup().id)}'
var storageBlobContainerName = 'config'
var userAssignedIdentityName = 'configDeployer'
var roleAssignmentName = guid(resourceGroup().id, 'contributor')
var contributorRoleDefinitionId = resourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')
var deploymentScriptName = 'CopyConfigScript'

resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = {
  name: storageAccountName
  tags: {
    displayName: storageAccountName
  }
  location: resourceGroup().location
  kind: 'StorageV2'
  sku: {
    name: 'Standard_LRS'
    tier: 'Standard'
  }
  properties: {
    allowBlobPublicAccess: true
    encryption: {
      services: {
        blob: {
          enabled: true
        }
      }
      keySource: 'Microsoft.Storage'
    }
    supportsHttpsTrafficOnly: true
  }

  resource blobService 'blobServices' existing = {
    name: 'default'
  }
}

resource blobContainer 'Microsoft.Storage/storageAccounts/blobServices/containers@2019-04-01' = {
  parent: storageAccount::blobService
  name: storageBlobContainerName
  properties: {
    publicAccess: 'Blob'
  }
}

resource userAssignedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = {
  name: userAssignedIdentityName
  location: resourceGroup().location
}

resource roleAssignment 'Microsoft.Authorization/roleAssignments@2020-04-01-preview' = {
  name: roleAssignmentName
  properties: {
    roleDefinitionId: contributorRoleDefinitionId
    principalId: userAssignedIdentity.properties.principalId
    principalType: 'ServicePrincipal'
  }
}

resource deploymentScript 'Microsoft.Resources/deploymentScripts@2020-10-01' = {
  name: deploymentScriptName
  location: resourceGroup().location
  kind: 'AzurePowerShell'
  identity: {
    type: 'UserAssigned'
    userAssignedIdentities: {
      '${userAssignedIdentity.id}': {}
    }
  }
  properties: {
    arguments: '-File \'${string(filesToCopy)}\''
    environmentVariables: [
      {
        name: 'ResourceGroupName'
        value: resourceGroup().name
      }
      {
        name: 'StorageAccountName'
        value: storageAccountName
      }
      {
        name: 'StorageContainerName'
        value: storageBlobContainerName
      }
    ]
    azPowerShellVersion: '3.0'
    scriptContent: '''
      param([string]$File)
      $fileList = $File -replace '(\[|\])' -split ',' | ForEach-Object { $_.trim() }
      $storageAccount = Get-AzStorageAccount -ResourceGroupName $env:ResourceGroupName -Name $env:StorageAccountName -Verbose
      $count = 0
      $DeploymentScriptOutputs = @{}
      foreach ($fileName in $fileList) {
          Write-Host "Copying $fileName to $env:StorageContainerName in $env:StorageAccountName."
          Invoke-RestMethod -Uri "https://raw.githubusercontent.com/Azure/azure-docs-json-samples/master/mslearn-arm-deploymentscripts-sample/$fileName" -OutFile $fileName
          $blob = Set-AzStorageBlobContent -File $fileName -Container $env:StorageContainerName -Blob $fileName -Context $storageAccount.Context
          $DeploymentScriptOutputs[$fileName] = @{}
          $DeploymentScriptOutputs[$fileName]['Uri'] = $blob.ICloudBlob.Uri
          $DeploymentScriptOutputs[$fileName]['StorageUri'] = $blob.ICloudBlob.StorageUri
          $count++
      }
      Write-Host "Finished copying $count files."
    '''
    retentionInterval: 'P1D'
  }
  dependsOn: [
    roleAssignment
    blobContainer
  ]
}

output fileUri object = deploymentScript.properties.outputs
output storageAccountName string = storageAccountName

Если это не так, скопируйте пример или настройте шаблон в соответствии с примером.

Создание файла параметров

После создания набора шаблонов можно проверить новый сценарий развертывания, используя файл параметров, где заданы новые файлы.

  1. Либо создайте файл azuredeploy.parameters.json вручную, либо используйте для этого расширение VS Code.

  2. Измените файл, чтобы указать два filesToCopy:

    {
        "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
        "contentVersion": "1.0.0.0",
        "parameters": {
            "filesToCopy": {
                "value": [
                    "swagger.Staging.json",
                    "appsettings.Staging.json"
                ]
            }
        }
    }
    
  1. Создайте файл azuredeploy.parameters.JSON.

  2. Измените файл, чтобы указать два filesToCopy:

    {
        "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
        "contentVersion": "1.0.0.0",
        "parameters": {
            "filesToCopy": {
                "value": [
                    "swagger.Staging.json",
                    "appsettings.Staging.json"
                ]
            }
        }
    }
    

Развертывание шаблона

Создайте группу ресурсов для упражнения

Необходимо создать группу ресурсов для хранения ресурсов, которые будут созданы в рамках этого упражнения. При использовании новой группы ресурсов выполнять очистку после упражнения будет гораздо проще.

Из терминала в Visual Studio Code выполните следующую команду, чтобы создать группу ресурсов для этого упражнения.

resourceGroupName="learndeploymentscript_exercise_2"
az group create --location eastus --name $resourceGroupName
$resourceGroupName = 'learndeploymentscript_exercise_2'
New-AzResourceGroup -Location eastus -Name $resourceGroupName

Развертывание шаблона в Azure

Разверните шаблон с помощью команд Azure CLI в терминале Visual Studio Code.

templateFile="azuredeploy.json"
templateParameterFile="azuredeploy.parameters.json"
today=$(date +"%d-%b-%Y")
deploymentName="deploymentscript-"$today

az deployment group create \
    --resource-group $resourceGroupName \
    --name $deploymentName \
    --template-file $templateFile \
    --parameters $templateParameterFile

Развертывание шаблона в Azure

Разверните шаблон, выполнив в терминале следующие команды Azure PowerShell.

$templateFile = 'azuredeploy.json'
$templateParameterFile = 'azuredeploy.parameters.json'
$today = Get-Date -Format 'MM-dd-yyyy'
$deploymentName = "deploymentscript-$today"

New-AzResourceGroupDeployment `
    -ResourceGroupName $resourceGroupName `
    -Name $deploymentName `
    -TemplateFile $templateFile `
    -TemplateParameterFile $templateParameterFile

Развертывание шаблона в Azure

Разверните шаблон с помощью команд Azure CLI в терминале Visual Studio Code.

templateFile="main.bicep"
templateParameterFile="azuredeploy.parameters.json"
today=$(date +"%d-%b-%Y")
deploymentName="deploymentscript-"$today

az deployment group create \
    --resource-group $resourceGroupName \
    --name $deploymentName \
    --template-file $templateFile \
    --parameters $templateParameterFile

Развертывание шаблона в Azure

Разверните шаблон, выполнив в терминале следующие команды Azure PowerShell.

$templateFile = 'main.bicep'
$templateParameterFile = 'azuredeploy.parameters.json'
$today = Get-Date -Format 'MM-dd-yyyy'
$deploymentName = "deploymentscript-$today"

New-AzResourceGroupDeployment `
    -ResourceGroupName $resourceGroupName `
    -Name $deploymentName `
    -TemplateFile $templateFile `
    -TemplateParameterFile $templateParameterFile

Проверка результата для шаблона

По завершении развертывания нужно убедиться в том, что оба файла были скопированы в учетную запись хранения, создав список содержимого контейнера BLOB-объектов.

  1. Перечислите содержимое контейнера BLOB-объектов.

    storageAccountName=$(az deployment group show --resource-group $resourceGroupName --name $deploymentName --query 'properties.outputs.storageAccountName.value' --output tsv)
    az storage blob list --account-name $storageAccountName --container-name config --query '[].name'
    

    Команда возвращает следующий код:

    [
      "swagger.Staging.json",
      "appsettings.Staging.json"
    ]
    
  2. Кроме того, можно просмотреть журналы (и другие сведения о развертывании) на портале Azure или использовать для этого следующую команду.

    az deployment-scripts show-log --resource-group $resourceGroupName --name CopyConfigScript
    
  1. Перечислите содержимое контейнера BLOB-объектов.

    $storageAccountName = (Get-AzResourceGroupDeployment -ResourceGroupName $resourceGroupName -Name $deploymentName).Outputs.storageAccountName.Value
    $storageAccount = Get-AzStorageAccount -ResourceGroupName $resourceGroupName
    Get-AzStorageBlob -Context $storageAccount.Context -Container config |
        Select-Object Name
    

    Команда возвращает следующий код:

    Name
    ----
    swagger.Staging.json
    appsettings.Staging.json
    
  2. Кроме того, можно просмотреть журналы (и другие сведения о развертывании) на портале Azure или использовать для этого следующую команду.

    Get-AzDeploymentScriptLog -ResourceGroupName $resourceGroupName -Name CopyConfigScript
    

Очистка группы ресурсов

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

az group delete --name $resourceGroupName
Remove-AzResourceGroup -Name $resourceGroupName