연습 - 리소스 변환 및 마이그레이션

완료됨

중요

이 연습을 수행하려면 사용자의 Azure 구독이 필요하며 요금이 발생할 수 있습니다. Azure 구독이 아직 없는 경우 시작하기 전에 체험 계정을 만듭니다.

장난감 회사에서 인기 있는 장난감 트럭을 만든 경쟁 업체를 인수했습니다. 장난감은 Azure에서 호스트되는 가상 머신에 연결하여 펌웨어 업데이트를 수신합니다. 가상 머신의 모든 리소스는 Azure Portal을 사용하여 수동으로 생성되었습니다. 이 단원에서는 리소스를 Bicep 파일로 마이그레이션하는 프로세스를 시작합니다.

프로세스 중에 다음 작업을 수행합니다.

  • Azure Portal을 사용하여 새 가상 머신을 배포합니다.
  • 가상 머신 리소스를 JSON 템플릿으로 내보냅니다.
  • JSON 템플릿을 Bicep으로 디컴파일합니다.
  • 새 Bicep 파일을 만들고 디컴파일된 템플릿에서 리소스를 이동합니다.

이 연습에서는 Visual Studio Code용 Bicep 확장을 사용합니다. Visual Studio Code에서 해당 확장을 설치해야 합니다.

Azure Portal을 사용하여 가상 머신 만들기

예제 시나리오의 상황을 시뮬레이션하기 위해 먼저 Azure Portal을 사용하여 가상 머신을 배포합니다.

  1. Azure Portal에 로그인합니다.

  2. Azure 홈페이지의 Azure 서비스에서 리소스 만들기를 선택합니다.

    Azure Portal을 보여 주는 스크린샷 리소스 만들기 옵션이 강조 표시되어 있습니다.

    Azure Marketplace는 리소스 만들기 창에 표시됩니다.

  3. Ubuntu Server 20.04 LTS에서 만들기를 선택합니다.

    Azure Marketplace를 보여 주는 스크린샷 Ubuntu Server 20.04 LTS 아래의 만들기 링크가 강조 표시되어 있습니다.

    Important

    Ubuntu Server 20.04 LTS가 표시되지 않는 경우 Azure Marketplace에서 Ubuntu Server 20.04 LTS로 직접 이동합니다.

  4. 기본 탭에서 각 설정에 다음 값을 입력합니다. 다른 모든 설정에 기본값을 사용합니다.

    설정
    프로젝트 세부 정보
    Resource group 새로 만들기를 선택하고 ToyTruck을 입력합니다.
    인스턴스 세부 정보
    가상 머신 이름 ToyTruckServer
    지역 (미국) 미국 서부 3
    가용성 옵션 인프라 중복 필요 없음
    이미지 Ubuntu Server 20.04 LTS - x64 Gen2
    크기 Standard_D2s_v3
    관리자 계정
    인증 유형 암호
    사용자 이름 toytruckadmin
    암호 암호를 입력합니다.
    인바운드 포트 규칙
    공용 인바운드 포트 없음
  5. 관리 탭에서 자동 종료 사용이 선택되지 않았는지 확인합니다.

  6. 검토 + 만들기를 선택합니다. Azure는 설정의 유효성을 검사합니다. 이미지 요구 사항에 따라 추가 정보를 입력하거나 선택해야 할 수 있습니다.

  7. 만들기를 선택하여 VM을 배포하고 만듭니다.

    Azure Portal에서는 진행 중인 배포를 보여 줍니다.

  8. 배포가 완료되면 리소스 그룹 이름을 선택하여 리소스 그룹을 엽니다.

    배포를 보여 주는 Azure Portal 스크린샷 리소스 그룹 이름이 강조 표시되어 있습니다.

    이제 리소스 그룹에 가상 머신과 해당 종속성이 포함됩니다.

    리소스 그룹을 보여주는 Azure Portal 스크린샷.

