Simplify your deployment with nested Azure Resource Manager (ARM) templates


Most solutions, if not all, are composed of multiple parts: backend, frontend, services, APIs, etc. Because all parts could have a different life-cycle it's important to be able to deploy them individually. However, sometimes we would like to deploy everything at once. It's exactly the scenario I had in a project I'm working on where with backend and one frontend.

In this post, I will explain how I use nested Azure Resource Manager (ARM) templates and conditions to let the user decide if he wants to deploy only the backend or the backend with a frontend of his choice. All the code will be available in GitHub and if you prefer, a video version is available below.
(This post is also available in French)

The Context


The project used in this post my open-source budget-friendly Azure URL Shortener. Like mentioned previously the project is composed of two parts. The backend leverage Microsoft serverless Azure Functions, it a perfect match in this case because it will only run when someone clicks a link. The second part is a frontend, and it's totally optional. Because the Azure Functions are HTTP triggers they act as an API, therefore, they can be called from anything able to do an HTTP call. Both are very easily deployable using an ARM template by a PowerShell or CLI command or by a one-click button directly from GitHub.

The Goal


At the end of this post, we will be able from one-click to deploy just the Azure Functions or to deploy them with a frontend of our choice (I only have one right now, but more will come). To do this, we will modify the "backend" ARM template using condition and nest the ARM template responsible for the frontend deployment.

