创建具有数据磁盘和多个 NIC 的 VM
本文为 Azure 使用者提供 ARM 模板最佳实践指南,本文通过对一个创建 VM 的实例的讲解,让您对 ARM 模板开发有一个快速的从实践到理论的认识。如果您对 ARM 模板开发并不熟悉,本文比较合适。请注意,文中 “Azure” 作用范围均指中国。
需求
用户可以同过 ARM 模板在 Azure 中创建虚拟机 (VM)。对很多应用系统来说,数据和程序需要分开存放,数据磁盘用来专门存放数据。有多个 NIC 时,可跨各个 NIC 分隔不同的流量类型。同时,数据库对于应用系统来说,一般也是必须的。
这是一个比较基础的用户需求,我们将会基于这个需求设计一个基础模板,并对之进行讲解,力求使您以最快的速度掌握 ARM 模板的开发。
方案
本方案中,虚拟机部署在虚拟网络 (VNet) 中其自己的子网(Subnet)中,Nic有两个,一个用于数据流访问,另一个用于控制流访问,网络安全组 (NSG) 以控制哪些流量允许到达部署中的每个子网和 NIC。下图显示了此方案的基本体系结构:
模板
本节以上述方案为基础,对实际的案例进行剖析,希望用最快的方式使您掌握 ARM 模板的开发,并能够较快地理解 ARM 模板相关的格式、用法和深入的理解。对于比较全面的 ARM 模板开发学习,请参考 ARM 文档。如下将针对ARM模板的json文件,逐段讲解 ARM 模板的开发。
在开始前,请首先准备一个 Azure 账号,下载 DemoVM ARM模板,并安装和配置 Azure PowerShell。
请注意,下文中每一小节对应着示例中的注释,比如 “1.1” 小节对应着示例讲解中的 “1.1 ARM模板”。
1 模板参数、变量、函数和命名
1.1 ARM 模板了解和部署
请参考 ARM概述 和 了解 Azure 资源管理器模板的结构和语法。
ARM模板基于以资源为中心 Azure 云计算平台,一般来说,Azure 上的所有资源都可以用 ARM 模板来部署,同样,也可以用 PowerShell 或 Azure-cli命令来部署。 请在 PowerShell下用如下命令部署模板 DemoVM ARM模板,并在 Azure 入口中查看资源组 mytestrg。ARM 模板部署后,被部署的模板也可以从 Azure 入口中导出,具体请参考 导出 ARM 模板。如果您的订阅资源不够了,请参考 如何申请配额资源。
Login-AzureRmAccount -EnvironmentName AzureChinaCloud
new-AzureRmResourceGroup -Name mytestrg -Location "China North"
New-AzureRmResourceGroupDeployment -ResourceGroupName mytestrg -TemplateFile .\DemoVM.json
ARM 模板部署完成后,请浏览器中查询部署是否成功, http://{VmName}-0.chinanorth.cloudapp.chinacloudapi.cn/
1.2 模板参数
请参考 模板参数。
模板参数用于标识模板的输入,模板参数也可以写成单独的参数文件。
1.3 参数缺省值和资源函数
请参考 资源管理器模板函数 以及 用于 ARM 模板的资源函数。
模板函数是 ARM 模板中经常用到的功能。resourceGroup() 用于获取资源组,是常用的函数,我们建议您使用这个函数而不是类似于“China North”这样的字符串。
1.4 Azure 资源命名约定
请参考 Azure 资源命名约定
Azure资源命名有很多限制,例如Linux的虚拟机名称长度限制为15个字符,比如存储账号不能用大写字符,请特别注意这一点。
1.5 模板变量
模板变量 variables 一般在parameters后定义,注意其引用的uniquestring() 函数,它可以生成 哈希值,建议使用这个函数,这样部署的资源名称不会有重复现象。
{
"$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. ARM 资源基本用法
2.1 ARM Resources 资源
请参考 Azure ARM 模板的 Resources 介绍,以及具体的 Azure 资源列表。
ARM 模板开发的主要部分都位于 resources 之内,因此了解这一部分的基本概念以及用法就非常重要。请注意 Azure 资源列表 链接,这里面详细介绍了您可以部署的资源的用法、属性等。另外请注意这个“资源列表”来自于Global,Azure 中国的可能稍有不同,具体请参考 资源提供程序和类型 并通过 PowerShell (PowerShell指令列表)获取实时信息。
2.2 API Version
可参考2.1中的 Azure 资源列表,并通过 PowerShell 获取实时信息,如果需要单纯获取 API Version 信息,可以在 Azure 入口 中的“所有服务->资源浏览器->提供程序”中查看。
请注意不同的 API Version 可能资源的语法格式略有不同,如果您在 Visual Studio中开发,会有相应的提示。
2.3 资源类型
可参考2.1中的 Azure 资源列表。
Azure 中的资源类型通过“type”来表示。本例中,“Microsoft.Network”是provider,“publicIPAddresses”是resource type,如何使用公共IP地址资源,可参考 Azure 资源列表中的 Public IP Address。
2.4 部署多个资源实例
请参考 copyIndex 部署多个资源实例。
ARM 模板可以用copyIndex()方法部署多个资源实例,本例中为2个实例。
"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. 磁盘和存储
3.1 数据磁盘
很多应用需要 VM 附加数据磁盘,这在 ARM 模板中很容易实现,但要注意的是,磁盘虽然可以部署成功,但您需要手动在磁盘上创建文件系统并挂载到操作系统。下面展示了本例中如何在 Linux 中创建文件系统并挂载到操作系统的流程。如果您想自动实现文件系统的创建和挂载,请参考 4.5 采用自定义脚本实现。
登录到 部署在 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 存储账号
请参考 azure存储简介,关于存储账户 以及 存储的服务级别协议(SLA)。关于属性“accountType”,请参考 Azure资源中的"sku object" 以及 存储类型选择。
存储账号是 Azure 中一个非常重要的概念和资源,所有的磁盘都必须位于存储账号下,请详细阅读存储账号的相关文档。
{
"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. 虚拟机
4.1 虚拟机大小
请参考 Azure 中 Linux 虚拟机的大小,Azure 中 Windows 虚拟机的大小 以及 虚拟机价格。
Azure 中国目前在中国有四个云计算中心,请注意并不是每个云计算中心在任何时刻都有所有类型的虚拟机。
4.2 虚拟机镜像
请参考 ARM制作指南 中的“VHD 镜像引用”部分和 Azure镜像。
Azure 中国目前有数百个虚拟机镜像,如果您想引用这些镜像,请先查询所有的 Azure镜像,请查看镜像中 artifacts 中的 uri字段,其中的 imageReference 包含了publisher、offer 和 sku。您也可以通过 powershell 查看所有的镜像,比如 Get-AzureRmVMImagePublisher/Get-AzureRmVMImageOffer/Get-AzureRmVMImageSku 等命令。
4.3 资源依赖关系
请参考 ARM 模板中部署资源的顺序。
请注意,由于 ARM 模板中的资源之间有先后依赖关系,因此在设计整个架构的时候,就需要仔细定义这种依赖关系。
4.4 ARM 资源迭代
在 Azure ARM 模板中部署资源或属性的多个实例 中的“子资源的迭代”模块。
资源下面可以包含资源,本案中”extensions”就是典型案例。当然这个“extensions”也可以不作为"Microsoft.Compute/virtualMachines"的子资源存在,但是其type需要修改为“Microsoft.Compute/virtualMachines/extensions”。
4.5 自定义脚本
仔细阅读 在 Linux 虚拟机上使用 Azure 自定义脚本扩展版本 2 中的“扩展架构”部分,也可以参考 通过azure cli动态执行 VM 扩展。
虚机启动后可以执行指定脚本,可以灵活配置或部署用户的应用。我们建议将 “fileUris” 指向的脚本存储到Azure 存储中,这样网络状况会更好一些,注意 “fileUris” 必须是可访问的。
本案例中的自定义脚本部署了 LAMP 架构,但并没有 实际的应用实例访问 Mysql 数据库,如果您需要安装应用并配置应用程序的数据库参数,请到 Azure 入口 资源组中查询部署的 Mysql 数据库的参数。
{
"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": { }
}
}
]
}