리소스 그룹 콘텐츠를 JSON 템플릿으로 내보내기

  1. 왼쪽 메뉴의 Automation에서 템플릿 내보내기를 선택합니다.

    리소스 그룹 창의 템플릿 내보내기 메뉴 항목을 보여주는 Azure Portal의 스크린샷.

    JSON 템플릿이 생성됩니다. 데이터가 여기에 표시되는 데 1-2분 정도 걸릴 수 있습니다.

  2. 다운로드 단추를 선택합니다.

    다운로드 단추가 강조 표시된 내보낸 리소스 그룹 JSON 템플릿을 보여 주는 Azure Portal의 스크린샷

    JSON 템플릿 및 매개 변수 파일은 .zip 파일로 컴퓨터에 다운로드됩니다.

  3. 바탕 화면처럼 쉽게 액세스할 수 있는 폴더에 파일의 압축을 푸세요.

  4. Visual Studio Code를 엽니다.

로컬 환경 준비

  1. 터미널 메뉴에서 새 터미널을 선택합니다. 터미널 창은 일반적으로 화면의 아래쪽 절반에서 열립니다.

  2. 터미널 창 오른쪽에 bash가 표시되면 올바른 셸이 이미 열려 있다는 의미입니다. 또는 오른쪽에 bash 셸 아이콘이 표시되면 선택하여 셸을 시작할 수 있습니다.

    Bash 옵션이 표시된 Visual Studio Code 터미널 창의 스크린샷

    bash 이외의 셸이 나타나면 셸 드롭다운 화살표를 선택한 다음 Git Bash를 선택합니다.

    표시되어 있는 터미널 셸 드롭다운에서 Git Bash 기본값이 선택된 상태의 Visual Studio Code 터미널 창 스크린샷

  3. 터미널에서 템플릿을 저장한 디렉터리로 이동합니다. 예를 들어, templates 폴더에 템플릿을 저장한 경우 다음 명령을 사용할 수 있습니다.

    cd templates
    

Bicep 설치

다음 명령을 실행하여 최신 버전의 Bicep이 있는지 확인합니다.

az bicep install && az bicep upgrade
  1. 터미널 메뉴에서 새 터미널을 선택합니다. 터미널 창은 일반적으로 화면의 아래쪽 절반에서 열립니다.

  2. 터미널 창 오른쪽에 pwsh 또는powershell이 표시될 경우 올바른 셸이 이미 열려 있다는 의미입니다. 또는 오른쪽에 PowerShell 셸 아이콘이 표시되면 선택하여 셸을 시작할 수 있습니다.

    셸 드롭다운 목록에 pwsh 옵션이 표시된 Visual Studio Code 터미널 창의 스크린샷.

    pwsh 또는 powershell 이외의 셸이 나타나면 셸 드롭다운 화살표를 선택한 다음 PowerShell을 선택합니다.

    터미널 셸 드롭다운 목록이 표시되고 PowerShell이 선택되어 있는 Visual Studio Code 터미널 창의 스크린샷.

  3. 터미널에서 템플릿을 저장한 디렉터리로 이동합니다. 예를 들어, templates 폴더에 템플릿을 저장한 경우 다음 명령을 사용할 수 있습니다.

    Set-Location -Path templates
    

Bicep CLI 설치

Azure PowerShell에서 Bicep을 사용하려면 Bicep CLI를 설치합니다.

JSON 템플릿을 Bicep으로 디컴파일

decompile 명령을 사용하여 템플릿에서 Bicep 파일을 만듭니다.

az bicep decompile --file template.json

디컴파일 작업은 다음과 유사한 경고를 생성합니다.

WARNING: Decompilation is a best-effort process, as there is no guaranteed mapping from ARM JSON
 to Bicep.

You might need to fix warnings and errors in the generated bicep file(s), or decompilation might fail
 entirely if an accurate conversion is not possible.

If you would like to report any issues or inaccurate conversions,
please see https://github.com/Azure/bicep/issues.

decompile 명령을 사용하여 템플릿에서 Bicep 파일을 만듭니다.

bicep decompile template.json

디컴파일 작업은 다음과 유사한 경고를 생성합니다.

WARNING: Decompilation is a best-effort process, as there is no guaranteed mapping from ARM JSON
 to Bicep.

