Skip to main content

Command Palette

Search for a command to run...

Deploying your code with ARM templates in Azure Managed Apps

Updated
4 min read
B

Expert generalist • Independent Contractor • Microsoft MVP • Home Assistant enthusiast Hi there! I'm Bogdan Bujdea, a software developer from Romania. I'm currently a .NET independent contractor, and in my free time I get involved in the local .NET community or I'm co-organizing the @dotnetdays conference. I consider myself an expert generalist, mostly because I enjoy trying out new stuff whenever I get the chance and I get bored pretty easily, so on this blog you'll see me posting content from programming tutorials to playing with my smart gadgets.

I'm currently trying to publish an Azure Managed Application in the Azure Marketplace , and one of the issues I've encountered is deploying the code for my Azure Functions and Web Apps.

First, let me show you a simplified structure of the zip file that I submitted for certification:

- createUiDefinition.json
- mainTemplate.json
- nestedtemplates (folder)
   - webapi.json

Here's how it works:

  • the "createUIDefinition.json" file contains the UI that you see in Azure, it's the place where you configure your resources(storage type, name of the app, app service plan, etc.) You can try the Create UI definition sandbox website and see how it works.
  • the "mainTemplate.json" is where you specify what resources you want to create (web apps, databases, storage, virtual machines, etc.)
  • nested templates are a way to separate the creation of your resources so you don't put everything in the "mainTemplate.json" file. In my example, I have just an webapi that I want to deploy so I'll just show this file.

Using these json files you can have the resources created in a matter of minutes, which is pretty cool! However, the Web API needs the code to be deployed, otherwise it will be just an empty Azure Web App, so how do we do that?

Well, we could use a site extension which does the deploy, like this:

{
    "type": "Extensions",
    "apiVersion": "2021-01-01",
    "name": "MSDeploy",
    "dependsOn": [
        "[resourceId('Microsoft.Web/Sites/', variables('appServiceName'))]",
        "[resourceId('Microsoft.Web/Sites/config', variables('appServiceName'), 'connectionstrings')]"
    ],
    "properties": {
        "packageUri": "https://www.mystorage.com\webapi.zip"
    }
}

This site extension will download the zip file from the address I specified in the packageUri property and deploy it inside my Azure Web App. Pretty simple, right?

Well, not exactly...it seems that in order to pass certification, you can't specify external resources, so your code has to be inside the same zip file that you submit for certification. Thankfully, the reviewers pointed me to the right documentation and I was able to figure out what to do, so I'll describe the steps in here as well.

It seems that you are allowed to also deploy scripts or artifacts, not only json files, but you have to follow some rules.

1. Create a zip file of your published app

In my case, I just had to download the artifact generated by my Azure DevOps pipeline, but you can also do it manually if you use the command "dotnet publish" and zip the contents of the "publish" folder.

2. Add the published app inside the zip file

In the root I only have the "createUIDefinition.json" and "mainTemplate.json" files, this is the recommended approach. That's why I created an "artifacts" folder where I placed my published app, so now the structure looked like this:

- createUiDefinition.json
- mainTemplate.json
- nestedtemplates (folder)
   - webapi.json
- artifacts (folder)
   - webapi.zip - this is a zip file with the contents of the "bin\Release\net5.0\publish" folder

3. Point the packageURI property to the location of the zip file

In order to do this we have to allow 2 parameters in the mainTemplate.json file, they are called "_artifactsLocation" and "_artifactsLocationSasToken". DO NOT change their name, because they are automatically initialized during deployment and if you change the name like I did initially then it won't work.

This is how you add them in the parameters of the mainTemplate:

"parameters": {
        "_artifactsLocation": {
            "type": "string",
            "metadata": {
                "description": "The base URI where artifacts required by this template are located including a trailing '/'"
            },
            "defaultValue": "[deployment().properties.templateLink.uri]"
        },
        "_artifactsLocationSasToken": {
            "type": "securestring",
            "metadata": {
                "description": "The sasToken required to access _artifactsLocation.  When the template is deployed using the accompanying scripts, a sasToken will be automatically generated. Use the defaultValue if the staging location is not secured."
            },
            "defaultValue": ""
        }
}

4. Build the URI of the zip file

With these two parameters you can then create a variable that contains the location of the zip file:

"zipUrl": "[uri(parameters('_artifactsLocation'), concat('artifacts/webapi.zip', parameters('_artifactsLocationSasToken')))]"

As you can see, I use the _artifactsLocation as the base URI, then I concatenate the location of the zip file and the SAS token.

5. Use the zipUrl in the deployment of your web api

{
    "type": "Extensions",
    "apiVersion": "2021-01-01",
    "name": "MSDeploy",
    "dependsOn": [
        "[resourceId('Microsoft.Web/Sites/', variables('appServiceName'))]",
        "[resourceId('Microsoft.Web/Sites/config', variables('appServiceName'), 'connectionstrings')]"
    ],
    "properties": {
        "packageUri": "[variables('zipUrl')]"
    },
    "condition": "[not(equals(variables('zipUrl'), ''))]"
}

Now your code will be deployed in the app service that you created.

N

Hi Bogdan, thankyou for sharing this with example template. Well explanation. I tried the same using LinkedIn templates concept but I am getting error like my package size is more than the allowed package size. What do you suggest is the better option in this scenario?

B

Hi Nikhat! Do you know what's the package size that you have? If I remember correctly, the maximum package size is around 1Gb, so you shouldn't try to upload a file larger than this. You can find more info here: https://learn.microsoft.com/en-us/azure/azure-functions/run-functions-from-deployment-package

N

Hi Bogdan Bujdea

Before we publish offer to azure market place, we are publishing the offer locally to service definition catalog. While publishing the azure managed app to the service definition catalog using Linked templates concept i.e., packaging the artifact along with the template files, is giving error that my linked templates package size is more than the allowed size 120MB. Our artifact size itself is around 250MB. What do you suggest would be the solution for this?

N

Hi Bogdan,

Thanks for writing this article. Very nice and I like it.

However, I am confused when you say about zipUrl:

"zipUrl": "[uri(parameters('_artifactsLocation'), concat('artifacts/webapi.zip', parameters('_artifactsLocationSasToken')))]"

Where exactly this line should go and in which template; mainTemplate or other templates.

Thanks, Nirmal

B

Hi Nirmal,

The zipUrl is a variable that you create in mainTemplate.json I am using nested templates so I send the zipUrl as a parameter in each nested template. I will create a Github repo where I will share the code and post the url here, so it will be easier to understand.

N

Bogdan Bujdea Thank you very much.

Look forward to see a link on GitHub.

/Nirmal

Azure Managed Applications

Part 1 of 1

In this series I will show you how to create Azure Managed Applications using ARM templates.