Deploy Premium Linux  Function App with ARM template
Tags: azure, serverless, devops
Published: 2020-08-13 04:34:07

I wanted to automate the deployment of the Premium Linux and AppService plan for Java application. I'd like to share what I learned. This repo is the repo I leave the samples.

* [Azure Functions Deployment Testing suite](https://github.com/TsuyoshiUshio/FunctionsDeploymentTestingSuite)

# Premimu Linux 

There is an official document however, I can't find Premium Linux configuration. 
* [Deploy on Premium plan](https://docs.microsoft.com/en-us/azure/azure-functions/functions-infrastructure-as-code#premium)

* [Azure Functions Premium plan](https://docs.microsoft.com/en-us/azure/azure-functions/functions-premium-plan#:~:text=The%20Azure%20Functions%20Premium%20plan%20%28sometimes%20referred%20to,size%2C%20base%20plan%20size%2C%20and%20maximum%20plan%20size.)

## Serverfarms

`targetWorkerCount` and `targetWorkerSizeId` are something we can't find on the official documentation. That is `int` properties. Important point is, `kind` as `elastic` and `reserved` as `true`.

```json
        {
            "apiVersion": "2018-02-01",
            "name": "[parameters('hostingPlanName')]",
            "type": "Microsoft.Web/serverfarms",
            "location": "[parameters('location')]",
            "kind": "elastic",
            "tags": {},
            "dependsOn": [],
            "properties": {
                "targetWorkerCount": "[parameters('targetWorkerCount')]",
                "targetWorkerSizeId": "[parameters('targetWorkerSizeId')]",
                "reserved": true,
                "maximumElasticWorkerCount": "[parameters('maximumElasticWorkerCount')]"
            },
            "sku": {
                "tier": "[parameters('sku')]",
                "name": "[parameters('skuCode')]"
            }
        },
```

We have a several resouces, however, the reference looks the latest. 

* [Microsoft.Web serverfarms template reference](https://docs.microsoft.com/en-us/azure/templates/microsoft.web/2020-06-01/serverfarms)

## targetWorkerSizeId
Probably, these meaning.

```
Small = 0,
Medium = 1,
Large = 2,
D1 = 3,
D2 = 4,
D3 = 5,
SmallV3 = 6,
MediumV3 = 7,
LargeV3 = 8,
NestedSmall = 9,
```
## Web/sites

`kind` as `functionapp,linux`. For specifying languages, I set `FUNCTIONS_WORKER_RUNTIME` as `java`, `linuxFxVersion` as `Java|8`. The `linuxFxVersion` requires only on linux. It represents docker images that you found [azure functions docker](https://github.com/Azure/azure-functions-docker). You can find some possible value in [here](https://docs.microsoft.com/en-us/azure/azure-functions/functions-infrastructure-as-code#create-a-function-app-2). It can be specify the generic one like `Java|8` but also you can specify specific docker image version like `DOCKER|mcr.microsoft.com/azure-functions/python:2.0.13351-python3.6-appservice`. You can find it on [azure functions docker](https://github.com/Azure/azure-functions-docker) repo.

For the premium and consumption plan, we need `WEBSITE_CONTENTAZUREFILECONNECTIONSTRING` and `WEBSITE_CONTENTSHARE`.

```json
        {
            "apiVersion": "2018-11-01",
            "name": "[parameters('name')]",
            "type": "Microsoft.Web/sites",
            "kind": "functionapp,linux",
            "location": "[parameters('location')]",
            "tags": {},
            "dependsOn": [
                "[resourceId('microsoft.insights/components', parameters('appInsightsName'))]",
                "[resourceId('Microsoft.Web/serverfarms', parameters('hostingPlanName'))]",
                "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]"
            ],
            "properties": {
                "name": "[parameters('name')]",
                "siteConfig": {
                    "appSettings": [
                        {
                            "name": "FUNCTIONS_EXTENSION_VERSION",
                            "value": "~3"
                        },
                        {
                            "name": "FUNCTIONS_WORKER_RUNTIME",
                            "value": "[parameters('functionWorkerRuntime')]"
                        },
                        {
                            "name": "APPINSIGHTS_INSTRUMENTATIONKEY",
                            "value": "[reference(concat('microsoft.insights/components/', parameters('appInsightsName')), '2015-05-01').InstrumentationKey]"
                        },
                        {
                            "name": "APPLICATIONINSIGHTS_CONNECTION_STRING",
                            "value": "[reference(concat('microsoft.insights/components/', parameters('appInsightsName')), '2015-05-01').ConnectionString]"
                        },
                        {
                            "name": "AzureWebJobsStorage",
                            "value": "[concat('DefaultEndpointsProtocol=https;AccountName=',parameters('storageAccountName'),';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2019-06-01').keys[0].value,';EndpointSuffix=','core.windows.net')]"
                        },
                        {
                            "name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING",
                            "value": "[concat('DefaultEndpointsProtocol=https;AccountName=',parameters('storageAccountName'),';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2019-06-01').keys[0].value,';EndpointSuffix=','core.windows.net')]"
                        },
                        {
                            "name": "WEBSITE_CONTENTSHARE",
                            "value": "[concat(toLower(parameters('name')), '94ed')]"
                        }
                    ],
                    "linuxFxVersion": "[parameters('linuxFxVersion')]"
                },
                "serverFarmId": "[concat('/subscriptions/', parameters('subscriptionId'),'/resourcegroups/', parameters('serverFarmResourceGroup'), '/providers/Microsoft.Web/serverfarms/', parameters('hostingPlanName'))]",
                "clientAffinityEnabled": false
            }
        },
```
* [Microsoft.Web sites/config template reference](https://docs.microsoft.com/en-us/azure/templates/microsoft.web/2020-06-01/sites/config)
* [Web Apps - Create Or Update](https://docs.microsoft.com/en-us/rest/api/appservice/webapps/createorupdate#siteconfig)

One of the question is [Why do I need both APPINSIGHTS_INSTRUMENTATIONKEY and APPLICATIONINSIGHTS_CONNECTION_STRING in my Azure Function configuration?](https://stackoverflow.com/questions/60691568/why-do-i-need-both-appinsights-instrumentationkey-and-applicationinsights-connec). You can find the answer on the link.

# What did I google it?

## Deployed not supported region

```
{
    "Code": "BadRequest",
    "Message": "Requested features are not supported in region. Please try another region.",
    "Target": null,
    "Details": [
        {
            "Message": "Requested features are not supported in region. Please try another region."
        },
        {
            "Code": "BadRequest"
        },
        {
            "ErrorEntity": {
                "ExtendedCode": "59911",
                "MessageTemplate": "Requested features are not supported in region. Please try another region.",
                "Parameters": [],
                "Code": "BadRequest",
                "Message": "Requested features are not supported in region. Please try another region."
            }
        }
    ],
    "Innererror": null
}
```

These command shows you the location that available to you for each resources.

```bash
az provider show --namespace Microsoft.Web | jq ".resourceTypes[] | select(.resourceType == \"serverFarms\") | .locations" 
```

* [Products available by region](https://azure.microsoft.com/en-us/global-infrastructure/services/?products=functions)
* [az account list-location](https://github.com/Azure/azure-cli/issues/1520) find locations that you can use.

## The serverFarm property has an incorrect value for App Service Plan

The error message was very confusing. However, it was an issue of this part. It was not the `serverfarms` resource. I forget to add value to `serverFarmResourceGroup`. 

```
"serverFarmId": "[concat('/subscriptions/', parameters('subscriptionId'),'/resourcegroups/', parameters('serverFarmResourceGroup'), '/providers/Microsoft.Web/serverfarms/', parameters('hostingPlanName'))]",
```
The way I identify issue is portal. Even if I deploy from my local machine, if you go to portal and see the deployment history, then you can find which resources causes an issue. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/im5ntvadnveznw8bu1kf.png)

```
Deployment failed. Correlation ID: 95b838bf-3c0d-45f0-9457-0b10c916109f. {
  "Code": "BadRequest",
  "Message": "The serverFarm property has an incorrect value for App Service Plan. Valid values are a plan name as string or of format  subscriptions/subscriptionId/resourceGroups/resourceGroupName/providers/Microsoft.web/serverfarms/planName where the subscription is the same as the site's subscription.",
  "Target": null,
```
# serverframs can not found

I encounter the issue. The reason was, the template that I've got from `donwload automated script` was wrong. It has a section like this. 

```
            "dependsOn": [
                "microsoft.insights/components/tsushijava8trace",
                "[concat('Microsoft.Web/serverfarms/', parameters('hostingPlanName'))]",
                "[concat('Microsoft.Storage/storageAccounts/', parameters('storageAccountName'))]"
            ],
```

`dependsOn` section requires `resourceId` function.

```
            "dependsOn": [
                "[resourceId('microsoft.insights/components', parameters('appInsightsName'))]",
                "[resourceId('Microsoft.Web/serverfarms', parameters('hostingPlanName'))]",
                "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]"
            ],
```

# Lessons Learned

This time, I have no sample, so I can't identify how we can deploy Premium Functions. 

1. Deploy Premium Linux functions from portal and download automated script
2. Deploy Premium Linux functions from portal and see `Export template`
3. Offical Doc [Automate resource deployment for your function app in Azure Functions](https://docs.microsoft.com/en-us/azure/azure-functions/functions-infrastructure-as-code)
5. References [Microsoft.Web serverfarms template reference](https://docs.microsoft.com/en-us/azure/templates/microsoft.web/2020-06-01/serverfarms), [Microsoft.Web sites/config template reference](https://docs.microsoft.com/en-us/azure/templates/microsoft.web/2020-06-01/sites/config)

When I look back, the best way might be... 

1. Learn the basic with the official document. 
2. Deploy Premimu Linux functions from portal and see `Export template`
3. Understand the meaning of the parameters with Reference

The `download automated script` is something I used to use frequently, however, this time, the template does not work. Understand the proper format and check with the `Export template` is the `truth`. 

I hope this helps.