Share via


빠른 시작: BYOS(Bring Your Own Storage)를 사용하여 Azure 관리형 애플리케이션 정의 만들기 및 게시

이 빠른 시작에서는 Azure 관리형 애플리케이션에 대해 BYOS(Bring Your Own Storage)를 사용하는 방법을 소개합니다. 조직의 멤버에 대한 서비스 카탈로그에서 관리형 애플리케이션 정의를 만들고 게시합니다. 고유한 스토리지 계정을 사용하는 경우 관리형 애플리케이션 정의가 서비스 카탈로그의 120MB 한도를 초과할 수 있습니다.

관리형 애플리케이션 정의를 서비스 카탈로그에 게시하려면 다음 작업을 수행합니다.

  • 관리형 애플리케이션을 통해 배포되는 Azure 리소스를 정의하는 ARM 템플릿(Azure Resource Manager 템플릿)을 만듭니다.
  • 관리 되는 애플리케이션을 배포할 때 포털에 대한 사용자 인터페이스 요소를 정의합니다.
  • 필요한 JSON 파일이 포함된 .zip 패키지를 만듭니다.
  • 관리형 애플리케이션 정의를 저장하는 스토리지 계정을 만듭니다.
  • 서비스 카탈로그에서 사용할 수 있도록 관리형 애플리케이션 정의를 고유한 스토리지 계정에 배포합니다.

관리형 애플리케이션 정의가 120MB 미만이고 고유한 스토리지 계정을 사용하지 않으려는 경우 빠른 시작: Azure 관리형 애플리케이션 정의 만들기 및 게시로 이동합니다.

Bicep을 사용하여 관리형 애플리케이션 정의를 개발할 수 있지만 Azure에 정의를 게시하려면 먼저 ARM 템플릿 JSON으로 변환해야 합니다. 자세한 내용은 빠른 시작: 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-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 파일의 루트 수준에 있어야 합니다. 파일이 폴더에 있으면 관리형 애플리케이션 정의를 만들 때 필요한 파일이 없다는 오류가 표시됩니다.

관리형 애플리케이션의 정의를 배포할 때 사용할 수 있도록 Azure Storage 계정에 app.zip을 업로드합니다. 스토리지 계정 이름은 Azure에서 전역적으로 고유해야 하며 길이는 소문자와 숫자만 포함된 3-24자여야 합니다. 명령에서 대괄호(<>)를 포함한 자리 표시자 <demostorageaccount>를 고유한 스토리지 계정 이름으로 바꿉니다.

New-AzResourceGroup -Name packageStorageGroup -Location westus3

$storageAccount = New-AzStorageAccount `
  -ResourceGroupName packageStorageGroup `
  -Name "<demostorageaccount>" `
  -Location westus3 `
  -SkuName Standard_LRS `
  -Kind StorageV2

$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

관리형 애플리케이션 정의에 대한 사용자 고유의 스토리지 가져오기

조직의 규정 요구 사항에 따라 위치 및 액세스를 관리할 수 있도록 관리형 애플리케이션 정의를 고유한 스토리지 계정에 저장합니다. 고유한 스토리지 계정을 사용하면 서비스 카탈로그의 관리형 애플리케이션 정의에 대한 120MB 제한을 초과하는 애플리케이션을 사용할 수 있습니다.

참고 항목

사용자 고유의 스토리지 가져오기는 ARM 템플릿 또는 관리형 애플리케이션 정의의 REST API 배포에서만 지원됩니다.

스토리지 계정 만들기

관리형 애플리케이션 정의에 대한 스토리지 계정을 만듭니다. 스토리지 계정 이름은 Azure에서 전역적으로 고유해야 하며 길이는 소문자와 숫자만 포함된 3-24자여야 합니다.

이 예제는 새 리소스 그룹 byosDefinitionStorageGroup를 만듭니다. 명령에서 대괄호(<>)를 포함한 자리 표시자 <definitionstorage>를 고유한 스토리지 계정 이름으로 바꿉니다.

New-AzResourceGroup -Name byosDefinitionStorageGroup -Location westus3

New-AzStorageAccount `
  -ResourceGroupName byosDefinitionStorageGroup `
  -Name "<definitionstorage>" `
  -Location westus3 `
  -SkuName Standard_LRS `
  -Kind StorageV2