You might need to fix warnings and errors in the generated bicep file(s), or decompilation might fail
 entirely if an accurate conversion is not possible.

If you would like to report any issues or inaccurate conversions,
please see https://github.com/Azure/bicep/issues.

디컴파일된 Bicep 파일 검사

Visual Studio Code에서 template.bicep 파일을 열고 살펴봅니다. 유효한 Bicep 파일이지만 다음을 비롯한 몇 가지 문제가 있습니다.

  • 매개 변수 및 리소스에 주어진 기호 이름에는 밑줄이 포함되어 있으며 이해하기가 어렵습니다.
  • location 속성은 모든 리소스 정의에서 하드 코딩됩니다.
  • 템플릿에는 매개 변수이거나 Azure에서 자동으로 설정해야 하는 하드 코딩된 값이 포함되어 있습니다.

이 모듈의 나머지 부분에서 이 문제를 해결합니다.

새 Bicep 파일 만들기

  1. Visual Studio Code에서 main.bicep이라는 새 파일을 만듭니다.

  2. Visual Studio Code에서 Bicep 도구가 로드되도록 빈 파일을 저장합니다.

    파일>다른 이름으로 저장을 선택해도 되고 Windows에서 Ctrl+S(macOS는 ⌘+S) 키를 눌러도 됩니다.

  3. 두 파일이 동시에 보이도록 편집기를 분할합니다(왼쪽 창의 template.bicep 파일과 오른쪽 창의 main.bicep 파일).

    1. main.bicep 탭을 선택합니다.
    2. 보기>편집기 레이아웃>오른쪽 분할을 선택하여 오른쪽 창에서 main.bicep 탭을 엽니다.
    3. 왼쪽 창에서 main.bicep 탭을 닫습니다.

    왼쪽 창의 template.bicep 파일과 오른쪽 창의 main.bicep 파일을 보여주는 분할 Visual Studio Code 편집기의 스크린샷.

각 요소를 새 Bicep 파일에 복사

  1. template.bicep 파일에서 networkSecurityGroups_ToyTruckServer_nsg_name_resource라는 리소스를 main.bicep 파일로 복사합니다.

    복사할 때 securityRules 속성은 비어 있습니다. 이 모듈의 후반부에서는 중복 속성을 제거하도록 파일을 리팩터링합니다.

  2. Visual Studio Code는 networkSecurityGroups_ToyTruckServer_nsg_name 매개 변수가 없으므로 오류를 나타냅니다.

    매개 변수 누락으로 인해 오류가 표시되는 도구 설명이 있는 마이그레이션된 리소스를 보여주는 Visual Studio Code 편집기의 스크린샷.

    매개 변수를 main.bicep 파일에 복사합니다.

  3. 다음 리소스 및 관련 매개 변수를 사용하여 프로세스를 반복합니다.

    • publicIPAddresses_ToyTruckServer_ip_name_resource
    • virtualMachines_ToyTruckServer_name_resource
    • virtualNetworks_ToyTruck_vnet_name_resource
    • virtualNetworks_ToyTruck_vnet_name_default
    • networkInterfaces_toytruckserver890_name_resource

    참고

    배포에 있는 리소스의 이름은 여기에 나열된 리소스의 이름과 다를 수 있습니다. 이름이 유사한 리소스를 찾습니다.

    각 리소스를 복사할 때 해당 속성을 검사합니다. 이 모듈의 후반부에서는 Bicep 모범 사례를 준수하도록 각 리소스의 속성 및 구성을 업데이트합니다.

    사용자 고유의 템플릿을 변환하거나 내보낼 때 리소스를 복사하면서 모범 사례를 따르도록 리소스를 업데이트할 수 있습니다. 이 모듈에서는 마이그레이션 프로세스의 각 단계를 더 쉽게 이해할 수 있도록 별도로 리소스를 업데이트합니다.