The ARM templates are available here in there [initial](https://github.com/FBoucher/AzUrlShortener/tree/master/tutorials/optional-arm/before) and [final](https://github.com/FBoucher/AzUrlShortener/tree/master/tutorials/optional-arm/before/after) versions.

Adding New Inputs


We will nest the ARM templates, this means that our backend template (azureDeploy.json) will call the frontend template (adminBlazorWebsite-deployAzure.json). Therefore we need to add all the required information to azureDeploy.json to make sure it's able to deploy adminBlazorWebsite-deployAzure.json successfully. Looking at the parameter required for the second template, we only two need values AdminEMail and AdminPassword. All the other can be generated or we already have them.

We will need also another parameter the will act as our selection option. So let's add a parameter named frontend and allowed only two values: none and adminBlazorWebsite. If the value is none we only deploy the Azure Function. When the value is adminBlazorWebsite we will deploy the Azure Function, of course, but we will also deploy an admin website to go with it.

Following the best practices, we add clear detail and add those three parameters in the parameters section of the ARM template

"frontend": {
    "type": "string",
    "allowedValues": [
        "none",
        "adminBlazorWebsite"
    ],
    "defaultValue": "adminBlazorWebsite",
    "metadata": {
        "description": "Select the frontend that will be deploy. Select 'none', if you don't want any. Frontend available: adminBlazorWebsite, none. "
    }
},
"frontend-AdminEMail": {
    "type": "string",
    "defaultValue": "",
    "metadata": {
        "description": "(Required only if frontend = adminBlazorWebsite) The EMail use to connect into the admin Blazor Website."
    }
},
"frontend-AdminPassword": {
    "type": "securestring",
    "defaultValue": "",
    "metadata": {
        "description": "(Required only if frontend = adminBlazorWebsite) Password use to connect into the admin Blazor Website."
    }
}

Nested Templates


Let's assume for now that we always deploy the website when we deploy the Azure Function, to keep things simple. What we need now is to used nested ARM template, and that when you deploy an ARM template from inside another ARM template. This is done with a Microsoft.Resources/deployments node. Let's look at the code:

{
    "name": "FrontendDeployment",
    "type": "Microsoft.Resources/deployments",
    "dependsOn": [
        "[resourceId('Microsoft.Web/sites/', variables('funcAppName'))]",
        "[resourceId('Microsoft.Web/sites/sourcecontrols', variables('funcAppName'), 'web')]"
    ],
    "resourceGroup": "[resourceGroup().name]",
    "apiVersion": "2019-10-01",
    "properties": {
        "mode": "Incremental",
        "templateLink": {
            "uri": "[variables('frontendInfo')[parameters('frontend')].armTemplateUrl]"
        },
        "parameters": {
            "basename": {
                "value" : "[concat('adm', parameters('baseName'))]"
            },
            "AdminEMail": {
                "value" : "[parameters('frontend-AdminEMail')]"
            },
            "AdminPassword": {
                "value" : "[parameters('frontend-AdminPassword')]"
            },
            "AzureFunctionUrlListUrl": {
                "value" : "[concat('https://', reference(resourceId('Microsoft.Web/sites/', variables('funcAppName')), '2018-02-01').hostNames[0], '/api/UrlList?code=', listkeys(concat(resourceId('Microsoft.Web/sites/', variables('funcAppName')), '/host/default/'),'2016-08-01').functionKeys.default)]"
            },
            "AzureFunctionUrlShortenerUrl": {
                "value" : "[concat('https://', reference(resourceId('Microsoft.Web/sites/', variables('funcAppName')), '2018-02-01').hostNames[0], '/api/UrlShortener?code=', listkeys(concat(resourceId('Microsoft.Web/sites/', variables('funcAppName')), '/host/default/'),'2016-08-01').functionKeys.default)]"
            },
            "GitHubURL": {
                "value" : "[parameters('GitHubURL')]"
            },
            "GitHubBranch": {
                "value" : "[parameters('GitHubBranch')]"
            },
            "ExpireOn": {
                "value" : "[parameters('ExpireOn')]"
            },
            "OwnerName": {
                "value" : "[parameters('OwnerName')]"
            }

        }
    }
}

If we examine this node, we have the classic: name, type, dependsOn, resourceGroup, apiVersion. Here We really want the Azure Functions to be fully deployed so we need the FunctionApp to be created AND the GitHub sync to be complete, this is why there is also a dependency on Microsoft.Web/sites/sourcecontrols.

In properties we will pass the mode as Incremental as it will leave unchanged resources that exist in the resource group but aren't specified in the template.

Learn more about the Azure Resource Manager deployment modes here as they are very powerful.

The second property is templateLink. This is really important as it's the URL to the other ARM template. That URI must not be a local file or a file that is only available on your local network. You must provide a URI value that downloadable as HTTP or HTTPS. In this case, it's a variable that contains the GitHub URL where the template is available.

Finally, we have the parameters, and this is how we pass the values to the second template. Let's skip those where I just pass the parameter value from the caller to the called, and focus on basename, AzureFunctionUrlListUrl, and AzureFunctionUrlShortenerUrl.

For basename I just add a prefix to the parameter basename received, this way the resource names will be different but we can still see the "connection". That's purely optional, you could have added this value in a parameter to azureDeploy.json, I prefer keeping the parameters a minimum as possible as I think it simplifies the deployment for the users.

Finally for AzureFunctionUrlListUrl, and AzureFunctionUrlShortenerUrl I needed to retrieve the URL of the Azure Function with the security token because they are secured. I do that by concatenating different parts.

Component Value
Beginning of the URL 'https://'
Reference the Function App, return the value of hostname reference(resourceId('Microsoft.Web/sites/', variables('funcAppName')), '2018-02-01').hostNames[0]
Specify the Function targeted in this case UrlList. And starting the querystring to pass the code (aka. security token) '/api/UrlList?code='
Using the new listkeys function to retrieve the default Function key. listkeys(concat(resourceId('Microsoft.Web/sites/', variables('funcAppName')), '/host/default/'),'2016-08-01').functionKeys.default

Conditional parts


Now that the second ARM template can be deployed, let's add a condition so it gets, indeed, deploy only when we desire. To do this it's very simple, we need to add a property condition.

{
    "name": "FrontendDeployment",
    "type": "Microsoft.Resources/deployments",
    "condition": "[not(equals(parameters('frontend'), 'none'))]",
    "dependsOn": [
        "[resourceId('Microsoft.Web/sites/', variables('funcAppName'))]",
        "[resourceId('Microsoft.Web/sites/sourcecontrols', variables('funcAppName'), 'web')]"
    ]
}

In this case, is the value of the parameter is different then none, the nested template will be deployed. When a condition end-up being "false", the entire resource will be ignored during the deployment. How simple or complex are your conditions... that's your choice!

Happy deployment. :)




Reading Notes #424


Suggestion of the week

Cloud

Programming

Podcasts

Miscellaneous

  • Visual Studio Codespaces (Nik Molnar) - I really like the new name I think it says more about what it is. And seriously how can I not like the new price! Less than 2$/day for a machine!

