Search code examples
azureazure-resource-managerazure-rm-templateazure-bicepinfrastructure-as-code

Bicep to act as a template for deploying app service and related resources


I have individual biceps for app insight, app service plan, and, app service.

I am creating a template bicep where I will call each of these as modules to deploy one app service. And now whenever for any of my solutions I need to deploy an app service, I will just call this template with minimum parameters so it can deploy an app service with all required supporting resources like app service plan and app insight.

The situation I am stuck with now is I need one app service plan to host two app services one for web and the other for api and each of them should have their own app insight.

The individual modules are very simple, I am still giving a sample for app service plan below:

//asp.bicep
param planName string
param planLocation string = resourceGroup().Location
param planSku string
param planTier string

resource appServicePlan 'Microsoft.Web/serverfarms@2022-03-01' = { name: planName, location: planLocation, sku: { 
name: planSku
tier: planTier
]}

output appPlanId string = appServicePlan.id

Below I have the app service template where all the individual biceps are being called as modules, shown below:

//astemplate.bicep
param rgLocation string = resourceGroup().location
param name string
param planSku string
param planTier string
param appSettings array = []
param netFrameworkVersion string

var appInsightModule = '${name}-AIModule'
var appServicePlanModule = '${name}-ASPModule'
var appServiceModule = '${name}-ASModule'

module aspModule ''={
 name: appServicePlanModule
 params: {
  planName: name
  planLocation: rgLocation
  planSku: planSku
  planTier: planTier
 }
}

module aiAppModule '' = {
 name: '${appInsightModule}-forApp'
 params: {
  name: '${name}-ai-app'
  location: rgLocation
 } 
}

module aiApiModule '' = {
 name: '${appInsightModule}-forApi'
 params: {
  name: '${name}-ai-api'
  location: rgLocation
 } 
}

module asAppModule '' = {
 name: '${appServiceModule}-app'
 params: {
  name: '${name}-app'
  rgLocation: rgLocation
  appInsightsKey: aiAppModule.outputs.instrumentationkey
  appServicePlanId: aspModule.outputs.appPlanId
  appSettings: appSettings
  netFrameworkVersion: netFrameworkVersion 
 }
 dependsOn: [aspModule, aiAppModule] 
}

module asApiModule '' = {
 name: '${appServiceModule}-api'
 params: {
  name: '${name}-api'
  rgLocation: rgLocation
  appInsightsKey: aiApiModule.outputs.instrumentationkey
  appServicePlanId: aspModule.outputs.appPlanId
  appSettings: appSettings
  netFrameworkVersion: netFrameworkVersion 
 }
 dependsOn: [aspModule, aiApiModule] 
}

What I am trying to achieve is a way to have to make just one call to app insight module and one to app service module instead of two calls each? Because I want this template to satisfy all permutation and combination. If I decide to have one app insight for all app services or one for each.

For App Insight, I was thinking of passing names app insight resources in an array and use for loop at the individual bicep level(resource) but then I got stuck with assigning the appropriate app insight to its related app service.

I hope the question is clear, please let me know if more details or other individual bicep is also required?


Solution

  • //AppInsight bicep
    param name string
    
    param location string = resourceGroup().location
    
    param aiPostFix string = 'ai'
    
    var aiName = '${name}-${aiPostFix}'
    
    resource appInsight 'Microsoft.Insights/components@2020-02-02' = {
      name: aiName
      kind: 'web'
      location: location
      properties:{
        Application_Type:'web'
        Request_Source:'rest'
        Flow_Type:'Bluefield'
      }
    }
    
    output instrumentationKey string = appInsight.properties.InstrumentationKey
    output insightsName string = appInsight.properties.Name
    
    //ASP bicep
    param planName string
    param planLocation string = resourceGroup().location
    param planSku string
    param planTier string
    
    param aspPostFix string = 'asp'
    
    var aspName = '${planName}-${aspPostFix}'
    
    resource appServicePlan 'Microsoft.Web/serverfarms@2022-03-01' = { name: aspName, location: planLocation, sku: {
        name: planSku
        tier: planTier
      } }
    
      output appPlanId string = appServicePlan.id
    
    //App service bicep
    param rgLocation string = resourceGroup().location
    param name string
    param appServicePlanId string
    param appServicePostFix string = 'as'
    param netFrameworkVersion string = 'v6.0'
    param appInsightsKey string
    param appSettings array = []
    
    var appServiceName = '${name}-${appServicePostFix}'
    
    resource appService 'Microsoft.Web/sites@2021-02-01' = {
      name: appServiceName
      location: rgLocation
      properties:{
        serverFarmId: appServicePlanId
        siteConfig:{
          alwaysOn: true
          ftpsState: 'Disabled'
          netFrameworkVersion: netFrameworkVersion
          appSettings: appSettings
        }
        httpsOnly: true    
      }
    }
    
    output appServiceId string = appService.id
    
    

    Now the app service template bicep

    //astemplate bicep
    
    param rgLocation string = resourceGroup().location
    param aspName string
    param planSku string = 'XXX'
    param planTier string = 'XXX'
    param appSettings array = XXX
    param netFrameworkVersion string = 'XXX'
    param aiName string
    param asName string
    
    var aiModule = '${aiName}-AIModule'
    var hostingModule = '${aspName}-ASPModule'
    var asModule = '${asName}-ASModule'
    
    module aspModule 'asplan.bicep' = {
      name: hostingModule
      params: {
        planName: aspName
        planLocation: rgLocation
        planSku: planSku
        planTier: planTier
      }
    }
    
    module appInsightModule 'ai.bicep' = {
      name: aiModule
      params: {
        name: aiName
        location: rgLocation
      }
    }
    
    module appServiceAppModule 'as.bicep' = {
      name: asModule
      params: {
        name: asName
        rgLocation: rgLocation
        appInsightsKey: appInsightModule.outputs.instrumentationKey
        appServicePlanId: aspModule.outputs.appPlanId
        appSettings: appSettings
        netFrameworkVersion: netFrameworkVersion
      }
      dependsOn: [ aspModule, appInsightModule ]
    }
    
    

    Now for e.g. I need one asp which hosts two app services and both have their own app insight

    module appServiceApiTemplateModule 'astemplate.bicep' = {
      name: '${prefixRName}-ApiModule'
      params: {    
        aspName: prefixRName
        aiName: '${prefixRName}-web1'
        asName: '${prefixRName}-web1'
        appSettings: [      
          {
            name: 'Environment'
            value: environment
          }
        ]
      }
    }
    

    I can call the above module again and update aiName and asName parameter web1 to web2 and it will deploy one more app service with its own app insight but on the same hosting plan.