누락된 리소스 확인

  1. Azure Portal에서 ToyTruck 리소스 그룹을 엽니다.

  2. 리소스 목록을 검토하고 Bicep 파일의 리소스 목록과 비교합니다. 리소스 그룹에는 Bicep 파일에서 resource로 정의되지 않은 디스크 리소스가 포함되어 있습니다.

    디스크 리소스가 강조 표시된 리소스 그룹을 보여주는 Azure Portal의 스크린샷.

    Bicep에서 가상 머신을 사용할 때 관리 디스크 리소스를 명시적으로 정의할 필요는 없습니다. 대신 가상 머신의 속성을 정의하면 Azure에서 자동으로 관리 디스크를 만듭니다. 이 예제에서는 디스크 리소스가 Bicep 파일에 정의되지 않았을까 우려할 필요가 없습니다.

템플릿 확인

마이그레이션 단계가 끝나면 main.bicep 파일이 다음과 유사하게 표시됩니다.

param virtualNetworks_ToyTruck_vnet_name string = 'ToyTruck-vnet'
param virtualMachines_ToyTruckServer_name string = 'ToyTruckServer'
param networkInterfaces_toytruckserver154_name string = 'toytruckserver154'
param publicIPAddresses_ToyTruckServer_ip_name string = 'ToyTruckServer-ip'
param networkSecurityGroups_ToyTruckServer_nsg_name string = 'ToyTruckServer-nsg'

resource networkSecurityGroups_ToyTruckServer_nsg_name_resource 'Microsoft.Network/networkSecurityGroups@2022-05-01' = {
  name: networkSecurityGroups_ToyTruckServer_nsg_name
  location: 'westus3'
  properties: {
    securityRules: []
  }
}

resource publicIPAddresses_ToyTruckServer_ip_name_resource 'Microsoft.Network/publicIPAddresses@2022-05-01' = {
  name: publicIPAddresses_ToyTruckServer_ip_name
  location: 'westus3'
  sku: {
    name: 'Standard'
    tier: 'Regional'
  }
  properties: {
    ipAddress: '1.2.3.4'
    publicIPAddressVersion: 'IPv4'
    publicIPAllocationMethod: 'Static'
    idleTimeoutInMinutes: 4
    ipTags: []
  }
}

resource virtualMachines_ToyTruckServer_name_resource 'Microsoft.Compute/virtualMachines@2022-08-01' = {
  name: virtualMachines_ToyTruckServer_name
  location: 'westus3'
  properties: {
    hardwareProfile: {
      vmSize: 'Standard_D2s_v3'
    }
    storageProfile: {
      imageReference: {
        publisher: 'canonical'
        offer: '0001-com-ubuntu-server-focal'
        sku: '20_04-lts-gen2'
        version: 'latest'
      }
      osDisk: {
        osType: 'Linux'
        name: '${virtualMachines_ToyTruckServer_name}_disk1_23e6a144c4ea4049b3e2be24b78a9e81'
        createOption: 'FromImage'
        caching: 'ReadWrite'
        managedDisk: {
          storageAccountType: 'Premium_LRS'
          id: resourceId('Microsoft.Compute/disks', '${virtualMachines_ToyTruckServer_name}_disk1_23e6a144c4ea4049b3e2be24b78a9e81')
        }
        deleteOption: 'Delete'
        diskSizeGB: 30
      }
      dataDisks: []
    }
    osProfile: {
      computerName: virtualMachines_ToyTruckServer_name
      adminUsername: 'toytruckadmin'
      linuxConfiguration: {
        disablePasswordAuthentication: false
        provisionVMAgent: true
        patchSettings: {
          patchMode: 'ImageDefault'
          assessmentMode: 'ImageDefault'
        }
        enableVMAgentPlatformUpdates: false
      }
      secrets: []
      allowExtensionOperations: true
      requireGuestProvisionSignal: true
    }
    networkProfile: {
      networkInterfaces: [
        {
          id: networkInterfaces_toytruckserver154_name_resource.id
          properties: {
            deleteOption: 'Detach'
          }
        }
      ]
    }
    diagnosticsProfile: {
      bootDiagnostics: {
        enabled: true
      }
    }
  }
}

