I have followed Colin Percival's excellent work on getting FreeBSD images supported on the public cloud provider infrastructure since 2010. I spent some time this weekend looking at the latest images and writing an Azure Bicep template to launch a FreeBSD VM. Microsoft now has an article about launching FreeBSD VM images with their relatively excellent free azure documentation and training. That doc makes a great starting point, but it doesn't show how to find the latest FreeBSD images or use Bicep templates. As of this writing, FreeBSD 13.2 is the latest image in the Azure MarketPlace, and VMs can be launched in Azure at least half a dozen different ways:
- az command-line tool
- Start-AzVM PowerShell
- Bicep template engine
- ARM Templates
- Terraform
- Pulumi
- etc..
I'll show the az command-line needed to quickly launch a VM, but will focus mostly on Bicep templates, as this appears to be the current Microsoft-recommended Azure-specific template engine for automating Infrastructure as Code deployments on Azure. Before experimenting with this you need:
- An active Azure subscription.
- A user with owner/contributor roles.
- A resource group.
Command Line VM Creation:
The easiest method to create a new VM is simply to use the az command. I created a resource group called "FreeBSD" and then looked for the latest FreeBSD image names:
To find a list of publishers of FreeBSD images you can use something like:
# az vm image list-publishers --location westus --output table|grep thefreebsdfoundation westus thefreebsdfoundation
To find "offers" and "skus" from this publisher:
# az vm image list-offers --location westus --publisher thefreebsdfoundation --output table #westus freebsd-13_2 # az vm image list-skus --location westus --publisher thefreebsdfoundation --offer freebsd-13_2 --output table #westus 13_2-release #az vm image list \ # --location westus \ # --publisher thefreebsdfoundation \ # --offer freebsd-13_2 \ # --sku 13_2-release \ # --all --output table #x64 freebsd-13_2 thefreebsdfoundation 13_2-release thefreebsdfoundation:freebsd-13_2:13_2-release:13.2.0 13.2.0
Once we have identified a specific FreeBSD image string, you can create a VM instance with:
az vm create --name MyFreeBSD13 --resource-group FreeBSD --image thefreebsdfoundation:freebsd-13_2:13_2-release:13.2.0 --admin-username murray --generate-ssh-keysResourceGroup PowerState PublicIpAddress Fqdns PrivateIpAddress MacAddress Location Zones --------------- ------------ ----------------- ------- ------------------ ----------------- ---------- ------- FreeBSD VM running 172.191.154.200 10.0.0.4 00-0D-3A-8B-22-FD eastus
Behind the scenes, Azure is creating a number of resources on my behalf in addition to the VM instance:
- A virtual network (VNET)
- A virtual network interface (VNIC)
- A public IPv4 address
- A network security group (stateful level 4 firewall rules)
- A persistent disk for the OS.
- The virtual machine
All of these are created in my specified "FreeBSD" resource group, and I can ssh directly into the new VM, start installing packages or configuring it with Ansible, and otherwise prepare it for my use case. However, using a template engine can allow us to provide more configuration details about the VM to control costs and control how the resources are deployed.
Windows Azure Linux Agent
One thing to notice about the VM is that there are some Python 3.9 processes running by default. These are for the Windows Azure Linux Agent running from /usr/local/sbin/waagent and is outside the scope of this post.
Bicep Automation
The recommended way to author and deploy Bicep configurations is with Visual Studio Code and the Bicep extension. This extension allows you to visualize the resource graph that will be created by the config, handle autocompletion of long Azure resource names, and lets you deploy a configuration.
@description('Location for all resources.') param location string = resourceGroup().location @description('Prefix to use for VM names') param vmNamePrefix string = 'BackendVM' @description('Size of the virtual machines') param vmSize string = 'Standard_D2s_v3' // Unique DNS Name for the Public IP used to access the Virtual Machine. @description('DNS Label Prefix for Public IP used by Azure to access the VM') param dnsLabelPrefix string = toLower('FreeBSD-${uniqueString(resourceGroup().id)}') var publicIPAddressName = 'FreeBSDPublicIP' var virtualNetworkName = 'FreeBSDVnet' var subnet1Name = 'FreeBSD-subnet-1' var subnetRef1 = resourceId('Microsoft.Network/virtualNetworks/subnets', virtualNetworkName, subnet1Name) var networkInterfaceName = 'nic' //var numberOfInstances = 2 resource virtualNetwork 'Microsoft.Network/virtualNetworks@2021-05-01' = { name: virtualNetworkName location: location properties: { addressSpace: { addressPrefixes: [ '10.0.0.0/16' ] } subnets: [ { name: subnet1Name properties: { addressPrefix: '10.0.0.0/24' } } ] } resource subnet1 'subnets' existing = { name: subnet1Name } } output subnet1ResourceId string = virtualNetwork::subnet1.id // public IP Address resource publicIP 'Microsoft.Network/publicIPAddresses@2020-06-01' = { name: publicIPAddressName location: location properties: { publicIPAllocationMethod: 'Dynamic' publicIPAddressVersion: 'IPv4' dnsSettings: { domainNameLabel: dnsLabelPrefix } idleTimeoutInMinutes: 4 } sku: { name: 'Basic' } } resource networkInterface1 'Microsoft.Network/networkInterfaces@2021-05-01' = { name: '${networkInterfaceName}1' location: location properties: { ipConfigurations: [ { name: 'ipconfig1' properties: { privateIPAllocationMethod: 'Dynamic' subnet: { id: subnetRef1 } publicIPAddress: { id: publicIP.id } } } ] } dependsOn: [ virtualNetwork ] } resource vm1 'Microsoft.Compute/virtualMachines@2021-11-01' = { name: '${vmNamePrefix}1' location: location plan: { name: '13_2-release' product: 'freebsd-13_2' publisher: 'thefreebsdfoundation' } properties: { hardwareProfile: { vmSize: vmSize } osProfile: { computerName: '${vmNamePrefix}1' adminUsername: 'murray' adminPassword: 'XXXXXXX' // Use SSH keys instead, for testing with hard-coded password need 6+ chars, one lower, one upper, one special character } storageProfile: { imageReference: { publisher: 'thefreebsdfoundation' offer: 'freebsd-13_2' sku: '13_2-release' version: '13.2.0' } osDisk: { createOption: 'FromImage' } } networkProfile: { networkInterfaces: [ { id: networkInterface1.id } ] } // diagnosticsProfile: { // bootDiagnostics: { // enabled: true // storageUri: storageAccount.properties.primaryEndpoints.blob // } // } } }
Thats it! The Azure docs cover myriad configuration parameters to customize all aspects of the network and VM deployment, but this basic template should get you started with FreeBSD in Azure.