DEV Community

1suleyman
1suleyman

Posted on

🌐 Exercise 08 – Deploy VNETs and Output FQDNs Using Loops in Bicep

β€œWait… now we need networks in every country, plus a list of server URLs for the devs?”

Me: Sounds like a job for Bicep loops. πŸ› οΈπŸ˜Ž


πŸ’‘ Scenario

We’re expanding the smart teddy bear app to multiple countries. That means:

  • We need a virtual network (VNet) in each location.
  • Each VNet should have subnets for the frontend and backend.
  • Devs also want a list of SQL server FQDNs after deployment so they can connect from anywhere.

Let’s break it down and automate it πŸ’ͺ


🚧 What You’ll Learn

Feature Why It Matters
Variable Loops Define repeating items like subnets dynamically
Output Loops Return info (like FQDNs) for each location
Modular Deployment Keeps things clean and scalable

🧩 Step 1: Add Network Config to Your Bicep Template

Open main.bicep.

βž• Add These Parameters:

@description('IP range for the virtual networks')
param virtualNetworkAddressPrefix string = '10.10.0.0/16'

@description('Subnets for each VNet')
param subnets array = [
  {
    name: 'frontend'
    ipAddressRange: '10.10.5.0/24'
  }
  {
    name: 'backend'
    ipAddressRange: '10.10.10.0/24'
  }
]
Enter fullscreen mode Exit fullscreen mode

Think of it like defining rooms inside a house β€” one house (VNet) per location, each with two rooms (subnets): frontend and backend.


πŸ” Step 2: Use a Variable Loop for Subnets

var subnetProperties = [for subnet in subnets: {
  name: subnet.name
  properties: {
    addressPrefix: subnet.ipAddressRange
  }
}]
Enter fullscreen mode Exit fullscreen mode

This loop dynamically builds the list of subnets for each VNet based on our parameter. No more hardcoding!


🏑 Step 3: Deploy One VNet Per Location

Under your existing module databases loop, add this:

resource virtualNetworks 'Microsoft.Network/virtualNetworks@2024-05-01' = [for location in locations: {
  name: 'teddybear-${location}'
  location: location
  properties:{
    addressSpace:{
      addressPrefixes:[
        virtualNetworkAddressPrefix
      ]
    }
    subnets: subnetProperties
  }
}]
Enter fullscreen mode Exit fullscreen mode

Every location in the locations array gets its own teddy-themed VNet 🧸


πŸ“¬ Step 4: Add Outputs to Your database.bicep Module

Open modules/database.bicep and at the bottom, add:

output serverName string = sqlServer.name
output location string = location
output serverFullyQualifiedDomainName string = sqlServer.properties.fullyQualifiedDomainName
Enter fullscreen mode Exit fullscreen mode

These act like a return statement β€” giving us back key details about each SQL server.


πŸ“¦ Step 5: Loop Over Outputs in Your Main Template

Now back in main.bicep, at the bottom, add this:

output serverInfo array = [for i in range(0, length(locations)): {
  name: databases[i].outputs.serverName
  location: databases[i].outputs.location
  fullyQualifiedDomainName: databases[i].outputs.serverFullyQualifiedDomainName
}]
Enter fullscreen mode Exit fullscreen mode

You now get a full list of all deployed SQL server names, their regions, and their FQDNs. Your devs will love you for this πŸ‘¨β€πŸ’»


πŸ§ͺ Example: Final main.bicep Structure

Your main.bicep will now contain:

  • Secure login parameters
  • Location list
  • VNet and subnet settings
  • Database module loop
  • VNet loop
  • Output loop
param locations array = [ 'westus', 'eastus2', 'eastasia' ]
param sqlServerAdministratorLogin string
param sqlServerAdministratorLoginPassword string
param virtualNetworkAddressPrefix string = '10.10.0.0/16'
param subnets array = [
  { name: 'frontend'; ipAddressRange: '10.10.5.0/24' }
  { name: 'backend'; ipAddressRange: '10.10.10.0/24' }
]

var subnetProperties = [for subnet in subnets: {
  name: subnet.name
  properties: {
    addressPrefix: subnet.ipAddressRange
  }
}]

module databases 'modules/database.bicep' = [for location in locations: {
  name: 'database-${location}'
  params: {
    location: location
    sqlServerAdministratorLogin: sqlServerAdministratorLogin
    sqlServerAdministratorLoginPassword: sqlServerAdministratorLoginPassword
  }
}]

resource virtualNetworks 'Microsoft.Network/virtualNetworks@2024-05-01' = [for location in locations: {
  name: 'teddybear-${location}'
  location: location
  properties: {
    addressSpace: {
      addressPrefixes: [ virtualNetworkAddressPrefix ]
    }
    subnets: subnetProperties
  }
}]

output serverInfo array = [for i in range(0, length(locations)): {
  name: databases[i].outputs.serverName
  location: databases[i].outputs.location
  fullyQualifiedDomainName: databases[i].outputs.serverFullyQualifiedDomainName
}]
Enter fullscreen mode Exit fullscreen mode

πŸš€ Deploy It!

Make sure you’re set up:

az bicep install && az bicep upgrade
az login
az group create --name BicepRG --location westus
Enter fullscreen mode Exit fullscreen mode

Then deploy:

az deployment group create \
  --resource-group BicepRG \
  --name main \
  --template-file main.bicep
Enter fullscreen mode Exit fullscreen mode

πŸ’¬ You’ll be prompted for the SQL login and password β€” make sure they’re secure and meet Azure’s password rules.


πŸ”Ž Post-Deployment: What to Check

Head to the Azure Portal:

  • Open your Resource Group
  • You should see three virtual networks (westus, eastus2, eastasia)
  • Each VNet should have frontend and backend subnets
  • Scroll to Deployments > main > Outputs
  • You’ll see an array of your SQL server FQDNs, ready to be copied!

βœ… Devs can now grab their connection strings. Ops teams are happy. Mission complete 🎯


🧠 In Short

Feature What We Did
Parameterized Subnets Passed in subnet structure as a parameter
Variable Loop Built reusable subnet configs
Resource Loop Deployed 1 VNet per region
Output Loop Gathered SQL server details for dev handoff

Wanna follow my Azure learning journey?

Stick around β€” I’m sharing it all, wins and stumbles included πŸ˜„

You can find me on LinkedIn β€” drop me a message and just say hi πŸ‘‹

Would love to hear what you're working on or learning!

Top comments (0)