-
Notifications
You must be signed in to change notification settings - Fork 24
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
28 changed files
with
3,221 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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" | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
Oops, something went wrong.