-
Notifications
You must be signed in to change notification settings - Fork 456
Solution creation
This section shows you how you can orchestrate a deployment using multiple resource modules.
Note: For the sake of the below examples we assume you leverage Bicep as your primary DSL.
When it comes to environment deployment leveraging modules, we can differentiate two different orchestrations:
-
Template-orchestration: These types of deployments reference individual modules from a 'main/environment' Bicep or ARM/JSON template and use its capabilities to pass parameters & orchestrate the deployments. By default, deployments are run in parallel by the Azure Resource Manager while accounting for all dependencies defined. Furthermore, the deploying pipeline only needs one deployment job that triggers the template's deployment.
-
Pipeline-orchestration: This approach uses the platform specific pipeline capabilities (for example pipeline jobs) to trigger the deployment of individual modules, where each job deploys one module. By defining dependencies in between jobs you can make sure your resources are deployed in order. Parallelization is achieved by using a pool of pipeline agents that execute the jobs, while accounting for all dependencies defined. Both the template-orchestration as well as pipeline-orchestration may run a validation and subsequent deployment on the bottom-right Azure subscription. This subscription, in turn, should be the subscription where you want to host your environment. However, you can extend the concept and for example deploy the environment first to an integration and then a production subscription.
The template-orchestrated approach means using a main or so-called master template for deploying resources in Azure. This template will only contain nested deployments, where the modules - instead of embedding their content into the master template - will be referenced by the master template.
With this approach, modules need to be stored in an available location, where the Azure Resource Manager (ARM) can access them. This can be achieved by storing the modules templates in an accessible location like local, Template Specs or the Bicep Registry.
In an enterprise environment, the recommended approach is to store these templates in a private environment, only accessible by enterprise resources. Thus, only trusted authorities can have access to these files.
The following example shows how you could orchestrate a deployment of multiple resources using local module references. In this example we will deploy a resource group with a contained NSG and use the same in a subsequent VNET deployment.
targetScope = 'subscription'
// ================ //
// Input Parameters //
// ================ //
// RG parameters
@description('Optional. The name of the resource group to deploy')
param resourceGroupName string = 'validation-rg'
@description('Optional. The location to deploy into')
param location string = deployment().location
// NSG parameters
@description('Optional. The name of the vnet to deploy')
param networkSecurityGroupName string = 'BicepRegistryDemoNsg'
// VNET parameters
@description('Optional. The name of the vnet to deploy')
param vnetName string = 'BicepRegistryDemoVnet'
@description('Optional. An Array of 1 or more IP Address Prefixes for the Virtual Network.')
param vNetAddressPrefixes array = [
'10.0.0.0/16'
]
@description('Optional. An Array of subnets to deploy to the Virual Network.')
param subnets array = [
{
name: 'PrimarySubnet'
addressPrefix: '10.0.0.0/24'
networkSecurityGroupName: networkSecurityGroupName
}
{
name: 'SecondarySubnet'
addressPrefix: '10.0.1.0/24'
networkSecurityGroupName: networkSecurityGroupName
}
]
// =========== //
// Deployments //
// =========== //
// Resource Group
module rg '../arm/Microsoft.Resources/resourceGroups/deploy.bicep' = {
name: 'registry-rg'
params: {
name: resourceGroupName
location: location
}
}
// Network Security Group
module nsg '../arm/Microsoft.Network/networkSecurityGroups/deploy.bicep' = {
name: 'registry-nsg'
scope: resourceGroup(resourceGroupName)
params: {
name: networkSecurityGroupName
}
dependsOn: [
rg
]
}
// Virtual Network
module vnet '../arm/Microsoft.Network/virtualNetworks/deploy.bicep' = {
name: 'registry-vnet'
scope: resourceGroup(resourceGroupName)
params: {
name: vnetName
addressPrefixes: vNetAddressPrefixes
subnets: subnets
}
dependsOn: [
nsg
rg
]
}
The following example shows how you could orchestrate a deployment of multiple resources using modules from a private Bicep Registry. In this example we will deploy a resource group with a contained NSG and use the same in a subsequent VNET deployment.
Note: the preferred method to publish modules to the Bicep registry is to leverage our CI environment. However, this option may not be applicable to all scenarios (ref e.g. the Consume library section). As an alternative, the same Publish-ModuleToPrivateBicepRegistry.ps1 script leveraged by the publishing step of the CI environment pipeline can also be executed locally.
targetScope = 'subscription'
// ================ //
// Input Parameters //
// ================ //
// RG parameters
@description('Optional. The name of the resource group to deploy')
param resourceGroupName string = 'validation-rg'
@description('Optional. The location to deploy into')
param location string = deployment().location
// NSG parameters
@description('Optional. The name of the vnet to deploy')
param networkSecurityGroupName string = 'BicepRegistryDemoNsg'
// VNET parameters
@description('Optional. The name of the vnet to deploy')
param vnetName string = 'BicepRegistryDemoVnet'
@description('Optional. An Array of 1 or more IP Address Prefixes for the Virtual Network.')
param vNetAddressPrefixes array = [
'10.0.0.0/16'
]
@description('Optional. An Array of subnets to deploy to the Virual Network.')
param subnets array = [
{
name: 'PrimarySubnet'
addressPrefix: '10.0.0.0/24'
networkSecurityGroupName: networkSecurityGroupName
}
{
name: 'SecondarySubnet'
addressPrefix: '10.0.1.0/24'
networkSecurityGroupName: networkSecurityGroupName
}
]
// =========== //
// Deployments //
// =========== //
// Resource Group
module rg 'br/modules:microsoft.resources.resourcegroups:0.4.735' = {
name: 'registry-rg'
params: {
name: resourceGroupName
location: location
}
}
// Network Security Group
module nsg 'br/modules:microsoft.network.networksecuritygroups:0.4.735' = {
name: 'registry-nsg'
scope: resourceGroup(resourceGroupName)
params: {
name: networkSecurityGroupName
}
dependsOn: [
rg
]
}
// Virtual Network
module vnet 'br/modules:microsoft.network.virtualnetworks:0.4.735' = {
name: 'registry-vnet'
scope: resourceGroup(resourceGroupName)
params: {
name: vnetName
addressPrefixes: vNetAddressPrefixes
subnets: subnets
}
dependsOn: [
nsg
rg
]
}
The example assumes you are using a bicepconfig.json
configuration file like:
{
"moduleAliases": {
"br": {
"modules": {
"registry": "<registryName>.azurecr.io",
"modulePath": "bicep/modules"
}
}
}
}
The following example shows how you could orchestrate a deployment of multiple resources using template specs. In this example we will deploy a NSG and use the same in a subsequent VNET deployment.
Note: the preferred method to publish modules to template-specs is to leverage our CI environment. However, this option may not be applicable to all scenarios (ref e.g. the Consume library section). As an alternative, the same Publish-ModuleToTemplateSpec.ps1 script leveraged by the publishing step of the CI environment pipeline can also be executed locally.
targetScope = 'subscription'
// ================ //
// Input Parameters //
// ================ //
// RG parameters
@description('Optional. The name of the resource group to deploy')
param resourceGroupName string = 'validation-rg'
@description('Optional. The location to deploy into')
param location string = deployment().location
// Network Security Group parameters
@description('Optional. The name of the vnet to deploy')
param networkSecurityGroupName string = 'TemplateSpecDemoNsg'
// Virtual Network parameters
@description('Optional. The name of the vnet to deploy')
param vnetName string = 'TemplateSpecDemoVnet'
@description('Optional. An Array of 1 or more IP Address Prefixes for the Virtual Network.')
param vNetAddressPrefixes array = [
'10.0.0.0/16'
]
@description('Optional. An Array of subnets to deploy to the Virual Network.')
param subnets array = [
{
name: 'PrimarySubnet'
addressPrefix: '10.0.0.0/24'
networkSecurityGroupName: networkSecurityGroupName
}
{
name: 'SecondarySubnet'
addressPrefix: '10.0.1.0/24'
networkSecurityGroupName: networkSecurityGroupName
}
]
// =========== //
// Deployments //
// =========== //
// Resource Group
module rg 'ts/modules:microsoft.resources.resourcegroups:0.4.735' = {
name: 'rgDeployment'
params: {
name: resourceGroupName
location: location
}
}
// Network Security Group
module nsg 'ts/modules:microsoft.network.networksecuritygroups:0.4.735' = {
name: 'nsgDeployment'
scope: resourceGroup(resourceGroupName)
params: {
name: networkSecurityGroupName
}
dependsOn: [
rg
]
}
// Virtual Network
module vnet 'ts/modules:microsoft.network.virtualnetworks:0.4.735' = {
name: 'vnetDeployment'
scope: resourceGroup(resourceGroupName)
params: {
name: vnetName
addressPrefixes: vNetAddressPrefixes
subnets : subnets
}
dependsOn: [
rg
nsg
]
}
The example assumes you are using a bicepconfig.json
configuration file like:
{
"moduleAliases": {
"ts": {
"modules": {
"subscription": "<<subscriptionId>>",
"resourceGroup": "artifacts-rg"
}
}
}
}
The modules provided by this repo can be orchestrated to create more complex infrastructures and as such reusable solutions or products. This approach leverages the main 'ResourceModules' repository alongside its contained modules & pipeline templates to deploy resources. Each pipeline job deploys one instance of a resources and their order is controlled by specifying dependencies in the pipeline itself.
- Below you can find an example which uses makes use of multiple repositories to orchestrate the deployment (also known as a multi-repository approach) in GitHub
- It fetches the public Azure/ResourceModules repo for consuming bicep modules and uses the parameter files present in the private Contoso/MultiRepoTest repo for deploying infrastructure
- This example is creating a Resource group, an NSG and a VNet -
- Job: Deploy multi-repo solution
- Checkout 'Azure/ResourceModules' repo at root of the agent
- Set environment variables for the agent
- Checkout 'contoso/MultiRepoTest' repo containing the parameter files in a nested folder - "MultiRepoTestParentFolder"
- Deploy resource group in target Azure subscription
- Deploy network security group
- Deploy virtual network A
- Job: Deploy multi-repo solution
name: 'Multi-Repo solution deployment'
on:
push:
branches:
- main
paths:
- 'network-hub-rg/Parameters/**'
- '.github/workflows/network-hub.yml'
env:
AZURE_CREDENTIALS: ${{ secrets.AZURE_CREDENTIALS }}
removeDeployment: false
jobs:
job_deploy_multi_repo_solution:
runs-on: ubuntu-20.04
name: 'Deploy multi-repo solution'
steps:
- name: 'Checkout ResourceModules repo at the root location'
uses: actions/checkout@v2
with:
repository: 'Azure/ResourceModules'
fetch-depth: 0
- name: 'Set environment variables'
uses: deep-mm/set-variables@v1.0
with:
variableFileName: 'global.variables'
- name: 'Checkout MultiRepoTest repo in a nested MultiRepoTestParentFolder'
uses: actions/checkout@v2
with:
repository: 'contoso/MultiRepoTest'
fetch-depth: 0
path: 'MultiRepoTestParentFolder'
- name: 'Deploy resource group'
uses: ./.github/actions/templates/validateModuleDeployment
with:
templateFilePath: './arm/Microsoft.Resources/resourceGroups/deploy.bicep'
parameterFilePath: './MultiRepoTestParentFolder/network-hub-rg/Parameters/ResourceGroup/parameters.json'
location: '${{ env.defaultLocation }}'
resourceGroupName: '${{ env.resourceGroupName }}'
subscriptionId: '${{ secrets.ARM_SUBSCRIPTION_ID }}'
managementGroupId: '${{ secrets.ARM_MGMTGROUP_ID }}'
removeDeployment: $(removeDeployment)
- name: 'Deploy network security group'
uses: ./.github/actions/templates/validateModuleDeployment
with:
templateFilePath: './arm/Microsoft.Network/networkSecurityGroups/deploy.bicep'
parameterFilePath: './MultiRepoTestParentFolder/network-hub-rg/Parameters/NetworkSecurityGroups/parameters.json'
location: '${{ env.defaultLocation }}'
resourceGroupName: '${{ env.resourceGroupName }}'
subscriptionId: '${{ secrets.ARM_SUBSCRIPTION_ID }}'
managementGroupId: '${{ secrets.ARM_MGMTGROUP_ID }}'
removeDeployment: $(removeDeployment)
- name: 'Deploy virtual network A'
uses: ./.github/actions/templates/validateModuleDeployment
with:
templateFilePath: './arm/Microsoft.Network/virtualNetworks/deploy.bicep'
parameterFilePath: './MultiRepoTestParentFolder/network-hub-rg/Parameters/VirtualNetwork/vnet-A.parameters.json'
location: '${{ env.defaultLocation }}'
resourceGroupName: '${{ env.resourceGroupName }}'
subscriptionId: '${{ secrets.ARM_SUBSCRIPTION_ID }}'
managementGroupId: '${{ secrets.ARM_MGMTGROUP_ID }}'
removeDeployment: $(removeDeployment)
- 'Azure/ResourceModules' repo has been checked out at the root location intentionally because the
deep-mm/set-variables@v1.0
task expects the global.variables.json file in the .github/variables/ location. The GitHub Actions also expect the underlying utility scripts at a specific location- 'contoso/MultiRepoTest' repo has been checked out in a nested folder called as "MultiRepoTestParentFolder" to distinguish it from the folders from the other repo in the agent but can be downloaded at the root location too if desired