Howdy fellow IoT Edgers!

The ability to quickly spin up an Azure VM with IoT Edge configured out of the box is very convenient for testing or a lab environment. For this purpose, we have an Azure Marketplace Ubuntu w/ IoT Edge offer. However, some users mentioned to me that it is a bit flaky with automation and hard to extend with other custom operations. I did a bit of digging to see if I could tweak this and shared an improvement on Github. Community members expressed interest in knowing how the improvement worked under the covers, so here are the gory (not really) details.

ARM + cloud-init = 👍🏽

Cloud-init is a widely used industry approach to customize a Linux installation after the first boot. Azure supports cloud-init for several popular Linux distributions. I picked Ubuntu 18.04, a Tier 1 OS for IoT Edge. Using cloud-init, I was able to easily add the Microsoft Debian repo which hosts IoT Edge and Azure Moby packages, and install them at first boot (see cloud-init.txt ). Cloud-init is also a convenient extension point to add other packages or commands you might want installed or executed on your IoT Edge VM at boot.

Most of you are likely familiar with Azure Resource Manager (ARM) - it is the Azure native way to describe your cloud infrastructure, and a natural choice to define the components needed to spin up a ready-to-use Azure VM. The interesting bit for us is that ARM supports cloud-init, I just needed to put the contents of cloud-init.txt in the VM's customdata field.

1 (step) is better than 3

The current Azure Marketplace offer requires three steps - accept terms, create VM and finally, run the configuration script that sets the device connection string. I wanted to see if I could do this in a single step.

The challenge was to dynamically incorporate the user supplied connection string in the cloud-init config, which is then set as the value for customdata field of VM's ARM template. In my web search I stumbled on a way to do this using ', variables('parameterName'), ' pattern in the cloud-init file. It also had a link to the genoneline.py script that helped transform the cloud-init.txt file into a single line as required by the ARM template.

Putting it together

Using this method, I was able to produce a single liner that goes from zero to a VM with IoT Edge sending data to the cloud:

az group deployment create \ --name edgeVm \ --resource-group replace-with-rg-name \ --template-uri "https://aka.ms/iotedge-vm-deploy" \ --parameters dnsLabelPrefix='my-edge-vm1' \ --parameters adminUsername='azureuser' \ --parameters deviceConnectionString=$(az iot hub device-identity show-connection-string --device-id replace-with-device-name --hub-name replace-with-hub-name -o tsv) \ --parameters authenticationType='sshPublicKey' \ --parameters adminPasswordOrKey="$(< ~/.ssh/id_rsa.pub)"

If you prefer GUIs, you launch this ARM template in your Azure Portal as well: Deploy to Azure.

In the westu2 region, I was able to see data flowing to IoT Hub in under 3 minutes of executing the command (YMMV). Hope this was helpful, reply in the comments below if you have any feedback.

And finally, PRs are welcome if you have ideas for improvements!