This article assumes that you are familiar – have heard of - with infrastructure as Code (IaC) technologies such as Terraform, Pulumi, ARM Templates for Azure, then you already understand where to use Bicep: To create Azure resources natively without having to muck with JSON.
[Aside for non-native English speakers: Your arm 🙋♂️ & bicep💪 , got it? 😁]
Here’s how easy bicep is to grok:
targetScope = 'resourceGroup/Subscription/Management Group/Tenant>'
resource <symbolicName> ‘namespace provider@apiVersion’ = {
name: <the name you want to give your resource>
location: <where to deploy>
}
targetScope = 'resourceGroup'
resource virtualMachine 'Microsoft.Compute/virtualMachines@2022-03-01' = {
location: 'eastus'
name: 'vm-poc-srv-dev-001'
}
The above only requires you to know what resources that you want to deploy (A SQL database, an App Service or any of the hundreds of services that Azure supports), and the version number of the provider (usually, the latest). VSCode has great intellisense support.
What Do We Need? – Becoming a Newbie
Item Required | How to find |
Provider Name |
|
Versions Supported |
az provider list –query ‘[*].{namespace: namespace, apiVersion: resourceTypes[].apiVersions[]}’ |
The Latest Version |
az provider list --query '[*].{namespace: namespace, apiVersion: resourceTypes[].apiVersions[] | [0]}'
|
Required Properties |
resource storageAccount 'Microsoft.Storage/storageAccount@2022-05-01' = { }
|
List of all Properties |
|
What each property means | Azure Deployment Reference |
What are the other resources this resource depends on? |
az bicep decompile -f template.json
|
How to find a quick snippet of working Bicep for the resource |
|
Execute the Bicep Script | az deployment group create -g <name> -l <location> -f poc.bicep |
Execute the Bicep Script with Parameters | az deployment group create -g <name> -l <location> -f poc.bicep -p poc.parameters.json |
Beyond ‘Hello World’ – Becoming an Intermediate
OK. You have everything you ever need and started writing bicep code. However, VS Code starts complaining that you’re hardcoding values and you need ‘Parameters’.
Parameters & default values |
|
Execute the Bicep Script passing parameters from an external parameters file | az deployment group create -g <name> -l <location> -f poc.bicep -p poc.parameters.json |
Variables |
|
Functions that can only be used in parameter assignments | utcNow(), newGuid() |
Reach for the Skies - Becoming Advance
Minimum functions you’d need | resourceGroup().location
utcNow()
uniqueString(utcNow())
newGuid()
format(‘{0}-{1}-{2}’, var1, var2, var3) |
resource publicIpAddress 'Microsoft.Network/publicIPAddresses@2022-01-01' = if (attachPublicIP) {
name: 'pip-${nameSuffix}'
location: location
tags: coreTags
} | |
param itemCount int = 5
var stringArray = [for i in range(0, itemCount): 'item${(i + 1)}']
output arrayResult array = stringArray | |
Operators | (isPublic)? <true expression>: <false expression> |
Shoot for the moon – Becoming an Expert
Reuse Bicep files using Modules | module clientVM 'vm.windows.desktop.bicep' = {
name: 'windowsClientVM'
params: {
env: env
location: location
}
} |
Best Practices
While the base format of the language is very simple, using bicep emphasizing reuse, testability and modularity requires some thought and upfront planning.
Here’re the best practices I distilled, painstakingly assembled: 😉
A single or group (more typical) of bicep files are written for a “Project”
Follow the AZ naming convention from the CAF (for the most part except where the service barfs saying it can’t exceed ‘xx’ characters) for naming resources
Your entry point should always be main. Bicep
Makes it easy for someone to find the entry point quickly
Always assume your script would be used to create multiple environments
So, an execution always creates an environment for your project
Environments can be DEV, QA, INTG, STAGE, PROD or DEMO
It doesn’t matter what it’s called for the most part
Your scripts should never hard code any environment names except may be in the config files (which will be generated by the pipeline)
Always assume the default location where the Azure resources to be created will be dictated by the user
It may even change per environment
Follow lower case naming conventions for bicep
File name should be all lower case ending with the extension .bicep
Separate words with a hyphen: network-interface. Bicep
Typical parameters to consider for the main.bicep
env - The environment
projectName - The project this environment belongs to
location
coreTags
Parameters generally should not have default values
You should have a *.parameters.json for all your default parameters you want to debug the bicep file with
Every core azure service required must be in a separate file
network. Bicep
nsg.bicep
network-interface.bicep
Bicep files can refer / include other bicep files using 'modules' syntax
The overall structure of your bicep file should be:
Parameters
Variables
Global Config Module
Shared Modules
vnet
Every core azure service decled should belong to a component / service in your project
If you’re working to create
Create a nameSuffix & a nameSuffixShort
nameSuffixShort should denote items belonging at the project level (such as VNET). Example can be vnet-poc-dev-001
nameSuffix should include component. Example: plan-poc-wfe-dev-001
WFE == ‘Web Front End’
Always assume you’re just a node in the toolchain
Just because the pipeline supplied the password doesn’t mean the app might know it
Some output values generated by the core azure services such as the URL for an App Service etc. must be output as output variables
Put generated values that in a shared Key Vault
Comments