resource virtualNetworks_ToyTruck_vnet_name_resource 'Microsoft.Network/virtualNetworks@2022-05-01' = {
  name: virtualNetworks_ToyTruck_vnet_name
  location: 'westus3'
  properties: {
    addressSpace: {
      addressPrefixes: [
        '10.0.0.0/16'
      ]
    }
    subnets: [
      {
        name: 'default'
        id: virtualNetworks_ToyTruck_vnet_name_default.id
        properties: {
          addressPrefix: '10.0.0.0/24'
          delegations: []
          privateEndpointNetworkPolicies: 'Disabled'
          privateLinkServiceNetworkPolicies: 'Enabled'
        }
        type: 'Microsoft.Network/virtualNetworks/subnets'
      }
    ]
    virtualNetworkPeerings: []
    enableDdosProtection: false
  }
}

resource virtualNetworks_ToyTruck_vnet_name_default 'Microsoft.Network/virtualNetworks/subnets@2022-05-01' = {
  name: '${virtualNetworks_ToyTruck_vnet_name}/default'
  properties: {
    addressPrefix: '10.0.0.0/24'
    delegations: []
    privateEndpointNetworkPolicies: 'Disabled'
    privateLinkServiceNetworkPolicies: 'Enabled'
  }
  dependsOn: [
    virtualNetworks_ToyTruck_vnet_name_resource
  ]
}

resource networkInterfaces_toytruckserver154_name_resource 'Microsoft.Network/networkInterfaces@2022-05-01' = {
  name: networkInterfaces_toytruckserver154_name
  location: 'westus3'
  kind: 'Regular'
  properties: {
    ipConfigurations: [
      {
        name: 'ipconfig1'
        id: '${networkInterfaces_toytruckserver154_name_resource.id}/ipConfigurations/ipconfig1'
        etag: 'W/"6a38849d-bd59-4eae-856e-4909f7ac1fac"'
        type: 'Microsoft.Network/networkInterfaces/ipConfigurations'
        properties: {
          provisioningState: 'Succeeded'
          privateIPAddress: '10.0.0.4'
          privateIPAllocationMethod: 'Dynamic'
          publicIPAddress: {
            name: 'ToyTruckServer-ip'
            id: publicIPAddresses_ToyTruckServer_ip_name_resource.id
            properties: {
              provisioningState: 'Succeeded'
              resourceGuid: '07079685-0980-4ddf-acc3-3c8797c94b9a'
              publicIPAddressVersion: 'IPv4'
              publicIPAllocationMethod: 'Dynamic'
              idleTimeoutInMinutes: 4
              ipTags: []
              ipConfiguration: {
                id: '${networkInterfaces_toytruckserver154_name_resource.id}/ipConfigurations/ipconfig1'
              }
              deleteOption: 'Detach'
            }
            type: 'Microsoft.Network/publicIPAddresses'
            sku: {
              name: 'Basic'
              tier: 'Regional'
            }
          }
          subnet: {
            id: virtualNetworks_ToyTruck_vnet_name_default.id
          }
          primary: true
          privateIPAddressVersion: 'IPv4'
        }
      }
    ]
    dnsSettings: {
      dnsServers: []
    }
    enableAcceleratedNetworking: true
    enableIPForwarding: false
    disableTcpStateTracking: false
    networkSecurityGroup: {
      id: networkSecurityGroups_ToyTruckServer_nsg_name_resource.id
    }
    nicType: 'Standard'
  }
}

참고

템플릿에서 기호 이름, API 버전 및 IP 주소 중 일부를 포함하여 몇 가지 사항이 다를 수 있습니다. 하지만 괜찮습니다. 모듈의 뒷부분에서 이러한 불일치 중 일부를 해결합니다.

리소스를 나타내는 초기 Bicep 파일을 만들었습니다. Bicep 파일이 잘 구성되지 않았으며 모범 사례를 준수하지 않습니다. 다음 단원에서는 마이그레이션된 템플릿의 품질을 개선하는 방법을 알아봅니다.

Git과 같은 버전 제어 시스템을 사용하는 경우 작업을 커밋하기 좋은 시점입니다.

main.bicep 파일을 확인한 후 template.bicep 파일을 닫습니다.