共用方式為


快速入門:使用自備儲存體來建立和發佈 Azure 受控應用程式定義

本快速入門簡要介紹如何針對 Azure 受控應用程式自備儲存體 (BYOS)。 您會在服務類別目錄中建立和發佈受控應用程式定義,以供組織成員使用。 當您使用自己的儲存體帳戶時,受控應用程式定義可能會超過服務類別目錄設定的 120 MB 大小限制。

若要將受控應用程式定義發佈至您的服務類別目錄,請執行下列工作:

  • 建立 Azure Resource Manager 範本 (ARM 範本),該範本會定義要由受控應用程式部署的 Azure 資源。
  • 部署受控應用程式時,定義入口網站的使用者介面元素。
  • 建立包含必要 JSON 檔案的 .zip 套件。
  • 建立一個儲存體帳戶來儲存受控應用程式定義。
  • 將受控應用程式定義部署至您自己的儲存體帳戶,使其可在服務類別目錄中使用。

如果您的受控應用程式定義小於 120 MB,而且您不想使用自己的儲存體帳戶,請移至快速入門:建立及發佈 Azure 受控應用程式定義

您可以使用 Bicep 來開發受控應用程式定義,但必須先將它轉換成 ARM 範本 JSON,才能在 Azure 中發佈定義。 如需詳細資訊,請移至 快速入門:使用 Bicep 建立和發佈 Azure 受控應用程式定義

您也可以使用 Bicep 從服務類別目錄部署受控應用程式定義。 如需詳細資訊,請移至 快速入門:使用 Bicep 部署 Azure 受控應用程式定義

必要條件

若要完成此快速入門,您需要下列項目:

建立 ARM 範本

每個受控應用程式定義都包含名為 mainTemplate.json 的檔案。 此範本會定義要部署的 Azure 資源,而且與一般 ARM 範本不同。

開啟 Visual Studio Code,建立具有區分大小寫名稱 mainTemplate.json 的檔案,並加以儲存。

新增下列 JSON 並儲存檔案。 它會定義受控應用程式的資源,以部署 App Service、App Service 方案和儲存體帳戶。

