Skip to content
Niklas Forsbäck edited this page Jan 6, 2023 · 28 revisions

Bicep deployments using YAML based variables (Azure, DevOps, Bicep)

Intro

Bicep deployments are typically done using one parameter file that maps directly to the Bicep file. Each parameter file needs to have exact parameter match for the deployment to succeed. This leads to a situation where parameter files are hard to share for other deployments. Variables can be used instead of parameters. It has both advantages and some drawbacks such as secure parameters. The advantage is that you can create a variable file which is shared between multiple related deployments. This makes it easier to implement modular deployments. Using a YAML based variable definition makes the variable file easier to maintain, as it is more human readable than the JSON format. We will be using MS provided Bicep resource modules in the example (https://github.com/Azure/ResourceModules). These contains extensive and well defined Bicep templates with related documenation. A typical landing zone scenario with virtual network provisioning is presented.

YAML based variables

YAML variables need to be converted to JSON notation before they can be used in the deployment. Yq is a standalone program that can be used to convert variable files for the deployment.

# Part of pipeline Bash task
yq -P variables-dev.yml -o json > bicep-variables.json

Bicep supports loading of JSON variable files. It is possible to further point deeper into the JSON properties, but this is omitted here for simplicity.

// main.bicep
param landingZone object = loadJsonContent('bicep-variables.json') // Generated by yq converter (YAML-> JSON)loadJsonContent('bicep-variables.json')
param vnetName string = landingZone.vnet.name  // Reads from bicep-variables.json properties

Shared variables between pipeline and bicep deployments

YAML variables with more complex data structures cannot be used as template file for the pipeline or scripts. A separate YAML template file can be used for these scenarios. Only string, boolean and numbers are supported for variable templates. An example would be a vnet resource group name from the template variable file. This variable is shared between e.g. pipline CLI/PS tasks and bicep deployments.

// file bicep-variables-dev.yml, converted to json as part of pipeline execution
#DEV
vnet:
  name: vnetTest
...

// file template-variables.yml, converted to json as part of pipeline execution
variables:
  vnetResourceGroup: vnet-dev-rg
...

// main.bicep
loadJsonContent('template-variables.json')   // Shared YAML variables for scripts and bicep deployments converted to JSON
loadJsonContent('bicep-variables.json')  // Only for bicep deployments

param vnetName string = landingZone.vnet.name  // Reads from bicep-variables.json properties
param vnetResourceGroup string = variables.vnetResourceGroup // Reads from template-variables.json file. 
                                                             // Note that variables has to be the root property in this case. 
                                                             // Otherwise it cannot be used as template variable for scripts at pipeline level. 

One other alternative is to have a special section in the landing zone related YAML file and extract those variables and create a new file with simple YAML notation (with variables root property). Please refer to yq documention in [1] for more information.

YAML template file string interpolation in bicep deployments

String interpolation in a template file can also be used. The values needs to be given before pipeline execution, as in the example below. These have higher priority in deployments, see example below. Both pipeline parameters and pipeline UI variables can be used. YAML variables containing string interpolation expression are not usable for JSON conversion. Template literal expression syntax has no meaning in the JSON context.

# file template-variables.yml
parameters:
  env: ''
variables:
  vnetResourceGroup: vnet-${{ parameters.env }}-rg
...


# file azure-pipelines.yml
parameters:
- name: env
  values:
  - dev
  - qa   
  - prod

variables:
- template: template-variables.yml # Simple notation in template variable file.
    env:  ${{parameters.env}} 
...
# Part of pipeline CLI task
az deployment group create \
      --resource-group ${{ variables.vnetResourceGroup }} \ // This will override previous RG Name if given.
      --template-file main.bicep 

Example

The DevOps repository contains an example of vnet provisioning using MS provided bicep resource modules. YAML based variables are converted to JSON and loaded into the bicep main file. Everything is in one directory for simplicity reasons.

Concusions

Advantages

Modular and sharable variable files are easier to maintain across different deployments. Readability is improved when using YAML format as a source for the variable definitions.

Drawbacks

In some cases a separate parameter file might be needed. It would only contain a few parameters.

References

  1. Bicep resource modules, https://github.com/Azure/ResourceModules
  2. yq, yaml <-> json converter, https://github.com/mikefarah/yq

Clone this wiki locally