Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save palmerandy/22909c79de6d1f483a727116e5a1bfd4 to your computer and use it in GitHub Desktop.
Save palmerandy/22909c79de6d1f483a727116e5a1bfd4 to your computer and use it in GitHub Desktop.
Azure Function ARM template with Staging and Production slots.
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"azureSubscriptionId": {
"type": "string",
"metadata": {
"description": "The azure subscription Id. Something like 12345678-abcd-abcd-abcd-1234567890ab."
}
},
"appName": {
"type": "string",
"metadata": {
"description": "The name of the Function app to be created / modified"
}
},
"appServicePlanName": {
"type": "string",
"metadata": {
"description": "The name of the App Service plan that will host the Function app - this must exist already."
}
},
"functionsStorageAccountName": {
"type": "string",
"metadata": {
"description": "The name of the storage account to be created / modified that will be used to power the new Function app. More details in the comment of the resource."
}
},
"websiteStorageAccountName": {
"type": "string",
"metadata": {
"description": "The name of the existing storage account that the website uses as it's primary storage account (e.g. for queues and table storage)."
}
},
"applicationInsightsName": {
"type": "string",
"metadata": {
"description": "The name of the existing application insight to log information."
}
},
"applicationInsightsLocation": {
"type": "string",
"metadata": {
"description": "The name of the existing application insight to log information."
}
}
},
"variables": {
"functionsStorageAccountid": "[concat('/subscriptions/', parameters('subscriptionId'), '/resourceGroups/', resourceGroup().name, '/providers/Microsoft.Storage/storageAccounts/', parameters('functionsStorageAccountName'))]",
"websiteStorageAccountid": "[concat('/subscriptions/', parameters('subscriptionId'), '/resourceGroups/', resourceGroup().name, '/providers/Microsoft.Storage/storageAccounts/', parameters('websiteStorageAccountName'))]",
"slotName": "[concat(parameters('appName'), '/staging')]"
},
"resources": [
{
"type": "Microsoft.Storage/storageAccounts",
"name": "[parameters('functionsStorageAccountName')]",
"apiVersion": "2016-12-01",
"location": "[resourceGroup().location]",
"kind": "Storage",
"sku": {
"name": "Standard_LRS"
},
"properties": {
"supportsHttpsTrafficOnly": false,
"encryption": {
"keySource": "Microsoft.Storage",
"services": {
"blob": {
"enabled": true
},
"file": {
"enabled": true
}
}
},
"dependsOn": [],
"comments": "This storage account is used to log to Azure Table storage and power the Monitor tab in the portal. We explicity use a seperate account, in case we want to change the SKU of websiteStorageAcccount parameter."
}
},
{
"name": "[parameters('applicationInsightsName')]",
"apiVersion": "2014-04-01",
"type": "Microsoft.Insights/components",
"kind": "other",
"location": "[parameters('applicationInsightsLocation')]",
"properties": { "applicationId": "[parameters('applicationInsightsName')]" }
},
{
"name": "[parameters('appName')]",
"apiVersion": "2015-08-01",
"type": "Microsoft.Web/sites",
"kind": "functionapp",
"location": "[resourceGroup().location]",
"identity": {
"type": "SystemAssigned"
},
"properties": {
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', parameters('appServicePlanName'))]",
"siteConfig": {
"phpVersion": "off",
"use32BitWorkerProcess": "false",
"alwaysOn": "true",
"remoteDebuggingEnabled": "false",
"remoteDebuggingVersion": "",
"webSocketsEnabled": true,
"http20Enabled": true,
"ftpsState": "Disabled",
"appSettings": [
{
"name": "FUNCTIONS_EXTENSION_VERSION",
"value": "~1"
},
{
"name": "Project",
"value": "src"
}
]
},
"dependsOn": [
"[resourceId('Microsoft.Web/Sites', parameters('appName'))]",
"[resourceId('Microsoft.Storage/storageAccounts', parameters('functionsStorageAccountName'))]",
"[resourceId('Microsoft.Insights/components', parameters('applicationInsightsName'))]"
],
"comments": "This Function App will host all Azure functions."
},
"resources": [
{
"name": "slotConfigNames",
"type": "config",
"apiVersion": "2015-08-01",
"dependsOn": [
"[resourceId('Microsoft.Web/Sites', parameters('appName'))]"
],
"tags": {
"displayName": "slotConfigNames"
},
"properties": {
"appSettingNames": [
"DisableAllFunctions"
]
}
},
{
"apiVersion": "2015-08-01",
"name": "appsettings",
"type": "config",
"dependsOn": [
"[resourceId('Microsoft.Web/Sites', parameters('appName'))]",
"[resourceId('Microsoft.Storage/storageAccounts', parameters('functionsStorageAccountName'))]"
],
"properties": {
//Important: when adding new App Setting, you need to add them to the staging slot
"DisableAllFunctions": "false", //note this setting is slot specific
"AzureWebJobsStorage": "[concat('DefaultEndpointsProtocol=https;AccountName=', parameters('websiteStorageAccountName'), ';AccountKey=', listKeys(variables('websiteStorageAccountid'),'2015-05-01-preview').key1)]",
"AzureWebJobsDashboard": "[concat('DefaultEndpointsProtocol=https;AccountName=', parameters('functionsStorageAccountName'), ';AccountKey=', listKeys(variables('functionsStorageAccountid'),'2015-05-01-preview').key1)]",
"FUNCTIONS_EXTENSION_VERSION": "~1",
"APPINSIGHTS_INSTRUMENTATIONKEY": "[reference(resourceId('Microsoft.Insights/components', parameters('applicationInsightsName')), '2014-04-01').InstrumentationKey]"
}
}
]
},
{
"apiVersion": "2016-08-01",
"dependsOn": [
"[resourceId('Microsoft.Web/sites', parameters('appName'))]"
],
"kind": "functionapp",
"location": "[resourceGroup().location]",
"name": "[variables('slotName')]",
"properties": {
"enabled": true,
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', parameters('appServicePlanName'))]"
},
"type": "Microsoft.Web/sites/slots",
"resources": [
{
"name": "appsettings",
"type": "config",
"apiVersion": "2015-08-01",
"dependsOn": [
"[resourceId('Microsoft.Web/sites/slots', variables('slotName'))]"
],
"tags": {
"displayName": "AppSettings"
},
"properties": {
//Important: when adding new App Setting, you need to add them to the production slot
"DisableAllFunctions": "true", //note this setting is slot specifc
"AzureWebJobsStorage": "[concat('DefaultEndpointsProtocol=https;AccountName=', parameters('websiteStorageAccountName'), ';AccountKey=', listKeys(variables('websiteStorageAccountid'),'2015-05-01-preview').key1)]",
"AzureWebJobsDashboard": "[concat('DefaultEndpointsProtocol=https;AccountName=', parameters('functionsStorageAccountName'), ';AccountKey=', listKeys(variables('functionsStorageAccountid'),'2015-05-01-preview').key1)]",
"FUNCTIONS_EXTENSION_VERSION": "~1",
"APPINSIGHTS_INSTRUMENTATIONKEY": "[reference(resourceId('Microsoft.Insights/components', parameters('applicationInsightsName')), '2014-04-01').InstrumentationKey]"
}
}
]
}
]
}
@palmerandy
Copy link
Author

From line 89-161 it appears that you're deploying a function app with two resources. One of those resource has the type "config" and name "slotConfigNames", on lines 127-142. Lines 143-159 appear to already configure the properties. What is the purpose of this resource being defined?

I'm not sure if I fully understand your question, but here is what each each groups of line objective:
Line 89-96 is the Function App (a type of App Service).
Line 97-118 are the Function App's properties
Lines 128-142 is the Function Apps slot configuration
Lines 143-159 is the Function App's app settings

Lines 162-196 deploy the staging slot for the function app. This resource deployment doesn't have the same resource defined like in the production slot on lines 127-142.

Yes - the point is to keep the production slot online.. This is explained in my related blog post https://andypalmer.dev/posts/automated-deployment-of-azure-functions-arm-templates/

Another question...couldn't you just embed the resource defined on lines 162-196 under the existing "resources" array in the production app? According to the schema documentation for the Sites template, you can provide a "slot" resource in the Microsoft.Web/sites object.

This sounds like it could work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment