Container Instance only runs on first deployment from ARM template - azure

I'm attempting to create a Storage Account with a file share via an ARM template. To do this, I'm creating the Storage Account and then running a az CLI command within a container instance, as described here.
The template deploys just fine, but the trouble is that the container is only started on the first run. Subsequent deployments do not result in the container instance being started, and thus if the file share has been removed (humans make mistakes), it's not recreated.
I can't use a complete deployment because there are other resources in the Resource Group.
I have consulted to documentation, but there doesn't seem to be anything about this in there.
Is there anyway to tell the container instance to always start?
Here is the example template that I am using -
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"storageAccountType": {
"type": "string",
"defaultValue": "Standard_LRS",
"allowedValues": [
"Standard_LRS",
"Standard_GRS",
"Standard_ZRS"
],
"metadata": {
"description": "Storage Account type"
}
},
"storageAccountName": {
"type": "string",
"defaultValue": "[uniquestring(resourceGroup().id)]",
"metadata": {
"description": "Storage Account Name"
}
},
"fileShareName": {
"type": "string",
"metadata": {
"description": "File Share Name"
}
},
"containerInstanceLocation": {
"type": "string",
"defaultValue": "[parameters('location')]",
"allowedValues": [
"westus",
"eastus",
"westeurope",
"southeastaisa",
"westus2"
],
"metadata": {
"description": "Container Instance Location"
}
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]",
"metadata": {
"description": "Location for all resources."
}
}
},
"variables": {
"image": "microsoft/azure-cli",
"cpuCores": "1.0",
"memoryInGb": "1.5",
"containerGroupName": "createshare-containerinstance",
"containerName": "createshare"
},
"resources": [
{
"type": "Microsoft.Storage/storageAccounts",
"name": "[parameters('storageAccountName')]",
"apiVersion": "2017-10-01",
"location": "[parameters('location')]",
"sku": {
"name": "[parameters('storageAccountType')]"
},
"kind": "Storage",
"properties": {}
},
{
"name": "[variables('containerGroupName')]",
"type": "Microsoft.ContainerInstance/containerGroups",
"apiVersion": "2018-02-01-preview",
"location": "[parameters('containerInstanceLocation')]",
"dependsOn": [
"[concat('Microsoft.Storage/storageAccounts/', parameters('storageAccountName'))]"
],
"properties": {
"containers": [
{
"name": "[variables('containerName')]",
"properties": {
"image": "[variables('image')]",
"command": [
"az",
"storage",
"share",
"create",
"--name",
"[parameters('fileShareName')]"
],
"environmentVariables": [
{
"name": "AZURE_STORAGE_KEY",
"value": "[listKeys(parameters('storageAccountName'),'2017-10-01').keys[0].value]"
},
{
"name": "AZURE_STORAGE_ACCOUNT",
"value": "[parameters('storageAccountName')]"
}
],
"resources": {
"requests": {
"cpu": "[variables('cpuCores')]",
"memoryInGb": "[variables('memoryInGb')]"
}
}
}
}
],
"restartPolicy": "OnFailure",
"osType": "Linux"
}
}
]
}

What if you manually delete the ACI from Azure portal or trough az cli in between using az container delete. As I understand Azure Container Instances are meant to be disposable. I usually just delete the old container when I want to deploy new one. Of course this is done usually by CI&CD pipeline like Jenkins.
EDIT:
ARM-template only starts the container if it doesn't find the resource but because it does find the ACI it does nothing. IMHO you should not use ARM-Templates for container management.

Related

Azure resources created using custom provider not showing on azure portal

