Create a VM with a Data Disk and Multiple NICs

This article provides Azure users with a guide to best practice for ARM templates. The article uses the example of a VM to explain and quickly give you an understanding of the theory and practice of ARM template development. This article is appropriate for people who are unfamiliar with ARM template development. Please note that the scope of “Azure” within this article is limited to mainland China.

Requirements

You can create a virtual machine (VM) in Azure using an ARM template. Many application systems require the separate storage of data and programs, with a data disk used specifically to store data. If there are multiple NICs, you can split different traffic types between the various NICs. Generally speaking, databases are also essential for application systems.

This is a fairly basic user requirement, so we will design a basic template based on this requirement and explain the process to help you quickly grasp how to develop ARM templates.

Scenario

In this scenario, the VM is deployed on its own subnet within the virtual network (VNet). There are two NICs: one is used for data access, the other is used to control flow access, while the Network Security Group (NSG) controls which traffic is allowed to reach each of the subnets and NICs within the deployment. The image below shows the basic system architecture for this scenario:

  

Template

This section uses the scenario described above as a basis to analyze an actual example, with the goal of helping you quickly grasp how to develop ARM templates and understand the formats, methods of use, and more advanced concepts involved in ARM templates. Please refer to the ARM Documentation for more comprehensive information about learning to develop ARM templates. The following section gives a paragraph-by-paragraph explanation of how to develop ARM templates using the JSON file for the ARM template.

Before you start, please prepare an Azure account, download the DemoVM ARM template, and install and configure Azure PowerShell.

Please note that every subsection of the text below corresponds to a comment in the example. For example, subsection “1.1” corresponds to “1.1 ARM Templates” in the example explanations.

1. Template Parameters, Variables, Functions, and Naming

1.1 Understand and Deploy ARM Templates

Please refer to ARM Overview and Understand the Structure and Syntax of Azure Resource Manager Templates.

ARM templates are based on the resource-focused Azure cloud computing platform. Generally speaking, all resources on Azure can be deployed using ARM templates, PowerShell, or Azure CLI commands. Please deploy the DemoVM ARM template in PowerShell using the commands below, then check the Resource Group mytestrg in the Azure portal. After you have deployed the ARM template, you can also export the template from the Azure portal. See Export an ARM Template for details. If you are not subscribed to enough resources, please refer to How to Request Quota Resources.

Login-AzureRmAccount -EnvironmentName AzureChinaCloud
new-AzureRmResourceGroup -Name mytestrg -Location "China North"
New-AzureRmResourceGroupDeployment -ResourceGroupName mytestrg -TemplateFile .\DemoVM.json

After you have deployed the ARM template, please check that deployment was successful by visiting http://{VmName}-0.chinanorth.cloudapp.chinacloudapi.cn/ in your browser.

1.2 Template Parameters

Please refer to Template Parameters.

Template parameters are used to identify template inputs. Template parameters can also be written as separate parameter files.

1.3 Default Parameter Values and Resource Functions

Please refer to Resource Manager Template Functions and Resource Functions for ARM Templates.

Template functions are functions that are commonly used in ARM templates. resourceGroup() is a commonly used function that is used to obtain resource groups. We recommend you use this function instead of strings like “China North.”

1.4 Azure Resource Naming Conventions

Please refer to Azure Resource Naming Conventions

There are many restrictions on Azure resource naming, and it is important to pay attention to this point. For example, Linux VM names are limited to 15 characters, and storage account names cannot include capital letters.

1.5 Template Variables

Please refer to ARM Template Variables.

Template variables are generally defined after the parameters. Please pay attention to the uniquestring() function they use to generate a hash code. We recommend you use this function so the resource names you deploy will not be duplicated.

