Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dependencies Example #12

Merged
merged 5 commits into from
Dec 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@ If you find this repository useful, please save the repository by hitting the

2. Install the [Bicep extension](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-bicep)

3. To test, deploy (resources to Azure) and debug Bicep files:
3. To deploy Bicep files:
- Install [AzureCLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli-windows?tabs=azure-cli) **[recommended method]** or
- [Azure PowerShell](https://learn.microsoft.com/en-us/powershell/azure/install-azure-powershell?view=azps-10.3.0) (must install [Bicep manually](https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/install#install-manually) if you want to use with PowerShell)

4. [Fork](https://github.com/riosengineer/Bicepify/fork) this repository so you have a copy to lab with our examples

5. In your forked repository, click the green Code and Open with VisualStudio for a quick start

6. Read the README files for further information and deployment commands to test
6. Read the README files for further information, explanations and deployment commands to test the example

## 🧪 About the project

Expand Down Expand Up @@ -59,6 +59,8 @@ Where possible, examples will be complimented by a blog post giving a deeper div

[Awesome Azure Bicep list](https://github.com/ElYusubov/AWESOME-Azure-Bicep)

[Azure Bicep Cheat Sheet](https://github.com/johnlokerse/azure-bicep-cheat-sheet)

## 🖌️ Authors

- [Rios Engineer](https://www.github.com/riosengineer)
91 changes: 91 additions & 0 deletions bicep-examples/dependencies/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# Resource dependencies in Azure Bicep 🦾

There's two types of dependencies `implicit` and `explicit` in Azure Bicep. Within the `main.bicep` file example you'll notice many implicit and some explicit dependencies that you can review as a real example of how these two play a role in your Azure Bicep deployments.

> [!TIP]
> If you're interested in the example solution and what it does then there is more information in this template repo [here](https://github.com/riosengineer/bicep-quickstart-frontdoor-private-endpoint-appservice) with supporting documentation and architectural drawing.

## Implicit 🔗

With `implicit` dependencies we are referencing another Azure resource within the same deployment, which means we'll not need to declare an explicit dependency. There are two common ways this is accomplished. For example:

```javascript
module appInsights 'modules/appInsights/appinsights.bicep' = {
name: '${uniqueString(deployment().name, location)}-appInsights'
params: {
name: appInsightsName
location: location
workspaceResourceId: logAnalytics.outputs.id
kind: 'web'
applicationType: 'web'
}
}
```

Note the `logAnalytics.outputs.id` defined is referencing a previous module for this resource properties. This is how an implicit dependency is created and ARM will then deploy resources in their dependent order.

```javascript
resource frontDoorOriginGroup 'Microsoft.Cdn/profiles/originGroups@2021-06-01' = {
name: frontDoorOriginGroupName
parent: frontDoorProfile
properties: {
loadBalancingSettings: {
sampleSize: 4
successfulSamplesRequired: 3
}
healthProbeSettings: {
probePath: '/'
probeRequestType: 'HEAD'
probeProtocol: 'Http'
probeIntervalInSeconds: 100
}
}
}
```

Lastly, notice the `parent:` property defined in this Azure Front Door resource block above, where it's defining the symbolic name from the Azure CDN profile object. This is also an implicit dependency created between the two objects.

## Explicit 🖇️

```javascript
resource frontDoorProfile 'Microsoft.Cdn/profiles@2021-06-01' = {
name: frontDoorProfileName
location: 'global'
sku: {
name: frontDoorSkuName
}
dependsOn: [
webApp
webAppPlan
]
}
```

For explicit dependencies, we can use the `dependsOn` property to describe explicitly which resources we want this deployment to depend on. You don't need to, and shouldn't add an implicit and explicit dependency in the same resource, it's a one or the other use case.

In the case above, I don't want my Front Door deployment to start before the App service and App Plan have been deployed first, as I need them to exist for my origin backend in Front Door.

## Deployment 🚀

> [!WARNING]
> This example deploys Azure Front Door Premium SKU which is circa $300 for the month. Do not leave running if you don't want to incur charges. Make sure to delete as soon as possible after deployment and you'll likely see very minimal costs.

Define the parameters in the top of the file before deploying.

In VisualStudio Code open a terminal and run:

CLI

```bash
az login
az set --subscription 'your subscription name'
az deployment create --confirm-with-what-if -g 'your resource group name' -f .\main.bicep
```

or PowerShell

```powershell
Connect-AzAccount
Set-AzContext -Subsription "your subsription name"
New-AzResourceGroupDeployment -Confirm -ResourceGroup "your resource group name" -TemplateFile "main.bicep"
```
229 changes: 229 additions & 0 deletions bicep-examples/dependencies/main.bicep
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
targetScope = 'resourceGroup'

// Change the below params to suit your deployment needs
// Go to the modules to amend IP schema, app plan sku/app code stack etc.
@description('Azure UK South region.')
param location string = resourceGroup().location

@description('Web App resource group name.')
param rg_web_workload string = 'rg-webapp-prod'

@description('Workload / corp / core landing zone subid.')
param workloadsSubId string = '00000000-0000-0000-0000-000000000000'

@description('Log analytics workspace name.')
param alaName string = 'ala-workspace-name'

@description('App service application insights name.')
param appInsightsName string = 'appinsights-name'

@description('Azure app service name.')
param webAppName string = 'webapp-001'

@description('The name of the Front Door endpoint to create. This must be globally unique.')
param afdWebEndpoint string = 'afd-${uniqueString(resourceGroup().id)}'

@description('The name of the SKU to use when creating the Front Door profile.')
@allowed([
'Standard_AzureFrontDoor'
'Premium_AzureFrontDoor'
])
param frontDoorSkuName string = 'Premium_AzureFrontDoor'

var frontDoorProfileName = 'afdpremium-web'
var frontDoorOriginGroupName = 'webapp-origin-group'
var frontDoorOriginName = 'webapp-origin-group'
var frontDoorRouteName = 'webapp-route'

///////////////
// Resources //
///////////////

// Azure App Service components

// vNet for integration
module vnet 'br/public:network/virtual-network:1.1.3' = {
name: '${uniqueString(deployment().name, location)}-webVnet'
scope: resourceGroup(workloadsSubId, rg_web_workload)
params: {
name: 'webapp-vnet'
addressPrefixes: [
'10.1.0.0/21'
]
subnets: [
{
name: 'webapp-snet'
addressPrefix: '10.1.1.0/24'
delegations: [
{
name: 'Microsoft.Web.serverFarms'
properties: {
serviceName: 'Microsoft.Web/serverFarms'
}
}
]
}
]
}
}

// Log Analytics workspace
module logAnalytics 'br/public:storage/log-analytics-workspace:1.0.3' = {
name: '${uniqueString(deployment().name, location)}-ala'
scope: resourceGroup(rg_web_workload)
params: {
name: alaName
location: location
}
}

// Application Insight
module appInsights 'modules/appInsights/appinsights.bicep' = {
name: '${uniqueString(deployment().name, location)}-appInsights'
scope: resourceGroup(workloadsSubId, rg_web_workload)
params: {
name: appInsightsName
location: location
workspaceResourceId: logAnalytics.outputs.id
kind: 'web'
applicationType: 'web'
}
}

// Azure App Plan
module webAppPlan 'modules/webApp/appPlan.bicep' = {
name: '${uniqueString(deployment().name, location)}-appPlan'
scope: resourceGroup(workloadsSubId, rg_web_workload)
params: {
name: 'appPlan'
location: location
sku: {
name: 'S1'
}
kind: 'App'
}
}

// Web App resource
module webApp 'modules/webApp/webApp.bicep' = {
name: '${uniqueString(deployment().name, location)}-webApp'
scope: resourceGroup(workloadsSubId, rg_web_workload)
params: {
name: webAppName
location: location
kind: 'app'
serverFarmResourceId: webAppPlan.outputs.resourceId
httpsOnly: true
publicNetworkAccess: 'Disabled'
appInsightResourceId: appInsights.outputs.resourceId
virtualNetworkSubnetId: vnet.outputs.subnetResourceIds[0]
siteConfig: {
detailedErrorLoggingEnabled: true
httpLoggingEnabled: true
requestTracingEnabled: true
ftpsState: 'Disabled'
minTlsVersion: '1.2'
alwaysOn: true
}
appSettingsKeyValuePairs: {
name: 'APPINSIGHTS_INSTRUMENTATIONKEY'
value: appInsights.outputs.instrumentationKey
}
managedIdentities: {
systemAssigned: true
}
}
}


// Front Door resource
resource frontDoorProfile 'Microsoft.Cdn/profiles@2021-06-01' = {
name: frontDoorProfileName
location: 'global'
sku: {
name: frontDoorSkuName
}
dependsOn: [
webApp
webAppPlan
]
}

// Front Door endpoint(s)
resource frontDoorEndpoint 'Microsoft.Cdn/profiles/afdEndpoints@2021-06-01' = {
name: afdWebEndpoint
parent: frontDoorProfile
location: 'global'
properties: {
enabledState: 'Enabled'
}
}

// Front Door origin group
resource frontDoorOriginGroup 'Microsoft.Cdn/profiles/originGroups@2021-06-01' = {
name: frontDoorOriginGroupName
parent: frontDoorProfile
properties: {
loadBalancingSettings: {
sampleSize: 4
successfulSamplesRequired: 3
}
healthProbeSettings: {
probePath: '/'
probeRequestType: 'HEAD'
probeProtocol: 'Http'
probeIntervalInSeconds: 100
}
}
}

// Front Door backend - Azure Web App
resource frontDoorOrigin 'Microsoft.Cdn/profiles/originGroups/origins@2022-11-01-preview' = {
name: frontDoorOriginName
parent: frontDoorOriginGroup
properties: {
hostName: webApp.outputs.defaultHostname
httpPort: 80
httpsPort: 443
originHostHeader: webApp.outputs.defaultHostname
priority: 1
weight: 1000
sharedPrivateLinkResource: {
groupId: 'sites'
privateLink: {
id: webApp.outputs.resourceId
}
privateLinkLocation: location
requestMessage: 'AFD PE to Web App'
status: 'Pending'
}
}
}

// Front Door route
resource frontDoorRoute 'Microsoft.Cdn/profiles/afdEndpoints/routes@2021-06-01' = {
name: frontDoorRouteName
parent: frontDoorEndpoint
dependsOn: [
frontDoorOrigin // This explicit dependency is required to ensure that the origin group is not empty when the route is created.
]
properties: {
originGroup: {
id: frontDoorOriginGroup.id
}
supportedProtocols: [
'Http'
'Https'
]
patternsToMatch: [
'/*'
]
forwardingProtocol: 'HttpsOnly'
linkToDefaultDomain: 'Enabled'
httpsRedirect: 'Enabled'
}
}

// Output FQDNs
output appServiceHostName string = webApp.outputs.defaultHostname
output frontDoorEndpointHostName string = frontDoorEndpoint.properties.hostName
Loading