I created an Azure custom provider by following the documentation in the link below:
https://learn.microsoft.com/en-us/azure/azure-resource-manager/custom-providers/
I am able to successfully create resources for the types defined in the custom provider using ARM templates. However, I do not see those resources on the azure portal under the specific resource group.
Is this behavior expected?
I have deployed the custom provider in azure portal using ARM template by following below steps
Open azure portal and search for custom deployment as below
Taken reference from Microsoft Doc
After opening custom deployment, i have used the below code and then click on save
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"funcName": {
"type": "string",
"defaultValue": "[uniqueString(resourceGroup().id)]",
"metadata": {
"description": "The unique name of the function application"
}
},
"storageName": {
"type": "string",
"defaultValue": "[concat('store', uniquestring(resourceGroup().id))]",
"metadata": {
"description": "The unique name of the storage account."
}
},
"location": {
"type": "string",
"defaultValue": "eastus",
"metadata": {
"description": "The location for the resources."
}
},
"zipFileBlobUri": {
"type": "string",
"defaultValue": "https://github.com/Azure/azure-docs-json-samples/blob/master/custom-providers/_artifacts/functionpackage.zip?raw=true",
"metadata": {
"description": "The URI to the uploaded function zip file"
}
}
},
"resources": [
{
"type": "Microsoft.Web/sites",
"apiVersion": "2022-03-01",
"name": "[parameters('funcName')]",
"location": "[parameters('location')]",
"kind": "functionapp",
"identity": {
"type": "SystemAssigned"
},
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts', parameters('storageName'))]"
],
"properties": {
"name": "[parameters('funcName')]",
"siteConfig": {
"appSettings": [
{
"name": "AzureWebJobsDashboard",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=',parameters('storageName'),';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('storageName')), '2022-05-01').keys[0].value)]"
},
{
"name": "AzureWebJobsStorage",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=',parameters('storageName'),';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('storageName')), '2022-05-01').keys[0].value)]"
},
{
"name": "FUNCTIONS_EXTENSION_VERSION",
"value": "~2"
},
{
"name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=',parameters('storageName'),';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('storageName')), '2022-05-01').keys[0].value)]"
},
{
"name": "WEBSITE_CONTENTSHARE",
"value": "[toLower(parameters('funcName'))]"
},
{
"name": "WEBSITE_NODE_DEFAULT_VERSION",
"value": "6.5.0"
},
{
"name": "WEBSITE_RUN_FROM_PACKAGE",
"value": "[parameters('zipFileBlobUri')]"
}
]
},
"clientAffinityEnabled": false,
"reserved": false
}
},
{
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2022-05-01",
"name": "[parameters('storageName')]",
"location": "[parameters('location')]",
"kind": "StorageV2",
"sku": {
"name": "Standard_LRS"
}
},
{
"type": "Microsoft.CustomProviders/resourceProviders",
"apiVersion": "2018-09-01-preview",
"name": "[parameters('funcName')]",
"location": "[parameters('location')]",
"dependsOn": [
"[concat('Microsoft.Web/sites/',parameters('funcName'))]"
],
"properties": {
"actions": [
{
"name": "ping",
"routingType": "Proxy",
"endpoint": "[concat('https://', parameters('funcName'), '.azurewebsites.net/api/{requestPath}')]"
}
],
"resourceTypes": [
{
"name": "users",
"routingType": "Proxy,Cache",
"endpoint": "[concat('https://', parameters('funcName'), '.azurewebsites.net/api/{requestPath}')]"
}
]
}
},
{
"type": "Microsoft.CustomProviders/resourceProviders/users",
"apiVersion": "2018-09-01-preview",
"name": "[concat(parameters('funcName'), '/ana')]",
"location": "parameters('location')",
"dependsOn": [
"[concat('Microsoft.CustomProviders/resourceProviders/',parameters('funcName'))]"
],
"properties": {
"FullName": "Ana Bowman",
"Location": "Moon"
}
}
],
"outputs": {
"principalId": {
"type": "string",
"value": "[reference(concat('Microsoft.Web/sites/', parameters('funcName')), '2022-03-01', 'Full').identity.principalId]"
}
}
}
Fill the following details like Subscription id, resource group, location and click on review+create
After deploying into the azure portal, we will get below
After deploying it to azure poral Goto azure portal and click on your resource group and click on the check box you will find as below

Mount Azure File Share on Azure Container with access key retrieval in ARM Template