다음 명령을 사용하여 스토리지 계정의 리소스 ID를 storageid라는 변수에 저장합니다. 관리형 애플리케이션 정의를 배포할 때 변수 값을 사용합니다.

$storageid = (Get-AzStorageAccount -ResourceGroupName byosDefinitionStorageGroup -Name <definitionstorage>).Id

스토리지 계정에 대한 역할 할당 설정

관리형 애플리케이션 정의를 스토리지 계정에 배포하려면 먼저 스토리지 계정 범위에서 어플라이언스 리소스 공급자 사용자에게 기여자 역할을 할당합니다. 이 할당을 통해 ID는 스토리지 계정의 컨테이너에 정의 파일을 쓸 수 있습니다.

변수를 사용하여 역할 할당을 설정할 수 있습니다. 이 예제에서는 이전 단계에서 만든 $storageid를 사용하고 $arpid 변수를 만듭니다.

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

New-AzRoleAssignment -ObjectId $arpid `
-RoleDefinitionName Contributor `
-Scope $storageid

Appliance Resource Provider는 Microsoft Entra 테넌트의 서비스 주체입니다. Azure Portal에서 Microsoft Entra ID>엔터프라이즈 애플리케이션으로 이동하여 검색 필터를 Microsoft 애플리케이션으로 변경하여 등록되었는지 확인할 수 있습니다. 어플라이언스 리소스 공급자를 검색합니다. 찾을 수 없으면 Microsoft.Solutions 리소스 공급자를 등록합니다.

그룹 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

정의 배포 템플릿 만들기

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은 고객이 이 리소스 그룹에 대해 바람직하지 않은 작업을 수행하지 못하도록 합니다. 현재 ReadOnly만 지원되는 잠금 수준입니다. ReadOnly는 고객이 관리형 리소스 그룹에 있는 리소스만 읽을 수 있도록 지정합니다. 관리형 리소스 그룹에 대한 액세스 권한이 부여된 게시자 ID는 잠금 수준에서 제외됩니다.

매개 변수 파일 만들기

관리형 애플리케이션 정의의 배포 템플릿에는 여러 매개 변수에 대한 입력이 필요합니다. 배포 명령은 값을 묻는 메시지를 표시하거나 값에 대한 매개 변수 파일을 만들 수 있습니다. 이 예제에서는 매개 변수 파일을 사용하여 매개 변수 값을 배포 명령에 전달합니다.

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": "<placeholder for managed application name>"
    },
    "definitionStorageResourceID": {
      "value": "<placeholder for you storage account ID>"
    },
    "packageFileUri": {
      "value": "<placeholder for the packageFileUri>"
    },
    "principalId": {
      "value": "<placeholder for principalid value>"
    },
    "roleId": {
      "value": "<placeholder for roleid value>"
    }
  }
}

다음 표에서는 관리형 애플리케이션 정의에 대한 매개 변수 값을 설명합니다.

매개 변수
managedApplicationDefinitionName 관리형 애플리케이션 정의의 이름입니다. 이 예제에서는 sampleByosManagedApplication을 사용합니다.
definitionStorageResourceID 정의가 저장되는 스토리지 계정의 리소스 ID입니다. storageid 변수의 값을 사용합니다.
packageFileUri .zip 패키지 파일의 URI를 입력합니다. packageuri 변수의 값을 사용합니다. 형식은 https://yourStorageAccountName.blob.core.windows.net/appcontainer/app.zip입니다.
principalId 관리형 리소스 그룹의 리소스를 관리할 수 있는 권한이 필요한 게시자 보안 주체 ID입니다. principalid 변수의 값을 사용합니다.
roleId 관리형 리소스 그룹에 대한 권한의 역할 ID입니다. 예를 들어 소유자, 기여자, 읽기 권한자입니다. roleid 변수의 값을 사용합니다.

