简体   繁体   中英

Deploying Web App for containers using ARM templates

I have been trying to automate deployment of my resources to resource group on Azure. Right now I am using ARM templates and so far I was able to create App Insights and App Service Plan using a template. This is how it looks like:

{
   "apiVersion": "2015-05-01",
   "name": "[variables('servicePlan')]",
   "kind": "linux",
   "type": "Microsoft.Web/serverfarms",
   "location": "[resourceGroup().location]",
   "tags": {
           "displayName": "BTC Push Notification Settings HostingPlan"
    },
    "sku": {
           "name": "[variables('skuNamePlan')]",
           "capacity": "[variables('skuSizePlan')]"
    },
    "properties": {
            "name": "[variables('servicePlan')]"
    }
},
{
    "apiVersion": "2015-05-01",
    "name": "[variables('appInsights')]",
    "type": "Microsoft.Insights/components",
    "location": "southcentralus",
    "tags": {
            "[concat('hidden-link:', resourceGroup().id, '/providers/Microsoft.Web/sites/', variables('appInsights'))]": "Resource",
            "displayName": "BTC Push Notification Settings App Insights"
     },
     "properties": {
            "applicationId": "[variables('appInsights')]"
        }
 }

I am having hard time creating Web App for Containers and pointing it to my docker image using ARM template. I have done it manually and it worked, likewise I did it through azure-cli like this az webapp create --resource-group ExampleGroupAlpina --plan myAppServicePlan --name DockerContainer --deployment-container-image-name this-is-my-image/sample-docker and this worked as well. I would appreciate if anyone could suggest creating this Web App for Containers using ARM Template.

For me none of these other answers worked. With the assistance of Azure support and these other answers I came up with the following template, that succesfully creates an app service plan with an Linux App Service for Containers running a custom Docker image from Azure Container Repository:

{
  "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "environment":{
      "type": "string"
    },
    "location": {
      "type": "string",
      "defaultValue": "[resourceGroup().location]",
      "metadata": {
        "description": "Location (region) for all resources."
      }
    },   
    "appServiceSku": {
      "type": "string",
      "defaultValue": "B1",
      "metadata": {
        "description": "The SKU of App Service Plan "
      }
    },
    "dockerImageName": {
      "type": "string",
      "defaultValue": "_MY_REGISTRY_USERNAME_.azurecr.io/_MY_NAMESPACE_/_MY_DOCKER_IMAGE_NAME_:_TAG_"
    },
    "dockerRegistryUrl": {
      "type": "string",
      "defaultValue": "https://_MY_REGISTRY_USERNAME_.azurecr.io"
    },
    "dockerRegistryUsername": {
      "type": "string",
      "defaultValue": "_MY_REGISTRY_USERNAME_"
    },
    "dockerRegistryPassword": {
      "type": "string",
      "defaultValue": "_MY_REGISTRY_PSW_"
    },
    "_artifactsLocation": {
      "type": "string"
    },
    "_artifactsLocationSasToken": {
      "type": "securestring"
    }
  },
  "variables": {
    "name": "projectname-",
    "webAppPortalName": "[concat(variables('name'), parameters('environment'), '-webapp')]",
    "appServicePlanName": "[concat(variables('name'), parameters('environment'),'-hosting')]",
  "resources": [       
    {
      "apiVersion": "2017-08-01",
      "type": "Microsoft.Web/serverfarms",
      "kind": "linux",
      "name": "[variables('appServicePlanName')]",
      "location": "[parameters('location')]",
      "comments": "This app service plan is used for the web app and slots.",
      "properties": {
        "reserved": true
      },
      "dependsOn": [],
      "sku": {
        "name": "[parameters('appServiceSku')]"
      }
    },
    {
      "type": "Microsoft.Web/sites",
      "apiVersion": "2016-08-01",
      "name": "[variables('webAppPortalName')]",
      "kind": "app,linux,container",
      "location": "[parameters('location')]",
      "dependsOn": [
        "[resourceId('Microsoft.Web/serverfarms', variables('appServicePlanName'))]"
      ],
      "properties": {
        "name": "[variables('webAppPortalName')]",
        "siteConfig": {
          "linuxFxVersion": "[concat('DOCKER|', parameters('dockerImageName'))]",
          "alwaysOn": true,
          "appSettings": [
            {
              "name": "WEBSITES_ENABLE_APP_SERVICE_STORAGE",
              "value": "false"
            },
            {
              "name": "DOCKER_REGISTRY_SERVER_URL",
              "value": "[parameters('dockerRegistryUrl')]"
            },
            {
              "name": "DOCKER_REGISTRY_SERVER_USERNAME",
              "value": "[parameters('dockerRegistryUsername')]"
            },
            {
              "name": "DOCKER_REGISTRY_SERVER_PASSWORD",
              "value": "[parameters('dockerRegistryPassword')]"
            }
          ]
        },
        "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('appServicePlanName'))]"
      }
    }
  ]
}

