Today, we’re going to talk about Bicep files. Just like its biological namesake, knowledge of Bicep is a very handy tool to arm yourself with (sorry, we couldn’t help ourselves!).
At its core, Bicep is a declarative language that you can use to simplify and speed up your deployment process to Azure in a reliable and consistent manner. You define the instructure you want to deploy Azure resources within a Bicep file.
The power is in your hands
Take control of your career. Get started with ACG and enhance your skillset with courses and real hands-on labs in AWS, Microsoft Azure, Google Cloud, and beyond.
What is repeatability?
There’s a lot to love about Infrastructure as Code, but one of its biggest benefits is repeatability. At its core, repeatability simply means being able to produce the exact same result from the same setup. The goal is that the code that you write should be able to be used and reused in various environments and scenarios.
How do we make our deployment files more reusable?
Some of the ways that we can make our deployment files become more reusable is with parameters and variables.
A parameter is used for prompting the user for a value when the code is executed. This way, you don’t have to hard code specific information into the deployment file.
Parameters would be used for values which would need to be updated every time the deployment file is run.
Variables on the other hand, are used to assign a specific value that can be reused over and over again through the deployment file. Unlike parameters, variables are used when the values change rarely. But if they did need to change, instead of updating each value in the file, you only need to update the variable, and all the references to that variable will have that value as well.
Parameters and variables can hold multiple kinds of data such as strings, integers, arrays and even objects with layers of properties.
How do parameters and variables apply to writing Bicep files?
By using these two tools, parameters and variables, we can make a bicep file adaptable to many situations.
I will walk through how you can write a Bicep file to deploy a virtual machine with either a Windows OS or a Linux OS, all based on the input of a user. Once the file is deployed, the user will be asked if the VM should be Windows or Linux, and then based on the response, the bicep file will know what properties to use to deploy that OS.
Creating a parameter
Let’s start with creating a parameter to ask the user if they want to deploy a Windows VM or a Linux VM. In Bicep, the way that a parameter is declared is by using the following syntax:
“param <name of parameter> <type of parameter data>”
As we can see from the snippet below, we are naming the parameter “windowsOrlinux” to let the user running the deployment know that they should choose which OS to select.
To add a little more context to how this parameter is being used, we also have the “description” decorator. In addition, we also have the “allowed” decorator. This is used to specify that only this list of specific values, “windows” or “linux”, will be accepted for the parameter. If another value is used, there will be an error letting you know that the deployment file is invalid, as only certain values are allowed to be used for this parameter.
Creating a variable object
Now that the user has selected which OS they want to be used for the VM, the next step is to add logic into the deployment file to figure out which image configurations to use based on that selection. The way we can do that is by creating a variable object such as the one below:
Declaring a variable
Before we go over how a variable object works, let us quickly go over how to declare a variable. You can simply use the following syntax:
“var <name of variable> = <value of variable>”
When it comes to the value of the variable, in many situations this will just be a singular value such as an integer or a string. This can be done by hardcoding the values or by utilizing functions to generate the values.
Alternatively, you can store an object as the value which can hold multiple values with layers of information. This will often be used in a situation such as the one here, where you are saving configuration data.
So in our snippet, we can see that we are storing two values of “windows” and “linux” listed within curly brackets. Then, within those values, there are properties such as publisher, offer, sku and version all wrapped up in their own set of curly brackets. Along with those properties, are the specific configuration values for those properties. In our example we are using a Windows 2019 Datacenter image or an Ubuntu 18.04 image.
Image reference properties
So now we have the parameter which will store either a value of “linux” or “windows” and an image variable with the relevant configurations. But how do they come together? How does the template know that if the parameter value is “windows” that it needs to use the windows configurations in the image variable? And vice versa with a “linux” value? Below, we have a snippet of the VM resource declaration focusing on the image reference properties in the storage profile section.
When looking at this snippet, the first thing you might notice is that the image reference properties of publisher, offer, sku and version match the properties saved in the image variable that was configured above.
Let’s move on to property values.
Look at the same snippet in closer detail, we first have a reference to the “image” variable and then at the end we can see that there is a period, followed by the corresponding object property. For example, if the value for “image” was “linux”, the value for the “offer” sub-property, would be “UbuntuServer”. Otherwise, if the value for “image” was “windows”, the value for the “offer” sub-property would be “WindowsServer”.
So how does the template know which value for “image” to choose? That is where the “windowsOrLinux” parameter comes in. After the “image” variable, the “windowsOrLinux” parameter is referenced in brackets to say that the value for the “image” variable is chosen based on the value of the parameter in brackets.
This is why it was so important to add an allowed values decorator to the parameter, because we had to make sure that the parameter values matched the values in the variable object. So now, when this file is being deployed, the user will select either “windows” or “linux” when the parameter prompts them. That parameter will then be used to specify which data in the “image” variable object to use for the publisher, offer, sku and version property values.
Conclusion and next steps
This was just one of many ways that a deployment file can be authored to make it adaptable to multiple situations. There are other tools and strategies that can be utilized such as functions and modules. However, as we have seen from the example above, while each one of these strategies can be helpful on their own to increase repeatability, they can be even more effective when combined together.
If you’d like to reference the full Bicep file referenced in this article, you can find this here.
If you’ve found this walkthrough interesting and want to learn more about Bicep and how to more efficiently deploy and manage Azure resources, check out my course Introduction to Azure Resource Manager.