Deploying Geneos on Azure Resource Manager using Bicep

Azure offers native IaC support through the Azure Resource Manager.

This guide outlines how to deploy Geneos components using Bicep templates and Azure Resource Manager Stacks.

Prerequisites Copied

  1. Azure CLI installed
    Install from Azure
  2. Bicep CLI installed

Note

This is normally bundled with the Azure CLI installation.
```bash
az bicep install
```
  1. Logged in from CLI

    az login
    
  2. Storage account and key vault storing the Geneos resources

    • Geneos component tarball file
    • Configuration file
    • Service file

Deployment commands Copied

Use the following az stack group commands to manage Deployment Stacks at resource group.

Create or update a deployment stack Copied

Configure bicep templates and parameters.

az stack group create \
  --name <StackName> \
  --resource-group <ResourceGroup> \
  --template-file <BicepFile> \
  --parameters <BicepParameters> \
  --action-on-unmanage deleteAll \
  --deny-settings-mode none

For example:

az stack group create \
  --name NetprobeStack \
  --resource-group DeploymentGroup \
  --template-file main.bicep \
  --parameters .\resources\netprobe\netprobe_params.bicepparam \
  --action-on-unmanage deleteAll \
  --deny-settings-mode none

Show public IP addresses of virtual machines in the deployment stack Copied

az stack group show \
  --name <StackName> \
  --resource-group <ResourceGroup> \
  --query "outputs.virtualMachinePublicIps.value" \
  --output table

For example:

  --name NetprobeStack \
  --resource-group DeploymentGroup \
  --query "outputs.virtualMachinePublicIps.value" \
  --output table

Delete the deployment stack Copied

az stack group delete \
  --name <StackName> \
  --resource-group <ResourceGroup> \
  --action-on-unmanage deleteAll

For example:

az stack group delete \
  --name NetprobeStack \
  --resource-group DeploymentGroup \
  --action-on-unmanage deleteAll

Template file Copied

Several template files are available which can be used depending on your provisioning goal.

Can we add the diagram in the docs?

Template file Description
main.bicep Main template file that will provision all the necessary resources for a new Virtual Machine along with a Geneos component.
NetworkSecurityGroup.bicep Used for provisioning a Network Security Group.
VirtualNetwork.bicep Used for provisioning a Virtual Network.
PublicIP.bicep Used for provisioning a Public IP Address.
NetworkInterface.bicep Used for provisioning a Network Interface.
VirtualMachine.bicep Used for provisioning a Virtual Machine.
RunCommand.bicep Used to run a command within the Virtual Machine (ex. Java Installation).
Geneos.bicep Used to deploy Geneos components within the Virtual Machine.

Parameters Copied

Reference parameters are already provided and can be found in the following paths:

Network Security Group Copied

targetScope = 'resourceGroup'

@description('Name of the network security group.')
param networkSecurityGroupName string
@description('TCP inbound destination port ranges for the network security group.')
param networkSecurityGroupTcpInboundDestinationPorts array = []
@description('Tags to apply to the network security group.')
param tags object = {}

resource nsg 'Microsoft.Network/networkSecurityGroups@2024-07-01' = {
  name: networkSecurityGroupName
  location: resourceGroup().location
  properties: {
    securityRules: [
      {
        name: 'AllowInboundTcp'
        properties: {
          protocol: 'Tcp'
          sourcePortRange: '*'
          destinationPortRanges: networkSecurityGroupTcpInboundDestinationPorts
          sourceAddressPrefix: '*'
          destinationAddressPrefix: '*'
          access: 'Allow'
          priority: 1000
          direction: 'Inbound'
        }
      }
    ]
  }
  tags: tags
}

output networkSecurityGroupId string = nsg.id
Parameter Description
networkSecurityGroupName Name of the network security group.

Note

The instance count will be automatically appended.
networkSecurityGroupTcpInboundDestinationPorts TCP inbound destination port ranges for the network security group.

Virtual Network Copied

targetScope = 'resourceGroup'

@description('Name of the virtual network.')
param virtualNetworkName string
@description('Address prefixes for the virtual network.')
param virtualNetworkAddressPrefixes array = []
@description('Address prefixes for the virtual network subnets.')
param virtualNetworkAddressPrefixesSubnet array = []
@description('Tags to apply to the virtual network.')
param tags object = {}

var subnetName = '${virtualNetworkName}-subnet'