{
  "$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 檔案會產生入口網站使用者介面。 您可以使用下拉式清單和文字輸入框等控制項元素,定義使用者為每個參數提供輸入的方式。

在此範例中,使用者介面會提示您輸入 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 個字元,且只有小寫字母和數字。 在命令中,以您唯一的儲存體帳戶名稱取代預留位置 <pkgstorageaccountname>,包括角括弧 (<>)。

New-AzResourceGroup -Name packageStorageGroup -Location westus

$pkgstorageparms = @{
  ResourceGroupName = "packageStorageGroup"
  Name = "<pkgstorageaccountname>"
  Location = "westus"
  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 中的存取層級而定,您可能需要管理員指派的其他權限。 如需詳細資訊,請參閱指派 Azure 角色以存取 Blob 資料

將該角色新增至儲存體帳戶之後,需要幾分鐘的時間才會在 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

使用下列命令,將封裝檔案的 URI 儲存在名為 packageuri 的變數中。 當您部署受控應用程式定義時,將會使用變數的值。

$packageuri=(Get-AzStorageBlob -Container appcontainer -Blob app.zip -Context $pkgstoragecontext).ICloudBlob.StorageUri.PrimaryUri.AbsoluteUri

以您自備的儲存體存放受控應用程式定義

您可以將受控應用程式定義儲存在您自己的儲存體帳戶中,以管理其位置和存取權而符合自身組織的法規需求。 使用您自己的儲存體帳戶,可讓您擁有超過服務類別目錄受控應用程式定義的 120 MB 限制的應用程式。

注意

「自備儲存體」僅支援受控應用程式定義的 ARM 範本或 REST API 部署。

建立儲存體帳戶

建立受控應用程式定義的儲存體帳戶。 儲存體帳戶名稱在整個 Azure 中必須是全域唯一的,長度必須是 3-24 個字元,且只有小寫字母和數字。

此範例會建立新的資源群組,名為 byosDefinitionStorageGroup。 在命令中,以您唯一的儲存體帳戶名稱取代預留位置 <byosaccountname>,包括角括弧 (<>)。

New-AzResourceGroup -Name byosDefinitionStorageGroup -Location westus

$byostorageparms = @{
  ResourceGroupName = "byosDefinitionStorageGroup"
  Name = "<byosaccountname>"
  Location = "westus"
  SkuName = "Standard_LRS"
  Kind = "StorageV2"
  MinimumTlsVersion = "TLS1_2"
  AllowBlobPublicAccess = $true
  AllowSharedKeyAccess = $true
}

$byosstorageaccount = New-AzStorageAccount @byostorageparms

建立儲存體帳戶之後,請將角色指派儲存體 Blob 資料參與者新增至儲存體帳戶範圍。 指派對 Microsoft Entra 使用者帳戶的存取權限。 您需要存取程式稍後的步驟。

將該角色新增至儲存體帳戶之後,需要幾分鐘的時間才會在 Azure 中變成作用中。 然後,您可以建立建立容器並上傳檔案所需的內容。

$byosstoragecontext = New-AzStorageContext -StorageAccountName $byosstorageaccount.StorageAccountName -UseConnectedAccount

使用下列命令,將儲存體帳戶的資源識別碼儲存在名為 byosstorageid 的變數中。 當您部署受控應用程式定義時,將會使用變數的值。

$byosstorageid = (Get-AzStorageAccount -ResourceGroupName $byosstorageaccount.ResourceGroupName -Name $byosstorageaccount.StorageAccountName).Id

設定儲存體帳戶的角色指派

將您的受控應用程式定義部署至儲存體帳戶之前,需先將參與者角色指派給儲存體帳戶範圍的設備資源提供者使用者。 此指派可讓身分識別將定義檔案寫入至儲存體帳戶的容器。

您可以使用變數來設定角色指派。 此範例會使用您在上一個步驟中建立的 $byosstorageid 變數,並建立 $arpid 變數。

$arpid = (Get-AzADServicePrincipal -SearchString "Appliance Resource Provider").Id

New-AzRoleAssignment -ObjectId $arpid -RoleDefinitionName Contributor -Scope $byosstorageid

設備資源提供者是 Microsoft Entra 租用戶中的服務主體。 您可以從 Azure 入口網站前往 [Microsoft Entra ID]>[企業應用程式],並將搜尋篩選變更為 [Microsoft 應用程式],以驗證其註冊狀態。 搜尋設備資源提供者。 如果找不到,請註冊Microsoft.Solutions資源提供者。

取得群組識別碼和角色定義識別碼

下一個步驟是選取要代表客戶管理資源的使用者、安全性群組或應用程式。 此身分識別會根據指派的角色,取得受控資源群組的權限。 角色可以是任何內建的 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('Resource ID for the bring your own storage account where the definition is stored.')
param definitionStorageResourceID 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 BYOS managed application'
var definitionDescription = 'Sample BYOS 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
    storageAccountId: definitionStorageResourceID
    authorizations: [
      {
        principalId: principalId
        roleDefinitionId: roleId
      }
    ]
  }
}

如需範本屬性的詳細資訊,請參閱 Microsoft.Solutions/applicationDefinitions

受控資源群組上的 lockLevel 可以避免客戶在此資源群組上執行非預期的作業。 目前唯一支援的鎖定等級是 ReadOnlyReadOnly 規定客戶只能讀取受控資源群組中存在的資源。 被授與受控資源群組存取權的發行者身分識別不受鎖定等級的限制。

建立參數檔案

受控應用程式定義的部署範本要求為多個參數輸入值。 部署命令會提示您輸入值,您也可以為值建立參數檔案。 在此範例中,我們使用參數檔案將參數值傳遞至部署命令。

在 Visual Studio Code 中,建立名為 deployDefinition-parameters.bicepparam 的新檔案並加以儲存。

將下列內容新增至參數檔案並加以儲存。 將包含角括弧在內的 <placeholder values> (即 <>) 取代為您的訂用帳戶識別碼。

using './deployDefinition.bicep'

param managedApplicationDefinitionName = 'sampleByosManagedApplication'
param definitionStorageResourceID = '<placeholder for you BYOS storage account ID>'
param packageFileUri = '<placeholder for the packageFileUri>'
param principalId = '<placeholder for principalid value>'
param roleId = '<placeholder for roleid value>'

下表描述受控應用程式定義的參數值。