Reading Notes #423

Every Monday, I share my "reading notes". Those are the articles, blog posts, podcast episodes, and books that catch my interest during the week and that I found interesting.

It's a mix of the actuality and what I consumed. You think you may have an interesting post, share it!
My office is in the basement... so I didn't conplained.

Cloud

Programming

Podcasts

Miscellaneous


~

Reading Notes #422


Cloud

Programming

Podcasts

Miscellaneous

~


How I Build a Budget-friendly URL Shortener Easy to Deploy and Customized


Available in French here

I don't know for you but I share links/ URLs very often. And a lot of time it's from videos, so it needs to be short and easy to remember. Something like https://c5m.ca/project is better than a random string (aka. GUID). And this is how I started a project to build a URL Shortener. I wanted to be budget-friendly, easy to deploy and customizable.

In this post, I will share how I build it, how you can use it, and how you can help!

Azure Url Shortener

How I build it, with the community


This tool was build during live streams coding sessions on Twitch (all videos are in available in my YouTube archive). It's composed of two parts: a Serverless backend leveraging the Azure Function & Azure Storage, and a frontend of your choice.

The backend is composed of a few Azure Functions that act as an on-demand HTTP API. They only consume when they are called. They are in .Net Core, C# to be specific. When publishing this post, there are four functions:

  • UrlShortener: To create a short URL.
  • UrlRedirect: That's the one called when a short link is used. An Azure Function Proxy is forwarding all call to the root.
  • UrlClickStats: Return the statistic for a specific URL.
  • UrlList: Return the list of all URLs created.

All the information like long url, short url, click count are save in an Azure Storage Table.
And that's it. Super light, very cost-efficient. IF you are curious about the price I'll but references in the footnotes

The frontend could be anything that can make HTTP requests. Right now in the project, I explain how to use a tool call Postman, there is also a very simple interface done that you can easily deploy.



This simple interface is of course protected and gives you the options to see all URLs and create new ones.

How YOU can use it


All the code is available into GitHub, and it's deployable with a one-click button!

Deploy to Azure

This will deploy the backend in your Azure subscription in a few minutes. If you don't own an Azure subscription already, you can create your free Azure account today.

Then you will probably want an interface to create your precious URLs. Once more in the GitHub repository, there is a List of available Admin interfaces and ready to be used. The Admin Blazor Website is currently the most friendly and can also be deployed in one-click.

How You can help and participate


Right now, there is really only one interface (and some instructions on how to use Postman to do the HTTP calls). But AzUrlShortener is an open-source project, meaning you can participate. Here some suggestions:

  • Build a new interface (in the language of your choice)
  • Improve current interface(s) with
    • logos
    • designs
    • Better UI 🙂
  • Register bugs in GitHub
  • Make feature request
  • Help with documentation/ translation

What's Next


Definitely come see the GitHub repo https://github.com/FBoucher/AzUrlShortener, click those deploy buttons. On my side, I will continue to add more features and make it better. See you there!


Video version





References

Reading Notes #421

Every Monday, I share my "reading notes". Those are the articles, blog posts, podcast episodes, and books that catch my interest during the week and that I found interesting.

It's a mix of the actuality and what I consumed. Enjoy!

Programming

  • Try gh, GitHub's new CLI (John Papa) - Oh, that's really nice I like that. I find it funny that t should like you just got a hit in the chest. However, it looks powerful enough to cut your breath... so it probably deserves it.

Podcasts

  • 0241 - Etienne Tremblay - GitHub Actions (Visual Studio Talk Show) - Great episode that compare, discuss, and speculate with GitHub Actions and Azure DevOps. It's in French. I miss you guys it's been too long... Great show.

Miscellaneous


~


Reading Notes #420




Every Monday, I share my "reading notes". Those are the articles, blog posts, podcast episodes, and books that catch my interest during the week and that I found interesting.

It's a mix of the actuality and what I consumed. This week I was less in a reading mode...

Programming


Miscellaneous

Reading Notes #419


Every Monday, I share my "reading notes". Those are the articles, blog posts, podcast episodes, and books that catch my interest during the week and that I found interesting.
It's a mix of the actuality and what I consumed. Enjoy!