resource vnet 'Microsoft.Network/virtualNetworks@2024-07-01' = {
  name: virtualNetworkName
  location: resourceGroup().location
  properties: {
    addressSpace: {
      addressPrefixes: virtualNetworkAddressPrefixes
    }
    subnets: [
      {
        name: subnetName
        properties: {
          addressPrefixes: virtualNetworkAddressPrefixesSubnet
        }
      }
    ]
  }
  tags: tags
}

output virtualNetworkId string = vnet.id
output virtualNetworkSubnetId string = '${vnet.id}/subnets/${subnetName}'
Parameter Description
virtualNetworkName Name of the virtual network.

Note

The instance count will be automatically appended.
virtualNetworkAddressPrefixes Address prefixes for the virtual network.
virtualNetworkAddressPrefixesSubnet Address prefixes for the virtual network subnets.

Public IP Address Copied

targetScope = 'resourceGroup'

@description('Name of the public IP address.')
param publicIpAddressName string
@description('SKU of the public IP address.')
param publicIpAddressSku string
@description('Type of the public IP address.')
param publicIpAddressType string
@description('Zones for the public IP address.')
param publicIpAddressZone array = []
@description('Tags to apply to the public IP address.')
param tags object = {}

resource pip 'Microsoft.Network/publicIPAddresses@2024-07-01' = {
  name: publicIpAddressName
  location: resourceGroup().location
  sku: {
    name: publicIpAddressSku
  }
  properties: {
    publicIPAllocationMethod: publicIpAddressType
  }
  zones: publicIpAddressZone
  tags: tags
}

output publicIpAddressId string = pip.id
output publicIpAddress string = pip.properties.ipAddress
Parameter Description
publicIpAddressName Name of the public IP address.

Note

The instance count will be automatically appended.
publicIpAddressSku SKU of the public IP address.
publicIpAddressType Type of the public IP address.
publicIpAddressZone Zones for the public IP address.

Network Interface Copied

targetScope = 'resourceGroup'

@description('Name of the network interface.')
param networkInterfaceName string
@description('ID of the network security group to associate with the network interface.')
param networkSecurityGroupId string
@description('ID of the public IP address to associate with the network interface.')
param publicIpAddressId string
@description('ID of the virtual network subnet to associate with the network interface.')
param virtualNetworkSubnetId string
@description('Tags to apply to the network interface.')
param tags object = {}

var ipConfigName = '${networkInterfaceName}-ipconfig'

resource nic 'Microsoft.Network/networkInterfaces@2024-07-01' = {
  name: networkInterfaceName
  location: resourceGroup().location
  properties: {
    ipConfigurations: [
      {
        name: ipConfigName
        properties: {
          subnet: {
            id: virtualNetworkSubnetId
          }
          privateIPAllocationMethod: 'Dynamic'
          publicIPAddress: {
            id: publicIpAddressId
            properties: {
              deleteOption: 'Delete'
            }
          }
        }
      }
    ]
    networkSecurityGroup: {
      id: networkSecurityGroupId
    }
  }
  tags: tags
}

output networkInterfaceId string = nic.id
Parameter Description
networkInterfaceName Name of the network interface.

Note

The instance count will be automatically appended.

Key Vault Copied

Parameter Description
keyVaultName Name of the Key Vault to retrieve secrets and files from.

Virtual Machine Copied

targetScope = 'resourceGroup'

@description('Name of the virtual machine.')
param virtualMachineName string
@description('Availability zones for the virtual machine.')
param virtualMachineZone array = []
@description('Size of the virtual machine.')
param virtualMachineSize string
@description('OS disk type for the virtual machine.')
param virtualMachineOsDiskType string
@description('Image offer for the virtual machine.')
param virtualMachineImageOffer string
@description('Image SKU for the virtual machine.')
param virtualMachineImageSku string
@description('Image version for the virtual machine.')
param virtualMachineImageVersion string
@description('Admin username for the virtual machine.')
param virtualMachineAdminUser string
@secure()
@description('Admin password for the virtual machine.')
param virtualMachineAdminPassword string
@description('ID of the network interface to attach to the virtual machine.')
param networkInterfaceId string
@description('Tags to apply to the virtual machine.')
param tags object = {}

