A guide to migrate to Azure Functions Flex Consumption plan hosting. Contains specific steps for secure, identity based, C# Functions with VNet integration. With continuous deployment via Azure DevOps.
A fully working Bicep sample is available at Azure Functions Flex Consumption Samples.
Many app settings and properties are moved to a different place in an Flex Consumption plan or simply depreciated entirely, for a complete overview, see Flex Consumption plan deprecations.
A big change is the introduction of the properties.functionAppConfig
element in Microsoft.Web/sites
, available from versions @2023-12-01
and up.
Of course, the most obvious change is the SKU, on Microsoft.Web/serverfarms@2023-12-01
, the kind
and sku
will look like this:
kind: 'functionapp'
sku: {
tier: 'FlexConsumption'
name: 'FC1'
}
If coming from a premium plan, make sure to remove most properties from the serverfarms
resource, you will end up with just this simple configuration:
properties: {
reserved: true
}
Scaling now is set on the sites
resource, instead of the serverfarms
resource, it might look like this inside the properties
element:
@maxValue(1000)
param maximumInstanceCount int = 100
@allowed([2048, 4096])
param instanceMemoryMB int = 2048
...
functionAppConfig: {
scaleAndConcurrency: {
maximumInstanceCount: maximumInstanceCount
instanceMemoryMB: instanceMemoryMB
}
}
To specify C# properties;
- change app setting
FUNCTIONS_WORKER_RUNTIME_VERSION
=8.0
to resource settingproperties.functionAppConfig.runtime.version
=8.0
. - change app setting
FUNCTIONS_WORKER_RUNTIME
=dotnet-isolated
to resource settingproperties.functionAppConfig.runtime.name
=dotnet-isolated
. - delete
properties.siteConfig.netFrameworkVersion
=v8.0
- if on an old linux plan; delete
properties.siteConfig.LinuxFxVersion
=DOTNET-ISOLATED|8.0
. - if on an old windows plan; delete
properties.siteConfig.windowsFxVersion
=DOTNET-ISOLATED|8.0
.
If coming from an identity-based connection for AzureWebJobsStorage
(host), this still works with identities, but requires a different setup:
- delete app setting
AzureWebJobsStorage__blobServiceUri
- delete app setting
AzureWebJobsStorage__queueServiceUri
- delete app setting
AzureWebJobsStorage__tableServiceUri
- add app setting
AzureWebJobsStorage__accountName
and point to the storage account name of the backend storage. - add
authentication.type
property on the deployment element, as specified under Deployment, this will make sure the connection to the backend uses a managed identity.
If using VNet integration:
- remove the
WEBSITE_VNET_ROUTE_ALL
app setting - remove
properties.vnetImagePullEnabled
- remove
properties.vnetRouteAllEnabled
- remove
properties.vnetContentShareEnabled
- remove
properties.vnetBackupRestoreEnabled
- remove the
Microsoft.Web/sites/networkConfig
resource entirely, it might have looked like this:
resource networkConfig 'Microsoft.Web/sites/networkConfig@2023-01-01' = {
parent: functionApp
name: 'virtualNetwork'
properties: {
subnetResourceId: appServicePlanSubnetId
swiftSupported: true
}
}
- add
properties.virtualNetworkSubnetId
=appServicePlanSubnetId
toMicrosoft.Web/sites
- change delegation of the subnet, so for the resource
Microsoft.Network/virtualNetworks/subnets
;properties.delegations.properties.serviceName
used to beMicrosoft.Web/serverFarms
, now it isMicrosoft.App/environments
.
If coming from a secure VNet integrated connection for AzureWebJobsStorage
(host), this still works with VNet integration, but requires a different setup:
- delete app setting
WEBSITE_CONTENTOVERVNET
That's all there is to it! You can isolate your storage account completely with private endpoints, and block all public access.
To deploy a C# app, or any other language app, it's completely different to what you are used to, zip deploy isn't what it used to be anymore. You will still deploy to the Function App, but without building and zipping your project fist. The app will manage all deployments in a storage account using a container. In a Premium plan, managing deployments used to be within a file share:
- delete app setting
WEBSITE_RUN_FROM_PACKAGE
. - if coming from a premium plan: delete app setting
WEBSITE_CONTENTSHARE
. - add a
deployment
element to yourproperties.functionAppConfig
element, it might look like this:
deployment: {
storage: {
type: 'blobContainer'
value: '${storage.properties.primaryEndpoints.blob}${deploymentStorageContainerName}'
authentication: {
type: 'SystemAssignedIdentity'
}
}
}
This setup, with
authentication.type
=SystemAssignedIdentity
, assumes the Function App has data permissions on thedeploymentStorageContainerName
.
- add a deployment container to your backend storage account, and use as specified in the
deploymentStorageContainerName
variable, it might look like this on aMicrosoft.Storage/storageAccounts/blobServices@2023-04-01
resource:
resource container 'containers' = [
for container in containers: {
name: container.name
properties: {
publicAccess: 'None'
}
}
]
To deploy your actual code, inside an Azure DevOps environment, build and deploy steps differ greatly.
- optionally: remove the
DotNetCoreCLI
build task, i would recommend still building your project inside your CI/CD, to keep sanity checks and tests in place. - remove the
DotNetCoreCLI
publish task, it might have looked like this:
- task: DotNetCoreCLI@2
displayName: "dotnet publish"
inputs:
command: publish
...
- remove any zip task you might had, your build artifact should be made like this:
- task: CopyFiles@2
displayName: copy to staging dir
inputs:
sourceFolder: "$(System.DefaultWorkingDirectory)/${{ parameters.projectFolderName }}"
contents: "*"
targetFolder: "$(Build.ArtifactStagingDirectory)/dotnet"
overWrite: true # optional
Deployment makes use of the Azure Functions Core Tools instead of the Azure Functions Deploy task.
- remove the
AzureFunctionApp@2
task. - add deploy tasks that looks like this:
- task: FuncToolsInstaller@0
inputs:
version: 'latest'
- task: AzurePowerShell@5
displayName: Azure Function App Deploy
inputs:
azureSubscription: SC-Sandbox
azurePowerShellVersion: LatestVersion
ScriptType: "InlineScript"
Inline: |
cd "$(Pipeline.Workspace)/drop/dotnet"
func azure functionapp publish "func-hello-001" --dotnet-isolated
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.