I'm creating a file share and container instance using ARM template, and I need to mount this created file share to the container. I have the below template -
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json",
"contentVersion": "1.0.0.0",
"parameters": {
"storageAccountType": {
"type": "string",
"defaultValue": "Standard_GRS",
"metadata": {
"description": "Storage Account type"
}
},
"storageAccountName": {
"type": "string",
"defaultValue": "[concat('storage', uniquestring(resourceGroup().id))]",
"metadata": {
"description": "Name of the Azure Storage account."
}
},
"sharePrefix": {
"type": "string",
"defaultValue": "files",
"metadata": {
"description": "Specifies the prefix of the file share names."
}
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]",
"metadata": {
"description": "Location for all resources."
}
},
.....
},
"variables": {
"ContainerGroupName": "[concat('my-cg',uniquestring(resourceGroup().id))]",
"storageAccountId": "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]",
"ContainerName": "my-container"
},
"resources": [
{
"type": "Microsoft.Storage/storageAccounts",
"name": "[parameters('storageAccountName')]",
"apiVersion": "2019-06-01",
"location": "[parameters('location')]",
"kind": "Storage",
"sku": {
"name": "[parameters('storageAccountType')]"
}
},
{
"type": "Microsoft.Storage/storageAccounts/fileServices/shares",
"apiVersion": "2019-06-01",
"name": "[concat(parameters('storageAccountName'), '/default/', parameters('sharePrefix'))]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]"
]
},
{
"name": "[variables('ContainerGroupName')]",
"type": "Microsoft.ContainerInstance/containerGroups",
"apiVersion": "2018-10-01",
"location": "[parameters('location')]",
"properties": {
"containers": [
{
"name": "[variables('ContainerName')]",
"properties": {
"image": "imageNameinACR",
"resources": {
"requests": {
"memoryInGB": 14,
"cpu": 4
}
},
"volumeMounts": [
{
"name": "filesharevolume",
"mountPath": "/app"
}
]
}
}
],
"imageRegistryCredentials": [
....
],
"restartPolicy": "OnFailure",
"osType": "Linux",
"volumes": [
{
"name": "filesharevolume",
"azureFile": {
"shareName": "[concat(parameters('storageAccountName'), '/default/', parameters('sharePrefix'))]",
"storageAccountName": "[parameters('storageAccountName')]",
"storageAccountKey": "[listKeys(parameters('storageAccountName'), '2019-06-01').keys[0].value]"
}
}
]
},
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]",
"[resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), 'default', parameters('sharePrefix'))]"
]
}
],
"outputs": {}
}
However, this is throwing the error
"error": {
"code": "CannotAccessStorageAccount",
"message": "The Azure storage account 'storage6x2un3wwsta6u' in volume 'filesharevolume' can't be accessed: 'The remote server
returned an error: (400) Bad Request.'. This can be caused by
incorrect Azure storage account key or Azure storage firewalls." }
I've also tried the resourceId to retrieve the secret like below, but it throws the same error.
"storageAccountKey": "[listKeys(variables('storageAccountId'), '2019-06-01').keys[0].value]"
Am I missing anything in the template? I referred to various samples that show this method to retrieve access keys in ARM template.
In my DOCKERFILE for the container image, I'm running
RUN MKDIR /App
Could there be an issue with the mount path? My assumption is that the fileshare will be mounted in this directory - /app/filesharevolume.
I don't see the definition of the variable storageAccountId, but the template function listkeys really works with the resource Id. So I give the code that works on my side:
"storageAccountKey": "[listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2019-06-01').keys[0].value]"
And if the storage account is not in the same resource group with the container group, then you can add the group name of the storage account when you get the resource Id:
"storageAccountKey": "[listKeys(resourceId(variables('resourceGroupName'), 'Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2019-06-01').keys[0].value]
Here is the example.
Update:
And there is a problem in the volumes of the container group. You need to change the file share name into this:
"volumes": [
{
"name": "filesharevolume",
"azureFile": {
"shareName": "[parameters('sharePrefix')]",
"storageAccountName": "[parameters('storageAccountName')]",
"storageAccountKey": "[listKeys(parameters('storageAccountName'), '2019-06-01').keys[0].value]"
}
}
]

Setting ENV in Azure Container Instances Deployment

I tried to automate my deployment of a Docker container to an Azure resource group following the docs on https://learn.microsoft.com/en-us/azure/azure-resource-manager/resource-manager-keyvault-parameter#deploy-a-key-vault-and-secret and https://gallery.azure.com/artifact/20161101/microsoft.containerinstances.1.0.8/Artifacts/mainTemplate.json.
I was able to deploy my application successfully, including the retrieval of encrypted secrets from Vault. I'm now struggling to set ENVs for my container, both secrets and normal ENVs. Even though there is a way to set ENVs in the az container API, I cannot find anything in the docs of the resource group deployment API. How can I pass ENVs to my Azure container?
The snippet of the json template you need is as follows (the full template is here)
"name": "[toLower(parameters('DeploymentName'))]",
"type": "Microsoft.ContainerInstance/containerGroups",
"properties": {
"containers": [
{
"environmentVariables": [
{
"name": "CertificateName",
"value": "[parameters('CertificateName')]"
},
],
You may look the sample mentioned here: https://github.com/Azure/azure-quickstart-templates/blob/master/101-aci-storage-file-share/azuredeploy.json
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"storageAccountType": {
"type": "string",
"defaultValue": "Standard_LRS",
"allowedValues": [
"Standard_LRS",
"Standard_GRS",
"Standard_ZRS"
],
"metadata": {
"description": "Storage Account type"
}
},
"storageAccountName": {
"type": "string",
"defaultValue": "[uniquestring(resourceGroup().id)]",
"metadata": {
"description": "Storage Account Name"
}
},
"fileShareName": {
"type": "string",
"metadata": {
"description": "File Share Name"
}
},
"containerInstanceLocation": {
"type": "string",
"defaultValue": "[resourceGroup().location]",
"allowedValues": [
"westus",
"eastus",
"westeurope",
"southeastaisa",
"westus2"
],
"metadata": {
"description": "Container Instance Location"
}
}
},
"variables": {
"image": "microsoft/azure-cli",
"cpuCores": "1.0",
"memoryInGb": "1.5",
"containerGroupName":"createshare-containerinstance",
"containerName": "createshare"
},
"resources": [
{
"type": "Microsoft.Storage/storageAccounts",
"name": "[parameters('storageAccountName')]",
"apiVersion": "2017-10-01",
"location": "[resourceGroup().location]",
"sku": {
"name": "[parameters('storageAccountType')]"
},
"kind": "Storage",
"properties": {}
},
{
"name": "[variables('containerGroupName')]",
"type": "Microsoft.ContainerInstance/containerGroups",
"apiVersion": "2018-02-01-preview",
"location": "[parameters('containerInstanceLocation')]",
"dependsOn": [
"[concat('Microsoft.Storage/storageAccounts/', parameters('storageAccountName'))]"
],
"properties": {
"containers": [
{
"name": "[variables('containerName')]",
"properties": {
"image": "[variables('image')]",
"command": [
"az",
"storage",
"share",
"create",
"--name",
"[parameters('fileShareName')]"
],
"environmentVariables": [
{
"name": "AZURE_STORAGE_KEY",
"value": "[listKeys(parameters('storageAccountName'),'2017-10-01').keys[0].value]"
},
{
"name": "AZURE_STORAGE_ACCOUNT",
"value": "[parameters('storageAccountName')]"
}
],
"resources": {
"requests": {
"cpu": "[variables('cpuCores')]",
"memoryInGb": "[variables('memoryInGb')]"
}
}
}
}
],
"restartPolicy": "OnFailure",
"osType": "Linux"
}
}
]
}
The recommended way for secrets is to Mount secret volume to your container, because it is using tmpfs and your secrets exist only in volatile memory!
NOTE: at the time of this post only Linux based containers support it...

How to create a new resource in Azure ARM templates?

Ok, I've done everything what described here with ARM template - https://azure.microsoft.com/en-us/documentation/articles/web-sites-integrate-with-vnet. Except one thing - Enabling VNET Integration with a pre-existing VNET.
Can this be done in ARM templates?
Thanks!
Here is a sample template that might help you. It's modified from this quickstart sample in GitHub
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"hostingPlanName": {
"type": "string",
"minLength": 1,
"metadata": {
"description": "Name of the hosting plan to use in Azure."
}
},
"webSiteName": {
"type": "string",
"minLength": 1,
"metadata": {
"description": "Name of the Azure Web app to create."
}
},
"vnetName": {
"type": "string",
"minLength": 1,
"metadata": {
"description": "Name of an existing Azure VNet which has a Gateway Subnet already, and is in the resource group you are going to deploy."
}
},
"skuName": {
"type": "string",
"defaultValue": "S1",
"allowedValues": [
"S1",
"S2",
"S3",
"P1",
"P2",
"P3",
"P4"
],
"metadata": {
"description": "Describes plan's pricing tier and instance size. Check details at https://azure.microsoft.com/en-us/pricing/details/app-service/"
}
},
"skuCapacity": {
"type": "int",
"defaultValue": 1,
"minValue": 1,
"metadata": {
"description": "Describes plan's instance count"
}
}
},
"resources": [
{
"apiVersion": "2015-08-01",
"name": "[parameters('hostingPlanName')]",
"type": "Microsoft.Web/serverfarms",
"location": "[resourceGroup().location]",
"tags": {
"displayName": "HostingPlan"
},
"sku": {
"name": "[parameters('skuName')]",
"capacity": "[parameters('skuCapacity')]"
},
"properties": {
"name": "[parameters('hostingPlanName')]"
}
},
{
"apiVersion": "2015-08-01",
"name": "[parameters('webSiteName')]",
"type": "Microsoft.Web/sites",
"location": "[resourceGroup().location]",
"tags": {
"[concat('hidden-related:', resourceGroup().id, '/providers/Microsoft.Web/serverfarms/', parameters('hostingPlanName'))]": "Resource",
"displayName": "Website"
},
"dependsOn": [
"[concat('Microsoft.Web/serverfarms/', parameters('hostingPlanName'))]"
],
"properties": {
"name": "[parameters('webSiteName')]",
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', parameters('hostingPlanName'))]"
},
"resources": [
{
"apiVersion": "2015-08-01",
"name": "web",
"type": "config",
"dependsOn": [
"[concat('Microsoft.Web/sites/', parameters('webSiteName'))]"
],
"properties": {
"pythonVersion": "3.4"
}
},
{
"apiVersion": "2015-08-01",
"name": "[parameters('vnetName')]",
"type": "virtualNetworkConnections",
"location": "[resourceGroup().location]",
"dependsOn": [
"[concat('Microsoft.Web/sites/', parameters('webSiteName'))]"
],
"properties": {
"vnetResourceId": "[concat(resourceGroup().id, '/providers/Microsoft.Network/virtualNetworks/', parameters('vnetName'))]"
}
}
]
}
]
}
Here are 3 things you should be careful with.
The template starts with a python web app template, and adds a "Microsoft.Web/sites/virtualNetworkConnections" resource. So, if you are using other programing language, you can start with some other template.
The pre-existing VNet should be in the same resource group you are deploying. If the VNet you are using are not in the same resource group, you should modify the "vnetResourceId" in the "properties" of the "Microsoft.Web/sites/virtualNetworkConnections".
The VNet you are using should have a Gateway with a Point-to-Site address already. Otherwise, you will not be able integrate you web app to the VNet. For more details, see Configure a Point-to-Site connection to a virtual network using PowerShell
Update: About how I get this info, well, there is not much about this on the net. This template is constructed based on the PowerShell solution and my knowledge about ARM template. The PowerShell solution is available in this article. Another possible way to get an ARM template is to create those resources in one resource group, and export the template of the resource group in the portal. But, for this case, that is not going to work, because resource type "Microsoft.Web/sites/virtualNetworkConnections" is not supported yet. However, you can still get a look at the REST API by the PowerShell Command Get-AzureRmResource with option -debug.
Get-AzureRmResource -ResourceGroupName <resource group> -ResourceType Microsoft.Web/sites/virtualNetworkConnections -Name <web app>/<VNet> -debug -ApiVersion 2015-08-01
You will get the following REST API.
Uri:
https://management.azure.com/subscriptions/<subscription id>/resourceGroups/<resource group>/providers/Microsoft.Web/sites/<web app>/virtualNetworkConnections/<VNet>?api-version=2015-08-01
Body:
{
"id": "/subscriptions/<subscription id>/resourceGroups/<resource group>/providers/Microsoft.Web/sites/<web app>/virtualNetworkConnections/<VNet>",
"name": "<VNet>",
"type": "Microsoft.Web/sites/virtualNetworkConnections",
"location": "<Location>",
"tags": null,
"properties": {
"vnetResourceId": "/subscriptions/<subscription id>/resourceGroups/<resource group>/providers/Microsoft.Network/virtualNetworks/<VNet>"
"certThumbprint": "<Thumbprint>",
"certBlob": "<cert>",
"routes": null,
"resyncRequired": false,
"dnsServers": null
}
}
Skipping some automatically generated values, you will get the template which is quite similar to the one I write:
{
"name": "<VNet>",
"type": "Microsoft.Web/sites/virtualNetworkConnections",
"location": "<Location>",
"properties": {
"vnetResourceId": "/subscriptions/<subscription id>/resourceGroups/<resource group>/providers/Microsoft.Network/virtualNetworks/<VNet>"
}
}