{
    "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",    //1.1 ARM模板
    "contentVersion": "1.0.0.0",
    "parameters": { //1.2 模板参数
        "location": {
            "type": "string",
            "defaultValue": "[resourceGroup().location]",  //1.3. 参数缺省值和资源函数
            "metadata": {
                "description": "Location for the resources."
            }
        },
        "vmName": {
            "type": "string",
            "defaultValue": "myvm", //1.4 Azure 资源命名约定
            "metadata": {
                "description": "Name of virtual machine"
            }
        },
        ……
    },

    "variables": {      //1.5 模板变量
        "publicIpNamePrefix":  "[concat('PublicIp-', uniquestring(resourceGroup().id))]",
        "nsgName": "[concat('NSG-', uniquestring(resourceGroup().id))]",
        ……
    }

2. Basic Ways to Use ARM Resources

2.1 ARM Resources

Please refer to Azure ARM Template Resources for an overview and to the Azure Resource List for details of specific resources.

The key parts of ARM template development are located within resources, so it is very important to understand the basic concepts and ways of using these parts. Please go to the Azure Resource List link, where you will find detailed explanations of the properties and methods of use for the resources you can deploy. Please also note that this “Resource List” comes from the global version of Azure, and the resources it contains may differ slightly from those for Azure China. For more details, you can refer to Resource Provider Programs and Types and obtain real-time information using PowerShell (PowerShell Command List).

2.2 API Version

You can refer to the Azure Resource List in section 2.1 and obtain real-time information using PowerShell. If you simply need to obtain the API version details, you can view them in the Azure portal by going to “All Resources -> Resource Browser -> Provider.”

Note that different API versions may use slightly different resource syntax formats. If you are developing in Visual Studio, you will see notifications as appropriate.

2.3 Resource Types

Please refer to the Azure Resource List in section 2.1.

Resource types are indicated by “type” within Azure. In this example, “Microsoft.Network” is the provider and “publicIPAddresses” is the resource type. Please refer to Public IP Address in the Azure Resource List for details of how to use public IP address resources.

2.4 Deploy Multiple Resource Instances

Please refer to copyIndex Deploy Multiple Resource Instances.

ARM templates can use the copyIndex() method to deploy multiple resource instances. This example consists of two instances.

"resources": [      //2.1 ARM Resources 资源。
    {
        "apiVersion": "2018-02-01",     //2.2 API Version
        "type": "Microsoft.Network/publicIPAddresses",  //2.3 资源类型
        "name": "[concat(variables('publicIpNamePrefix'), '-', copyIndex())]",  //2.4 部署多个资源实例
        "location": "[parameters('location')]",
        "scale": null,
        ……
        "copy": {
            "name": "publicipcopy",
            "count": 2
        }
    },
    {
        "apiVersion": "2018-02-01",
        "type": "Microsoft.Network/virtualNetworks",
        ……
    }
]

3. Disks and Storage

3.1 Data Disks

Many apps need a VM with a data disk attached. This is easy to implement with ARM templates, but it is important to remember that after you have deployed the disk, you still need to manually create the file system on the disk and mount it in the operating system (OS). The following section shows the process to create a file system in Linux and mount it in the OS. If you want to automate the process of creating and mounting the file system, please see section 4.5 for details of how to use custom scripts to achieve this.

    登录到 部署在 Azure上的 Linux VM 上。
    sudo fdisk -l   ;查看所有磁盘
    sudo df -h      ;查看已经挂载到 Linux 的磁盘,找到数据磁盘 /dev/sdc
    sudo mkfs.ext4 /dev/sdc     ;创建数据磁盘的文件系统
    sudo mkdir sdc              ;设置挂载点
    sudo mount /dev/sdc ./sdc   ;挂载数据磁盘的文件系统

     

3.2 Storage Accounts

Please refer to Introduction to Azure Storage, About Storage Accounts, and Storage Service Level Agreements (SLA). For information about the “accountType” property, see “sku objects” within Azure Resources and Storage Type Options.

Storage accounts are a key concept and resource within Azure. All disks must be located in a storage account. Please read the documentation on storage accounts carefully.

{
  "apiVersion": "2018-04-01",
  "type": "Microsoft.Compute/disks", //3.1 数据磁盘
  "copy": {
    "name": "diskCopy",
    "count": 1
  },
  "location": "[parameters('location')]",
  "name": "[variables('vmDataDiskId')]",
  "properties": {
    "creationData": {
      "createOption": "Empty"
    },
    "diskSizeGB": 50
  }
},
{
  "apiVersion": "2015-06-15",
  "type": "Microsoft.Storage/storageAccounts",//3.2 存储账号
  "name": "[parameters('storageAccountName')]",
  "location": "[parameters('location')]",
  "properties": {
    "accountType": "[parameters('storageAccountType')]"
  }
},

4. Virtual Machines

4.1 Virtual Machine Sizes

Please refer to Linux Virtual Machine Sizes in Azure, Windows Virtual Machine Sizes in Azure, and Virtual Machine Pricing.

Azure China currently has four cloud computing centers in Mainland China. Please note that not every cloud computing center offers every type of VM at any time.

4.2 Virtual Machine Images

Please see Azure Images and the “Use VHD Images” section in the ARM Template Creation Guide.

Azure China currently hosts several hundred VM images. If you want to use these images, please browse through the available Azure Images first. You can also view the URI field in the artifacts within the images; the imageReference inside it includes the publisher, offer, and SKU. You can also view all of the images through PowerShell, for example, by using commands like Get-AzureRmVMImagePublisher/Get-AzureRmVMImageOffer/Get-AzureRmVMImageSku.

4.3 Resource Dependencies

Please refer to ARM Template Resource Deployment Sequence.

Please note that as there are dependencies between resources in ARM templates, you need to define the dependencies in detail when designing the overall architecture.

4.4 ARM Resource Iterations

Deploy the “sub-resource iteration” template for multiple instances of resources or properties in Azure ARM templates.

Resources can be included under the resource. The “extensions” in this case is a typical example. Of course, these “extensions” could also be present as a sub-resource of “Microsoft.Compute/virtualMachines,” but the type would need to be changed to “Microsoft.Compute/virtualMachines/extensions.”

4.5 Custom Scripts

Please carefully read the “Extension Architecture” section of Use Azure Custom Scripts to Extend Version 2 on Linux Virtual Machines. You can also refer to “Dynamically Execute VM Extensions Using Azure CLI.”

After the VM starts, you can execute specific scripts to flexibly configure or deploy apps for the user. We recommend you save scripts pointing to “fileUris” in Azure Storage, as this will improve the network situation. Note that “fileUris” must be accessible.

The custom script in this example deploys the LAMP architecture, but does not include an actual app instance to access a MySQL Database. If you need to install apps and configure the database parameters for apps, please view the MySQL Database parameters for deployment in the Resource Group within the Azure portal.

{
  "apiVersion": "2017-12-01",
  "type": "Microsoft.Compute/virtualMachines",
  "name": "[parameters('vmName')]",
  "location": "[parameters('location')]",
  "tags": { },
  "scale": null,
  "properties": {
    "hardwareProfile": {
      "vmSize": "[parameters('vmSize')]" //4.1 虚拟机大小
    },
    "storageProfile": {
      "imageReference": {   //4.2 虚拟机镜像
        "publisher": "Canonical",
        "offer": "UbuntuServer",
        "sku": "[parameters('ubuntuOSVersion')]",
        "version": "latest"
      },
      ……
    },
    ……
  },
  "dependsOn": [        //4.3 资源依赖关系
    "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]",
    "[resourceId('Microsoft.Compute/disks',variables('vmDataDiskId'))]",
    ……
  ],
  "resources": [        //4.4 ARM 资源迭代
    {
      "type": "extensions", //4.5 自定义脚本     
      "name": "[concat(parameters('vmName'), '_configScript')]",
          ……
      "properties": {
        ……
        "settings": {
          "fileUris": [
            "[concat(parameters('_artifactsLocation'), '/scripts/prepwebserver.sh', parameters('_artifactsLocationSasToken'))]"
          ],
          "commandToExecute": "[concat('sh prepwebserver.sh', ' ', 'True', ' ', variables('singleQuote'), variables('testPageMarkup'), variables('singleQuote'), ' ', 'index.html', ' ', variables('singleQuote'), parameters('ubuntuOSVersion'), variables('singleQuote'))]"
        },
        "protectedSettings": { }
      }
    }
  ]
}