변수 값을 가져오려면:

  • Azure PowerShell: PowerShell에서 $variableName을 입력하여 변수 값을 표시합니다.
  • Azure CLI: Bash에서 echo $variableName을 입력하여 변수 값을 표시합니다.

정의 배포

관리형 애플리케이션의 정의를 배포하면 서비스 카탈로그에서 사용할 수 있게 됩니다. 이 프로세스는 관리형 애플리케이션의 리소스를 배포하지 않습니다.

byosAppDefinitionGroup이라는 리소스 그룹을 만들고 관리형 애플리케이션 정의를 스토리지 계정에 배포합니다.

New-AzResourceGroup -Name byosAppDefinitionGroup -Location westus3

New-AzResourceGroupDeployment `
  -ResourceGroupName byosAppDefinitionGroup `
  -TemplateFile deployDefinition.bicep `
  -TemplateParameterFile deployDefinition.parameters.json

정의 파일 스토리지 확인

배포 중에 템플릿의 storageAccountId 속성은 스토리지 계정의 리소스 ID를 사용하고 대/소문자를 구분하는 이름이 applicationdefinitions인 새 컨테이너를 만듭니다. 배포 중에 지정한 .zip 패키지의 파일은 새 컨테이너에 저장됩니다.

다음 명령을 사용하여 관리되는 애플리케이션 정의 파일이 스토리지 계정의 컨테이너에 저장되었는지 확인할 수 있습니다. 명령에서 대괄호(<>)를 포함한 자리 표시자 <definitionstorage>를 고유한 스토리지 계정 이름으로 바꿉니다.

Get-AzStorageAccount -ResourceGroupName byosDefinitionStorageGroup -Name <definitionstorage> |
Get-AzStorageContainer -Name applicationdefinitions |
Get-AzStorageBlob | Select-Object -Property Name | Format-List

참고 항목

보안 강화를 위해 관리형 애플리케이션 정의를 만들고 암호화를 사용하도록 설정된 Azure Storage 계정 Blob에 저장할 수 있습니다. 정의 콘텐츠는 스토리지 계정의 암호화 옵션을 통해 암호화됩니다. 파일에 대한 권한이 있는 사용자만 서비스 카탈로그의 정의에 액세스할 수 있습니다.

사용자가 정의에 액세스할 수 있는지 확인

사용자가 관리되는 애플리케이션 정의에 액세스할 수 있지만 조직의 다른 사용자도 액세스할 수 있는 것이 좋습니다. 정의에서 최소한 읽기 역할을 부여합니다. 구독 또는 리소스 그룹에서 이 수준의 액세스를 상속받을 수 있습니다. 정의에 대한 액세스 권한이 있는 사용자를 확인하고 사용자 또는 그룹을 추가하려면 Azure Portal을 사용하여 Azure 역할 할당으로 이동합니다.

리소스 정리

정의를 배포하려는 경우 문서를 연결하여 정의를 배포하는 다음 단계 섹션을 계속 진행합니다.

관리형 애플리케이션 정의를 완료한 경우 packageStorageGroup, byosDefinitionStorageGroupbyosAppDefinitionGroup이라는 리소스 그룹을 삭제할 수 있습니다.

이 명령은 리소스 그룹을 제거할 것인지 확인하라는 메시지를 표시합니다.

Remove-AzResourceGroup -Name packageStorageGroup

Remove-AzResourceGroup -Name byosAppDefinitionGroup

Remove-AzResourceGroup -Name byosDefinitionStorageGroup

다음 단계

관리되는 애플리케이션 정의를 게시했습니다. 이제 해당 정의의 인스턴스를 배포하는 방법을 알아보세요.