resource vm 'Microsoft.Compute/virtualMachines@2024-11-01' = {
  name: virtualMachineName
  location: resourceGroup().location
  zones: virtualMachineZone
  properties: {
    hardwareProfile: {
      vmSize: virtualMachineSize
    }
    storageProfile: {
      osDisk: {
        createOption: 'fromImage'
        managedDisk: {
          storageAccountType: virtualMachineOsDiskType
        }
        deleteOption: 'Delete'
      }
      imageReference: {
        publisher: 'canonical'
        offer: virtualMachineImageOffer
        sku: virtualMachineImageSku
        version: virtualMachineImageVersion
      }
    }
    networkProfile: {
      networkInterfaces: [
        {
          id: networkInterfaceId
          properties: {
            deleteOption: 'Delete'
          }
        }
      ]
    }
    securityProfile: {
      securityType: 'TrustedLaunch'
      uefiSettings: {
        secureBootEnabled: true
        vTpmEnabled: true
      }
    }
    additionalCapabilities: {
      hibernationEnabled: false
    }
    osProfile: {
      computerName: virtualMachineName
      adminUsername: virtualMachineAdminUser
      adminPassword: virtualMachineAdminPassword
      linuxConfiguration: {
        disablePasswordAuthentication: false
        patchSettings: {
          assessmentMode: 'ImageDefault'
          patchMode: 'ImageDefault'
        }
      }
    }
  }
  tags: tags
}

output virtualMachineId string = vm.id
output virtualMachineName string = vm.name
Parameter Description
virtualMachineName Name of the virtual machine.

Note

The instance count will be automatically appended.
virtualMachineZone Availability zones for the virtual machine.
virtualMachineSize Size of the virtual machine.
virtualMachineOsDiskType OS disk type for the virtual machine.
virtualMachineImageOffer Image offer for the virtual machine.
virtualMachineImageSku Image SKU for the virtual machine.
virtualMachineImageVersion Image version for the virtual machine.
virtualMachineAdminUser Admin username for the virtual machine.
keyVaultKeyNameForAdminPass Key Vault key name for the admin password.

Run Command Copied

targetScope = 'resourceGroup'

@description('Name of the run command.')
param runCommandName string
@description('Name of the virtual machine.')
param virtualMachineName string
@description('Command to run.')
param commandToRun string

resource command 'Microsoft.Compute/virtualMachines/runCommands@2024-11-01' = {
  name: '${virtualMachineName}/${runCommandName}'
  location: resourceGroup().location
  properties: {
    asyncExecution: false
    source: {
      script: commandToRun
    }
    timeoutInSeconds: 300
  }
}
Parameter Description
installJavaCommand Command to execute for Java installation

Geneos Copied

targetScope = 'resourceGroup'

@description('Name of the Geneos deployment.')
param geneosDeploymentName string
@description('Name of the virtual machine.')
param virtualMachineName string
@description('Binary URL in data storage.')
param binaryUrlInDataStorage string
@description('Configuration URL in data storage.')
param configUrlInDataStorage string
@description('Service URL in data storage.')
param serviceUrlInDataStorage string

@secure()
@description('SAS token of data storage.')
param sasToken string

var binaryUrl = !empty(binaryUrlInDataStorage) ? '${binaryUrlInDataStorage}?${sasToken}' : ''
var binaryScript = !empty(binaryUrlInDataStorage) ? '''
tar -xvzf geneos-*.tar.gz -C /opt
''' : ''

var configUrl = !empty(configUrlInDataStorage) ? '${configUrlInDataStorage}?${sasToken}' : ''
var configScript = !empty(configUrlInDataStorage) ?'''
mkdir -p /opt/config && cp *.xml /opt/config
''' : ''

var serviceUrl = !empty(serviceUrlInDataStorage) ? '${serviceUrlInDataStorage}?${sasToken}' : ''
var serviceScript = !empty(serviceUrlInDataStorage) ? '''
svc=$(basename *.service)
cp "$svc" /etc/systemd/system/
systemctl daemon-reload
systemctl enable "$svc"
systemctl start "$svc"
''' : ''

resource extension 'Microsoft.Compute/virtualMachines/extensions@2024-11-01' = {
  name: '${virtualMachineName}/${geneosDeploymentName}'
  location: resourceGroup().location
  properties: {
    publisher: 'Microsoft.Azure.Extensions'
    type: 'CustomScript'
    typeHandlerVersion: '2.1'
    settings: {
      fileUris: [
        binaryUrl
        configUrl
        serviceUrl
      ]
      commandToExecute: '${binaryScript}\n${configScript}\n${serviceScript}'
    }
  }
}
Parameter Description
binaryUrlInDataStorage Binary URL in data storage.
configUrlInDataStorage Configuration URL in data storage.
serviceUrlInDataStorage Service URL in data storage.
keyVaultKeyNameForSasToken Key Vault key name for the SAS token.

General Copied

Parameter Description
tags Tags to apply to all resources.
vmCount Number of virtual machines to deploy.
["Geneos"] ["Geneos > Netprobe"] ["User Guide"]

Was this topic helpful?