Suggestion of the week

  • Approval Workflows With GitHub Actions (Aaron Powell) - Wow! That's a very clever and impressive way to have step flow in GitHub. All the details are in the post if you would like to create your own.

Cloud

Programming

Podcasts

Miscellaneous


Reading Notes #418


Every Monday, I share my "reading notes". Those are the articles, blog posts, podcast episodes, and books that catch my interest during the week and that I found interesting.
It's a mix of the actuality and what I consumed. Enjoy!

Cloud

Programming

Shameless plug

Podcasts

  • Des fonctions courtes, qui font une chose (Les Semi-Colons) - First time for me listening to this podcast, third time for them. A very interesting podcast in "Canadian French". They are passing through the book Clean Code of Robert C. Martin. This episode was about chapter 3.
  • vygl - Le balado Ep.17 (vygl) - Great podcast in French. It was my first try and I really liked it. We can ear the experience of the speaker in their voice but also by the quality of this audio.

Miscellaneous

~



How to know how much your application is consuming on Azure

Are you worried when deploying a new application about our billing? Or afraid that you will receive an invoice from your cloud provider at the and of the month that put you in a bad situation? You are not alone, and this is why you should definitely look at the Azure Cost Manager.



In the video below, I explain how to use the Azure Cost Manager to see the actual cost and forecast for a specific application in the cloud and build a dashboard with your favorites information. Note that I said "cloud" because Azure Cost Manager can monitor both Azure and AWS resources. That's perfect for when we are "in" the portal, and that's why I will also show how you can make budgets, and set alerts, so you can track your resources automatically.



Useful Links


~

Reading Notes #417


Every Monday, I share my "reading notes". Those are the articles, blog posts, podcast episodes, and books that catch my interest during the week and that I found interesting.
It's a mix of the actuality and what I consumed.
Enjoy!


Cloud

Programming

Podcast

Miscellaneous


~


Reading Notes #416

Every Monday, I share my "reading notes". Those are the articles, blog posts, podcast episodes, and books that catch my interest during the week and that I found interesting. 

It's a mix of the actuality and what I consumed. Enjoy!


Cloud

  • Durable Functions Upgrade Strategies (Mark Heath) - A real gold mine of information about best practices when migrating. Of course great when migrating durable functions, but also true for any services.

Programming

  • Announcing PowerShell 7.0 (Joey) - That awesome post will explain what's in PowerShell 7 and why we should care... Because yes... we should.

Podcast

  • #361: The Generosity of Scars with Scott Mann (The EntreLeadership Podcast) - First when I eared the guess was a military I thought it will be full of war references... But no! This episode is all about human. Our self, are we feel alone and strangely the fact that we are not. Great episode and I really liked Scott Mann verbs.

Book

The Infinite Game 

by: Simon Sinek

 I really enjoyed this book. This book gave me vocabulary. It was putting words on ideas, explaining clearly some feelings that I wasn't able to express. Like when you know something is good or bad, but that you can explain why. It's less impressive than Start with Why, but definitely, something to read.


 


Reading Notes #415


Every Monday, I share my "reading notes". Those are the articles, blog posts, podcast episodes, and books that catch my interest during the week and that I found interesting. It's a mix of the actuality and what I consumed.



Cloud

Programming

Miscellaneous

  • What are Azure CLI Extensions? (Michael Crump) - An interesting first article of a series. This one introduces us to the extension... Hmmm. I think I have an idea.
~


Reading Notes #414

Every Monday, I share my "reading notes". Those are the articles, blog posts, podcast episodes, and books that catch my interest during the week and that I found interesting. It's a mix of the actuality and what I consumed.

Cloud

Programming

Podcasts

  • 0240 - Anthony Giretti - Le protocole gRPC (Visual Studio Talk Show) - Nice episode where they talk about gRPC and gRPC web, where it comes from, why it's different than the previous version, and how it's possible to use it with .Net. All that in French!

Miscellaneous

~

Reading Notes #413


Cloud

Programming

Miscellaneous

☁️

Reading Notes #412




Every Monday, I share my reading notes. Those are the articles, blog posts, podcast episodes, and books that catch my interest during the week and that I found interesting. It's a mix of the actuality and what I consumed.