_artifactsLocation and _artifactsLocationSasToken do not need values, but somehow they need to be included. The main difference to other answers is the inclusion of the reserved attribute in the properties for the App Service Plan.

Hopefully this saves some of the headache this created for me!

The following ARM template worked for me.

  • It allows to specify the authentication details of a private Azure Container Registry.
  • Also make sure the docker image name follows this pattern: _MY_REGISTRY_USERNAME_-on.azurecr.io/_MY_NAMESPACE_/_MY_DOCKER_IMAGE_NAME_:latest

I run the az command like this:

az group deployment create \
  --name "deployAzureApp" \
  --resource-group <MY_RESOURCE_GROUP_NAME> \
  --template-file <MY_ARM_JSON_TEMPLATE>.json  --verbose --debug

Here's the Azure Resource Manager (ARM) JSON template:

{
  "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "appName": {
      "type": "String",
      "defaultValue": "_MY_APP_NAME_"
    },
    "dockerImageName": {
      "type": "String",
      "defaultValue": "_MY_REGISTRY_USERNAME_-on.azurecr.io/_MY_NAMESPACE_/_MY_DOCKER_IMAGE_NAME_:latest"
    },
    "dockerRegistryUrl": {
      "type": "String",
      "defaultValue": "https://_MY_REGISTRY_USERNAME_-on.azurecr.io"
    },
    "dockerRegistryUsername": {
      "type": "String",
      "defaultValue": "_MY_REGISTRY_USERNAME_"
    },
    "dockerRegistryPassword": {
      "type": "String",
      "defaultValue": "_MY_REGISTRY_PSW_"
    },
    "servicePlanName": {
      "type": "String",
      "defaultValue": "_MY_SERVICE_PLAN_NAME_"
    },
    "appLocation": {
      "type": "String",
      "defaultValue": "_MY_REGION_"
    }
  },
  "resources": [
    {
      "type": "Microsoft.Web/sites",
      "apiVersion": "2016-08-01",
      "name": "[parameters('appName')]",
      "kind": "app,linux,container",
      "location": "[parameters('appLocation')]",
      "properties": {
        "name": "[parameters('appName')]",
        "siteConfig": {
          "linuxFxVersion": "[concat('DOCKER|', parameters('dockerImageName'))]",
          "alwaysOn": true,
          "appSettings": [
            {
              "name": "WEBSITES_ENABLE_APP_SERVICE_STORAGE",
              "value": "false"
            },
            {
              "name": "DOCKER_REGISTRY_SERVER_URL",
              "value": "[parameters('dockerRegistryUrl')]"
            },
            {
              "name": "DOCKER_REGISTRY_SERVER_USERNAME",
              "value": "[parameters('dockerRegistryUsername')]"
            },
            {
              "name": "DOCKER_REGISTRY_SERVER_PASSWORD",
              "value": "[parameters('dockerRegistryPassword')]"
            }
          ]
        },
        "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', parameters('servicePlanName'))]"
      }
    }
  ]
}

About Azure Web App for Container, actually, there is just one point different with Azure Web App in the template. The point is the kind type.

