PROBLEM
How to deploy two different Azure App Services to the same App Service plan when using VSTS idempotent continuous integration / continuous deployment processes.
ENVIRONMENT
I have written two
ARM TEMPLATES
each of which deploy a web application to Azure App Service.In order to deploy an App Service an Service Plan must be created first.
The
ARM TEMPLATES
currently create a unique Service Plan each for each Web App.I am using VSTS Release Definitions to deploy on each successful VSTS build. i.e releases are designed to be idempotent.
Currently each web app has its own Resource Group which includes it own App Service Plan. Ideally each web app has its own Resource Group, App Service Plan can be in its own Resource Group however (if this is possible).
The template below is an example of one of the templates used to deploy the Web App service to an App Service Plan.
It shows the creation of the App Service Plan using the naming conversion:
appname-Plan-q2dkkaaaaaaaa
This is created using:
- Seven Character identifier "appname" defined in the ARM parameters files.
- Resource identifier "plan".
- Resource Group name , which comes from random named Storage Account name "q2dkkaaaaaaaa" when it was created.
i.e
"hostingPlanName": "[concat(parameters('appName'),'-Plan-', uniqueString(resourceGroup().id))]",
EXAMPLE
{
"parameters": {
"appName": {
"type": "string",
"maxLength": 7,
"metadata": {
"description": "The name of the app that you wish to create."
}
},
"appServicePlanSku": {
"type": "string",
"defaultValue": "Standard",
"metadata": {
"description": "The Service Plan SKU"
}
},
"appServicePlanWorkerSize": {
"type": "string",
"defaultValue": "0",
"metadata": {
"description": "The App Service Plan Worker Size (?)"
}
},
"appServicePlanSkuCode": {
"type": "string",
"defaultValue": "S1",
"metadata": {
"description": "The App Service Plan SKU Code"
}
},
"appServicePlanNumWorkers": {
"type": "string",
"defaultValue": "2",
"metadata": {
"description": "The Number of App Service Workers."
}
},
"variables": {
"webAppName": "[concat(parameters('appName'),'-wa-', uniqueString(resourceGroup().id))]",
"hostingPlanName": "[concat(parameters('appName'),'-Plan-', uniqueString(resourceGroup().id))]",
"stageSlotName": "stageSlot",
"devSlotName": "devSlot"
}
},
"resources": [
{
"apiVersion": "2016-09-01",
"name": "[variables('hostingPlanName')]",
"type": "Microsoft.Web/serverfarms",
"location": "[resourceGroup().location]",
"properties": {
"name": "[variables('hostingPlanName')]",
"workerSizeId": "[parameters('appServicePlanWorkerSize')]",
"numberOfWorkers": "[parameters('appServicePlanNumWorkers')]"
},
"sku": {
"Tier": "[parameters('appServicePlanSku')]",
"Name": "[parameters('appServicePlanSkuCode')]"
},
"dependsOn": []
},
{
"apiVersion": "2015-08-01",
"type": "Microsoft.Web/sites",
"name": "[variables('webAppName')]",
"location": "[resourceGroup().location]",
"kind": "webapp",
"tags": {
"Environment": "production",
"displayName": "WebAppService"
},
"dependsOn": [
"[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]",
],
"properties": {
"name": "[variables('webAppName')]",
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms',variables('hostingPlanName'))]"
},
"resources": [
{
"name": "slotConfigNames",
"type": "config",
"apiVersion": "2015-08-01",
"dependsOn": [
"[resourceId('Microsoft.Web/sites', variables('webAppName'))]"
],
"tags": {
"displayName": "slotConfigNames"
},
"properties": {
"appSettingNames": []
}
},
{
"apiVersion": "2015-08-01",
"name": "[variables('stageSlotName')]",
"type": "slots",
"location": "[resourceGroup().location]",
"dependsOn": [
"[resourceId('Microsoft.Web/sites', variables('webAppName'))]"],
"properties": {},
"resources": []
},
{
"apiVersion": "2015-08-01",
"name": "[variables('devSlotName')]",
"type": "slots",
"location": "[resourceGroup().location]",
"dependsOn": [
"[resourceId('Microsoft.Web/sites', variables('webAppName'))]"],
"properties": {},
"resources": []
}
]
}
]
}
QUESTION
I am attempting to execute two ARM TEMPLATES (similar to the above example) to deploy two different Web Apps to the same Service Plan.
Its clear that both of these Web Apps must call the same central resource to ensure they both deploy to same App Service resource name and execute any changes.
- If the App Service plan exists = deploy web app.
- If the App Service plan does not exist = create service plan then deploy web app.
- If the App Service plan is changed = deploy the service plan change (e.g Tier change) then deploy the web app.
Taking the environmental description above into consideration , what options do I have to get this working?
- VSTS Global parameter in the Release Definition maybe ?
- ARM TEMPLATES call a PowerShell script that creates the app service plan ?
Keen to follow best practice.
I hope the above is described in enough detail. Sorry if something has been missed. Thank you.
SOLUTION
The solution in my case was to create three templates:
RESULT
EXAMPLE
Shared Service Plan - ARM Template example of a shared service plan:
Web App A - ARM Template Example containing LINKED TEMPLATE:
Hope this is useful to someone.
Thanks Scott
REF https://github.com/MicrosoftDocs/azure-docs/blob/master/articles/azure-resource-manager/resource-group-linked-templates.md