Cloud

Programming

Podcasts

  • #25: Shayne Boyer - Social Coder (The Solo Coder Podcast) - Once again a very nice episode. It was wonderful to discover my colleague to this interview. Well done.

Miscellaneous





Reading Notes #411

Cloud

  • Azure CLI Kung-Fu Tips and Tricks (Dan Patrick) - A true story for a real warrior... This post explains how a well done Azure CLI script can save you in hard conditions.

Programming

Podcast

Reading Notes #410


Every Monday, I share my reading notes. Those are the articles, blog posts, podcast episodes, and books that catch my interest during the week and that I found interesting. It's a mix of the actuality and what I consumed.

Programming

Databases

Podcast

  • Myself: It's not weird at all (Hanselminutes - Fresh Talk and Tech for Developers) - I nice episode much longer than the usual, but the guest is also special... It's Scott. During a Live Stream on Twitch it the Live Coders... People suggest making a podcast episode of the interview... I couldn't agree more.
  • The Power of Humor in Tech with Chloe Condon (Screaming in the Cloud) - Very refreshing episode with the awesome and very colorful Chloe. Nice show that goes to fast. Very interesting discussion about the non-traditional way to technical work, and its success.

Reading Notes #409


Every Monday, I share my reading notes. Those are the articles, blog posts, podcast episodes, and books that catch my interest during the week and that I found interesting. It's a mix of the actuality and what I consumed.

Cloud

Programming

  • CLI vs GitKraken Git GUI Speed Test (Jesus Murillo) - I love GitKraken, I still use the CLI and the integrated git in VSCode, but to really see things... It's the best, and wow it looks cool.

Podcasts

  • #23: John Sonmez - Becoming a Finisher, Part 1 (The Solo Coder Podcast) - I know, read and follow Simpler Programmer. It was so great to heard all the work that was put in to arrive to the current status. So many of us think it's a night success... Looking forward to listening to part 2.

Miscellaneous



Reading Notes #408


Every Monday, I share my reading notes. Those are the articles, blog posts, podcast episodes, and books that catch my interest during the week and that I found interesting. It's a mix of the actuality and what I consumed.

Cloud

Programming

Miscellaneous


☁️

Reading Notes #407


Every Monday, I share my reading notes. Those are the articles, blog posts, podcast episodes, and books that catch my interest during the week and that I found interesting. It's a mix of the actuality and what I consumed.

Cloud

  • Generating Images with Azure Functions (Aaron Powell) - Brilliant usage of Azure function and its the first one I see in F#! All the code is available in GitHub, definitely worth the detour.

Programming

  • Use MongoDB in Your C# ASP.NET Apps (Terje Kolderup) - This is a very complete tutorial the shows all the code and explains step by step how to add, configure and use MongoDB.

Podcasts


Miscellaneous

  • Is that position available for remote? (Mark Downie) - A very interesting post that, I think, explains well the 'behind the scene' of the response we can get when asking the remote question.
~

Reading Notes #406


Every week, I publish my reading notes. Those are the articles, blog posts, podcast episodes, and books that catch my interest and that I found interesting. It's a mix of the actuality and what I was looking for.

My Numbers for 2019

  • This marks the 46 Reading Notes blog post.
  • 20 blog posts in French or English. 
  • 69 live stream on Twitch
  • 33 Cloud 5 Minutes episode in French or English.
  • Many talks in different communities
  • 881 contributions in open-source projects

Looking forward to seeing you all in two days to start 2020 together!



Cloud

Programming

DevOps

Podcasts

Miscellaneous

  • Visualizing Your Work Schedule (Valentin Sawadski) - Interesting project.I'm always looking forward to the best way to track my time and see where I put my effort (aka time).

~

Reading Notes #405


Every week, I publish my reading notes. Those are the articles, blog posts, podcast episodes, and books that catch my interest and that I found interesting. It's a mix of the actuality and what I was looking for. This one is the last of 2019!

Cloud


Programming


Miscellaneous

  • Advice to my 20 year old self (Scott Hanselman) - An Interesting post. But to be honest, the more I think about it the less I would spoil things. So as good or bad as it sounds, my advice would probably just be something like thrust yourself, you'll be fine.
~