Creating VM's from image and adding to an existing Availability Set

How can I add an existing VM that I either created in the portal or imported from vmdepot to an existing availability set? It doesn't seem to be possible from the portal, does it work in Powershell? Does it work at all with the Resource Manager deployment model?
Currently, for ARM Deployment, Setting Availability set is not supported yet. Availability set could only be added during creation. Hence, for your case, you need to delete the current instance, and create a new deployment with the old OSDisk, Vnet, and some other setting.
This can be achieved by using ARM Template. The following example shows you how to deploy a VM with an existing VHD and Vnet. It also create a new availability set, and add the VM to the availability set.
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"location": {
"type": "string",
"metadata": {
"description": "Please enter the location where you want to deploy this VM"
}
},
"vmName": {
"type": "string",
"metadata": {
"description": "Name of the VM"
}
},
"osType": {
"type": "string",
"allowedValues": [
"Windows",
"Linux"
],
"metadata": {
"description": "Type of OS on the existing vhd"
}
},
"osDiskVhdUri": {
"type": "string",
"metadata": {
"description": "Uri of the existing VHD in ARM standard or premium storage"
}
},
"vmSize": {
"type": "string",
"metadata": {
"description": "Size of the VM"
}
},
"existingVirtualNetworkName": {
"type": "string",
"metadata": {
"description": "Name of the existing VNET"
}
},
"existingVirtualNetworkResourceGroup": {
"type": "string",
"metadata": {
"description": "Name of the existing VNET resource group"
}
},
"subnetName": {
"type": "string",
"metadata": {
"description": "Name of the subnet in the virtual network you want to use"
}
},
"dnsNameForPublicIP": {
"type": "string",
"metadata": {
"description": "Unique DNS Name for the Public IP used to access the Virtual Machine."
}
},
"availabilitySetName": {
"type": "string",
"metadata": {
"description": "The name of your Availability Set."
}
}
},
"variables": {
"api-version": "2015-06-15",
"publicIPAddressType": "Dynamic",
"vnetID": "[resourceId(parameters('existingVirtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks', parameters('existingVirtualNetworkName'))]",
"subnetRef": "[concat(variables('vnetID'),'/subnets/', parameters('subnetName'))]",
"nicName": "[parameters('vmName')]",
"publicIPAddressName": "[parameters('vmName')]"
},
"resources": [
{
"apiVersion": "[variables('api-version')]",
"type": "Microsoft.Network/publicIPAddresses",
"name": "[variables('publicIPAddressName')]",
"location": "[parameters('location')]",
"tags": {
"displayName": "PublicIPAddress"
},
"properties": {
"publicIPAllocationMethod": "[variables('publicIPAddressType')]",
"dnsSettings": {
"domainNameLabel": "[parameters('dnsNameForPublicIP')]"
}
}
},
{
"apiVersion": "[variables('api-version')]",
"type": "Microsoft.Network/networkInterfaces",
"name": "[variables('nicName')]",
"location": "[parameters('location')]",
"dependsOn": [
"[concat('Microsoft.Network/publicIPAddresses/', variables('publicIPAddressName'))]"
],
"tags": {
"displayName": "NetworkInterface"
},
"properties": {
"ipConfigurations": [
{
"name": "ipconfig1",
"properties": {
"privateIPAllocationMethod": "Dynamic",
"publicIPAddress": {
"id": "[resourceId('Microsoft.Network/publicIPAddresses',variables('publicIPAddressName'))]"
},
"subnet": {
"id": "[variables('subnetRef')]"
}
}
}
]
}
},
{
"type": "Microsoft.Compute/availabilitySets",
"name": "[parameters('availabilitySetName')]",
"apiVersion": "2015-06-15",
"location": "[parameters('location')]",
"properties": {
"platformFaultDomainCount": "3",
"platformUpdateDomainCount": "20"
}
},
{
"apiVersion": "[variables('api-version')]",
"type": "Microsoft.Compute/virtualMachines",
"name": "[parameters('vmName')]",
"location": "[parameters('location')]",
"tags": {
"displayName": "VirtualMachine"
},
"dependsOn": [
"[concat('Microsoft.Compute/availabilitySets/', parameters('availabilitySetName'))]",
"[concat('Microsoft.Network/networkInterfaces/', variables('nicName'))]"
],
"properties": {
"hardwareProfile": {
"vmSize": "[parameters('vmSize')]"
},
"AvailabilitySet" : {
"id": "[resourceId('Microsoft.Compute/availabilitySets', parameters('availabilitySetName'))]"
},
"storageProfile": {
"osDisk": {
"name": "[concat(parameters('vmName'))]",
"osType": "[parameters('osType')]",
"caching": "ReadWrite",
"vhd": {
"uri": "[parameters('osDiskVhdUri')]"
},
"createOption": "Attach"
}
},
"networkProfile": {
"networkInterfaces": [
{
"id": "[resourceId('Microsoft.Network/networkInterfaces',variables('nicName'))]"
}
]
}
}
}
]
}
If you want to add the VM to an existing availability set, you can delete
{
"type": "Microsoft.Compute/availabilitySets",
"name": "[parameters('availabilitySetName')]",
"apiVersion": "2015-06-15",
"location": "[parameters('location')]",
"properties": {
"platformFaultDomainCount": "3",
"platformUpdateDomainCount": "20"
}
},
and
"[concat('Microsoft.Compute/availabilitySets/', parameters('availabilitySetName'))]",
For more details about authoring ARM template, see Authoring Azure Resource Manager templates
For more information about how to deploy an ARM template, see Deploy a Resource Group with Azure Resource Manager template
And the above template is modified from this sample template from GitHub.
After I posted this answer, I had been thinking about using REST API to update vm with an availability set. I thought it might work, so I gave it a shot, and here is the error message I got:
Invoke-RestMethod : {
"error": {
"code": "PropertyChangeNotAllowed",
"target": "availabilitySet.id",
"message": "Changing property 'availabilitySet.id' is not allowed."
}
}
At C:\Users\v-dazen\Documents\setVMRestAPI.ps1:13 char:1
+ Invoke-RestMethod -Method Put -Uri "https://management.azure.com/subs ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
That means setting the availability set for an existing ARM deployed VM is not possible yet.

Resources