參數
managedApplicationDefinitionName 受控應用程式定義的名稱。 在這個範例中,請使用 sampleByosManagedApplication
definitionStorageResourceID 儲存定義之儲存體帳戶的資源識別碼。 使用 byosstorageid 變數的值。
packageFileUri 輸入 .zip 套件檔案的 URI。 使用 packageuri 變數的值。 格式為 https://yourStorageAccountName.blob.core.windows.net/appcontainer/app.zip
principalId 需要管理受控資源群組中資源之許可權的發行者主體識別碼。 使用 principalid 變數的值。
roleId 受控資源群組許可權的角色識別碼。 例如擁有者、參與者或讀者。 使用 roleid 變數的值。

若要取得變數值:

  • Azure PowerShell:在 PowerShell 中,輸入 $variableName 以顯示變數的值。
  • Azure CLI:在 Bash 中,輸入 echo $variableName 以顯示變數的值。

部署定義

在您部署受控應用程式的定義後,定義就會在您的服務類別目錄中變成可用狀態。 此程式不會部署受控應用程式的資源。

建立名為 byosAppDefinitionGroup 的資源群組,並且將受控應用程式定義部署至儲存體帳戶。

New-AzResourceGroup -Name byosAppDefinitionGroup -Location westus

$deployparms = @{
  ResourceGroupName = "byosAppDefinitionGroup"
  TemplateFile = "deployDefinition.bicep"
  TemplateParameterFile = "deployDefinition-parameters.bicepparam"
  Name = "deployDefinition"
}

New-AzResourceGroupDeployment @deployparms

確認定義檔案儲存體

在部署期間,範本的 storageAccountId 屬性會使用儲存體帳戶的資源識別碼,並使用區分大小寫的名稱 applicationdefinitions 建立新的容器。 您在部署期間所指定 .zip 套件中的檔案會儲存在新容器中。

您可以使用下列命令來確認受控應用程式定義檔案已儲存在儲存體帳戶的容器中。 在命令中,以您唯一的儲存體帳戶名稱取代預留位置 <byosaccountname>,包括角括弧 (<>)。

Get-AzStorageContainer -Name applicationdefinitions -Context $byosstoragecontext |
Get-AzStorageBlob | Select-Object -Property Name | Format-List

注意

若要提升安全性,您可以建立受控應用程式定義,並將其儲存在已啟用加密的 Azure 儲存體帳戶 Blob 中。 定義內容會透過儲存體帳戶的加密選項進行加密。 只有具備檔案權限的使用者,才能在服務類別目錄中存取該定義。

更新記憶體帳戶安全性

成功部署之後,若要改善記憶體帳戶的安全性,請停用共用存取密鑰屬性。 建立記憶體帳戶時,您新增了 儲存體 Blob 數據參與者的角色指派,讓您不需要使用記憶體密鑰即可存取容器和 Blob。

若要檢閱及更新記憶體帳戶的共用存取金鑰設定,請使用下列命令:

(Get-AzStorageAccount -ResourceGroupName $byosstorageaccount.ResourceGroupName -Name $byosstorageaccount.StorageAccountName).AllowSharedKeyAccess

Set-AzStorageAccount -ResourceGroupName $byosstorageaccount.ResourceGroupName -Name $byosstorageaccount.StorageAccountName -AllowSharedKeyAccess $false

確定使用者可以存取您的定義

您可以存取受控應用程式定義,但您想確保您組織中的其他使用者可以存取它。 至少在定義上將讀者角色授與給他們。 他們可能已從訂用帳戶或資源群組繼承此層級的存取權。 若要查看可存取定義和新增使用者或群組的人員,請參閱使用 Azure 入口網站指派 Azure 角色

清除資源

如果您要部署定義,請繼續閱讀與文章相關的後續步驟一節,以瞭解如何部署定義。

如果您已完成受控應用程式定義,您可以刪除自己建立的名為 packageStorageGroupbyosDefinitionStorageGroupbyosAppDefinitionGroup 的資源群組。

命令會提示您確認要移除資源群組。

Remove-AzResourceGroup -Name packageStorageGroup

Remove-AzResourceGroup -Name byosDefinitionStorageGroup

Remove-AzResourceGroup -Name byosAppDefinitionGroup

下一步

您發行了受控應用程式定義。 現在,深入了解如何部署該定義的執行個體。