Azure Web App:

"kind": "app"

Azure Web App for Container:

"kind": "app,linux,container",

So, you can create the Azure Web App for Container using template just setting up the kind with app,linux,container .

Update

I do the test and find out that the website kind is not the most important. The key is the property of the website:

"siteConfig": {
                    "linuxFxVersion": "DOCKER|nginx"
                },

And the template will like below and it does a good job.

{
    "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "webAppName": {
            "type": "string",
            "metadata": {
                "description": "Base name of the resource such as web app name and app service plan "
            },
            "minLength": 2
        },
        "sku": {
            "type": "string",
            "defaultValue": "S1",
            "metadata": {
                "description": "The SKU of App Service Plan "
            }
        },
        "location": {
            "type": "string",
            "defaultValue": "[resourceGroup().location]",
            "metadata": {
                "description": "Location for all resources."
            }
        }
    },
    "variables": {
        "webAppPortalName": "[concat(parameters('webAppName'), '-webapp')]",
        "appServicePlanName": "[concat('AppServicePlan-', parameters('webAppName'))]"
    },
    "resources": [
        {
            "apiVersion": "2017-08-01",
            "type": "Microsoft.Web/serverfarms",
            "kind": "linux",
            "name": "[variables('appServicePlanName')]",
            "location": "[parameters('location')]",
            "comments": "This app service plan is used for the web app and slots.",
            "properties": {},
            "dependsOn": [],
            "sku": {
                "name": "[parameters('sku')]"
            }
        },
        {
            "apiVersion": "2016-08-01",
            "type": "Microsoft.Web/sites",
            "name": "[variables('webAppPortalName')]",
            "location": "[parameters('location')]",
            "comments": "This is the web app, also the default 'nameless' slot.",
            "properties": {
                "name": "[parameters('webAppName')]",
                "siteConfig": {
                    "appCommandLine": "",
                    "linuxFxVersion": "DOCKER|nginx"
                },
                "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('appServicePlanName'))]"
            },
            "dependsOn": [
                "[resourceId('Microsoft.Web/serverfarms', variables('appServicePlanName'))]"
            ]
        }
    ]
}

For what I observed, the linuxFxVersion problem depends on the App Service Plan where the Web App is hosted. What helped me was to set the reserved property on the properties object of App Service Plan resource to true .

What Microsoft doumentation says about the reserved setting:

If Linux app service plan true, false otherwise.

It says nothing about its default value, but from what I observed its false .

This is how my App Service Plan resource ARM template looks like.

{
  "type": "Microsoft.Web/serverfarms",
  "apiVersion": "2019-08-01",
  "name": "[variables('appServicePlanName')]",
  "location": "[parameters('location')]",
  "sku": {
    "name": "[parameters('appServicePlanSkuName')]",
    "tier": "[parameters('appServicePlanSkuTier')]",
    "size": "[parameters('appServicePlanSkuSize')]",
    "family": "[parameters('appServicePlanSkuFamily')]",
    "capacity": "[parameters('appServicePlanSkuCapacity')]"
  },
  "kind": "linux",
  "properties": {
    "name": "[variables('appServicePlanName')]",
    "reserved": true
  }
}

The above template doesn't work now and will show the following logs-

[error]BadRequest: {
  "Code": "BadRequest",
  "Message": "The parameter LinuxFxVersion has an invalid value.",
  "Target": null,
  "Details": [
    {
      "Message": "The parameter LinuxFxVersion has an invalid value."
    },
    {
      "Code": "BadRequest"
    },
    {
      "ErrorEntity": {
        "ExtendedCode": "01007",
        "MessageTemplate": "The parameter {0} has an invalid value.",
        "Parameters": [
          "LinuxFxVersion"
        ],
        "Code": "BadRequest",
        "Message": "The parameter LinuxFxVersion has an invalid value."
      }
    }
  ],
  "Innererror": null
}

To fix this, We can make it 2 steps deployment process as mentioned in the following blog Updated Solution

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM