Azure functions are great. I used to do a lot of "csx" version (C# scripted version) but more recently I switched to the compile version, and I definitely loved it! However, I was looking for a way to keep my deployment short and sweet, because sometimes I don't have time to setup a "big" CI/CD or simply because sometimes I'm not the one doing the deployment... In those cases, I need a simple script that will deploy everything! In this post, I will share with you how you can deploy everything with one easy script.
The Context
In this demo, I will deploy a simple C# (full .Net framework) Azure functions. I will create the Azure Function App and storage using an Azure Resource Manager (ARM template) and deploy with a method named Zip push or ZipDeploy. All the code, script, a template is available on my Github.
The Azure Functions Code
The Azure Function doesn't have to be special, and it can be any language supported by Azure Functions. Simply to show you everything, here the code of my function.
namespace AzFunctionZipDeploy
{
public static class Function1
{
[FunctionName("GetTopRunner")]
public static async Task Run([HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)]HttpRequestMessage req, TraceWriter log)
{
log.Info("C# HTTP trigger function processed a request.");
string top = req.GetQueryNameValuePairs()
.FirstOrDefault(q => string.Compare(q.Key, "top", true) == 0)
.Value;
if (top == null)
{
dynamic data = await req.Content.ReadAsAsync< object>();
top = data?.top;
}
return top == null
? req.CreateResponse(HttpStatusCode.BadRequest, "Please pass a number to get your top x runner on the query string or in the request body")
: req.CreateResponse(HttpStatusCode.OK, new { message = $"Hello, here is your Top {top} runners", runners = A.ListOf(int.Parse(top)) });
}
}
class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
}
}
It's a really simple function that will return a list of Person generated on the fly. The list will contain as many person as the number passed in parameter. I'm using the very useful GenFu library, from my buddies: ASP.NET Monsters.
The only thing we need to do is to create our compress file (Zip or Rar) that contains everything our project required.
In this case, it's the project file (AzFunction-ZipDeploy.csproj), the function's code (Function1.cs) the host (host.json) and local settings of our function (local.settings.json).
The ARM template
For this demo, we need one Azure Function App. I will use a template that is part of the Azure Quickstart Templates. A quick look to the azuredeploy.parameters.json file and we see that the only parameter we really need to set is the name of our application.
To be able to ZipDeploy, we need to add one Application Setting to let the Kudu interface we need its help to compile our code. To do that let's open the azuredeploy.json and go to the appSettings section. We need to add a new variable named: SCM_DO_BUILD_DURING_DEPLOYMENT and set it to true. After adding the setting it should look like this (see the last one... that's our new one):
Now that all the pieces are ready it's time to put it together one script. In fact, only the two last commands are required; everything else is just stuff to make it easier to re-use it. Check out my previous post 5 Simple Steps to Get a Clean ARM Template, to learn more about the best practices related to ARM template. So let's see that script, it's pretty simple.
# script to Create an Azure Gramophone-PoC Solution
resourceGroupName=$1
resourceGroupLocation=$2
templateFilePath="./arm/azuredeploy.json"
parameterFilePath="./arm/azuredeploy.parameters.json"
dateToken=`date '+%Y%m%d%H%M'`
deploymentName="FrankDemo"$dateToken
# az login
# You can select a specific subscription if you do not want to use the default
# az account set -s SUBSCRIPTION_ID
if !( $(az group exists -g $resourceGroupName) ) then
echo "---> Creating the Resourcegroup: " $resourceGroupName
az group create -g $resourceGroupName -l $resourceGroupLocation
else
echo "---> Resourcegroup:" $resourceGroupName "already exists."
fi
az group deployment create --name $deploymentName --resource-group $resourceGroupName --template-file $templateFilePath --parameters $parameterFilePath --verbose
echo "---> Deploying Function Code"
az functionapp deployment source config-zip -g $resourceGroupName -n zipdeploydemo --src "./zip/AzFunction-ZipDeploy.zip"
echo "---> done <--- code="">--->
The only "new" thing is the last command functionapp deployment source config-zip. That where we specify to the Azure Function App to look to --src to get our source. Because I'm running it locally, the path is pointing to a local folder. However, you could execute this command also in the CloudShell, and that would become a URI... to an Azure Blob Storage by example.
Deploy and Test
If you didn't notice yet, I did my script in bash and Azure CLI. That because I want my script to be compatible with all platforms. Of course, you could have done it in PowerShell or anything else that would call the REST API.
To deploy, just execute the script passing the ResourceGroup name, and its location.
./Deploy-AZ-Gramophone.sh cloud5mins eastus
To get to Function URL, go to the Azure portal (portal.azure.com) and click on the Function App that we just deploy. Click on the function GetTopRunner in this case, and click on the </> Getfunction URL button.
Use that URL in postman and pass another parameter top to see we the deployment ws successful.
In Video Please
If you prefer, I also have a video version of this post.
New Updates for Azure Development in Visual Studio (Visual Studio Team) - Great update to the tooling that makes our life easier... Or at least that reduce (a lot) the pain when starting and deploying a project.
How I choose which services to use in Azure (Barry Luijbregts, Scott Hanselman) - Oh wow! Very interesting video, presenting a nice and structured way to pick our cloud services.
10 Reasons to Use Durable Functions (Mark Heath) - To celebrate his new course about durable function, Mark shares with us his top10 of the best reason with should use durable functions.
Creating PDF on ASP.NET Core (Gunnar Peipman) - Am bookmarking this one. Creating PDF is a common task and that code look "simple".
Data
Power BI Desktop May Feature Summary (Amanda Cofsky) - The monthly updates is always a great new. This month shows more about that new Q&A feature... You may not know about it, but you really want to use it...
Data Encodings and Layout (Clemens Vasters) - Very useful and deep article that provides the best practices for data encoding for different type of situation.
Books
Exactly What to Say, The Magic Words for Influence and Impact
(Phil M. Jones)
I listen to this audio book and really enjoy it. Simple powerful key works selection tat helps us to get where we want to go. It was only about two hours long and I listen to it in one shoot. And I’m mostly certain I will listen to it again.
ISBN 9780692881958
The Subtle Art of Not Giving a F*ck (Mark Manson) -Damn it's good! The title of the book let's me thought it will be very negative. Not giving a fu#*... But it's really not. Quite the opposite in fact. I really like the book and I'm planning to read/listen it another time in... One year. To see what changed.
Imagine you just arrived at the office. You only took a sip or two of your coffee or tea. You look at the tasks that need to be done today (well yesterday based on the request): a new project is starting, and you need to configure everything the team needs to start building that web application. The need a repository, a continuous integration and continuous delivery (CI/CD) pipeline, a place to deploy, monitoring tools, and of course you need to create an environment where they will be able to track their work. Should you panic? No, because you will use the new Azure DevOps Project available in Azure.
Let's Create the project
From the Azure portal (portal.azure.com) click on the plus button and search for "devops". Select DevOps Project, then click on the Create button. Then follow the five steps and Azure will create everything for you.
What is deployed
Your application from many popular frameworks
Automatic full CI/CD pipeline integration
Monitoring with Application Insights
Git Repository
Tasks/ Bugs tracking board
Deployment to the platform of your choice
In Video please!
Conclusion
The DevOps projects are really fantastic and are very useful. The fact that everything is all packaged together and automatically deployed is a considerable time saver. In short, are the Azure DevOps projects worth it? Oh yeah!
Why Developers Should Install WSL Today (Matt Hyon, August Banks) - I love WSL (aka Bash on Windows). It has evolved, and become something much more. After ready this post you will either install it right away or smile because it's already installed.
Why Responsive Web Design? (Chris Love) - A nice post that explains clearly why you really need to think responsive design, even more in 2018.
The RULES of Blogging (Darren Rowse) - If you are already bloging, or thinking about starting, take two minutes and watch this short video... The rules are.... Simple.
You have a solution that is already deployed in Azure, and you would like to reproduce it. You know that Azure Resource Manager (ARM) template could help you to do that, unfortunately, you don't know how to get started. In this post, I will share with you the best practices and how I implement them while working on ARM template.
How to Get your ARM Template
Of course, you could build your ARM template from scratch. However, there many quickstart templates available on GitHubd. Even more, you could also get Azure to generate the template for you!
If your building a new solution, go in the Azure portal (portal.azure.com) and start creating your resource as usual. But stop just before clicking on the Create button. Instead click on the link on his side named Download template and parameters. That will open a new blade where you will be able to download the template, parameters files, and a few scripts in different languages to deploy it.
If your solution is already deployed, you still have a way to get the template. Again, from the Azure portal, go to the resource group of your solution. In the left option panel, click on Automation script.
Step 1 - Use Git
Once you have your ARM template and a parameter file, move them in a folder and initialize a Git Repository. Even if it's only a local one this will give you an infinite of Ctrl-Z. Doing multiple commit along your journey to get a better and cleaner template, you will always have options to get back when your template was "functional".
A fantastic tool to edit ARM template is Visual Studio Code. It's free, it supports natively Git, and you can install great extensions to help you.
Step 2 - Validate, Validate, Validate, then Commit
az groupdeployment validate --resource-groupcloud5mins --template-file .\template.json --parameters .\parameters.json
Step 3 - Reduce the Number of Parameters
Nobody like tons of questions. Too many parameters is exactly like too many questions. So reduce them to the maximum. We cannot just delete those unwanted parameters, but they are still providing important information. Instead move them in the variables section.
You can do that in different ways, let me share mine. I start with the parameter files and bubble-up any parameter that I would like to keep. Next Cut/Paste all the unwanted parameters to a new file. Then I use the multi-cursor selection of VSCode to clean them in 2 clicks.
Once we have all parameters "converted" in variables, copy them into the variables section of the ARM template. You will need to delete the parameter equivalent from the top of the template.
Now that we have a clean list of parameters, and variables, we must fix the references to the converted parameters. To do that replace all
parameters() references by variables().
For exemple this:
parameters('networkInterfaceName')
will become that:
variables('networkInterfaceName')
Now that we have a more respectable list of parameters, we must be sure that what we expect from them is clear. To do that we have two simple feature at our disposal. The first one of course the name. Use a complete and clear name. Resist the temptation to shorten everything or use too many acronyms. The second is to use metadata description. This information will be displayed to users through the portal as tooltips.
"adminUsername": {
"type": "string",
"metadata": {
"description": "Name of Administrator user on the VM"
}
}
Step 4 - Use Use Unique String
When you deploy in Azure some names are global, and by definition need to be unique. This is why adding a suffix or a unique identifier to your named is a good practice. An excellent way to get an identifier is to use the function uniqueString(). This function will create a 64Bits hash based on the information passed in parameter.
In the example just above, we pass the identifier of the resource group and its name. It means that every time you will be deploying in the same resource group and at that location suffix will be the same. However, if your solution is deployed in multiple locations (for a disaster recovery, or another scenario), suffix will have a different value.
To use it, let's say the name of a virtual machine was passed as a parameter. Then we will create a variable and concatenate the parameter and our suffix.
Then instead of using the parameter inside your ARM template, you will be using this new variable.
Step 5 - Use Variables
One of the great strengths of using ARM template is that we can use them over and over. This is why we want to avoid anything that his static name or value. When we generated template from the Azure portal, these templates are a snapshot of that particular instances. The best way to stay structured and avoid too fixed names is to leverage variables.
When you use an ARM template generated from a "live" and already deployed solution the ARM will contains a lot of very specific information about this instance (Comments, ResourceIDs, States, etc.). When you are building a generic template don't hesitate to delete those.
You may wonder why we need the first variable RGName , since the resource group name is already available through the resourceGroup() function? Some resources, like Azure Blob Storage's name, must only contain lowercase characters. By making a variable we avoid repeating the to toLower() every time.
You can concatenate two, or more variables and/or string with the "very popular" function concat(). Sometimes, the name built by all those string is too long. You can trim it by using the function substring(stringToParse, startIndex, length). In this case, the Azure Blob Storage required a name with a maximum of 24 characters.
The best way to build a good template is to think like the people who will use it. Therefore, a developer may not know what the difference between a Standard_D2s_v3, a Standard_F8 or a Standard_H8. But will clearly know if he needs a medium, a large, or a web development VM.
That means that we will create a parameter with only specific values allowed, and base on that simple selection we will take more specific and technical decision. See the declaration of the following parameter.
"EnvironmentSize": {
"type": "string",
"defaultValue": "medium",
"allowedValues": [
"medium",
"large"
],
"metadata": {
"description": "Medium for regular development. Large for huge memory usage"
}
}
This parameter will only allowed two string "medium" or "large", anything else will return a validation error. If nothing is passed the default value will be "medium". And finally using a metadata description to make sure the purpose of the parameter is clear and well defined.
Then you define your variable (ex: TS-Size) as an object with two properties, or as many as you have allowed values. For each of these properties, you could have many other properties.
Then to use it, we just need to chained the variables and parameter. Notice how we have nested square brackets... This will use the TS-Size.medium.VMSize value by default.
I hope you will find those tips as useful, as I found they are. If you have other suggestions or recommendations, don't hesitate to add them in the comment section or reach me out.
Keep VS Code from Becoming an IDE (Ryan Palo) - Great finally! I super happy to see I'm not the only one doing that. Now what we need is a way to quickly change setups... Going from Markdown editor to Azure C# Function.
VS Code can do that?! (Burke Holland and Sarah Drasner) - Pretty cool little tips and tricks with vscode.
Authors Gary Keller, Jay Papasan That book was fantastic, and I really mean it. It helps on so many points! Professional, personal, social... It must be in your library. ISBN: 978-1885167774
I don't know for you, but I don't like losing time. This is why a few years ago I started using scripts to install all the software I need on my computer. Got a new laptop? N You just need to execute this script, go grab a coffee and when I'm back all my favorite (and required) softwares are all installed. On Linux, you could use apt-get, and on Windows, my current favorite is Chocolatey. Recently I needed to use more virtual machine (VM) in the cloud and I deceided that I should try using a Chocolatey script during the deployment. This way once the VM is created the softwares, I need is already installed! This post is all about my journey to get there, all scripts, issues and workarounds will be explained.
The Goal
Creating a new VM on premises applying the OS update and installing all the tools you need (like Visual Stutio IDE) will takes hours... This solution should be done under 10 minutes (~7min in my case).
Once the VM is available, it should have Visual Studio 2017 Enterprise, VSCode, Git and Node.Js installed. In fact, I would like to use the same Chocolatey script I use regularly.
In this post I will use Azure CLI, because it will works on any environment. However, PowerShell can also be use only a few command will be different. The VM will be deploy with an Azure resource Manager (ARM) template. To create and edit the ARM template I like to use VSCode, you don't need it but it's so much easier with it! I use two extension.
The first one Azure Resource Manager Snippets will help by generating the schema for our needs. In a JSON file you just need to type arm en voila! You ahave a long list of ARM template!
The second is Azure Resource Manager Tools. This extension provides language support for ARM and some validate. Very useful...
Creating the ARM Template
To Get started create a new JSon file. Then type arm and select the first option; to get an empty skeleton. Then add an extra line in resources and type again arm. This time scroll until you see arm-vm-windows.
A multi-cursor will allow you to edit the name of your VM everywhere in the file in one shot. Hit Tab to navigate automatically to the userName, and Tab again to go to the password.
Now we have a functional ARM template that we could deploy. However, let's add a few things first.
Searching the Image SKUs by Code
One of my favorite VM images for a DevBox is the one that includes Visual Studio pre-installed. One thing to know is those images are only deployable in an MSDN subscription. To specify wich image you want to use you need to pass a publisher, offer, and sku.
Here how to do it with Azure CLI commands
# List all the Publishers that contain VisualStudio (It's case sensitive)
az vm image list-publishers --location eastus --output table --query "[?contains(name,'VisualStudio')]"
# List all offers for the Publisher MicrosoftVisualStudio
az vm image list-offers --location eastus --publisher MicrosoftVisualStudio --output table
# List all availables SKUs for the Publisher MicrosoftVisualStudio with the Offer VisualStudio
az vm image list-skus --location eastus --publisher MicrosoftVisualStudio --offer VisualStudio --output table
Now that all the information is found, search in the ARM template and replace the current values by the one found. In my case, here are the new values.
Great now we have a VM with Visual Studio but our applications are still not installed. That will be done by adding the Custom Script Extension for Windows to our template. documentation page, a sample schema is there ready to be use.
The last node of your template is currently another extension. For the purpose of this blog post let's remove it. You should have something like this.
We will copy/ paste the snippet from the documentation page a change a few little things. Change the type (thank to our VSCode Extension for that catch). Update the dependencies to reflet our demo.
To use the extension your script needs to be available online. It could be in a blob storage (with some security) or just publicly available. In this case, the script is publicly available from my gist.github page. I created a variable in the variables section that contains the RAW URL of my script, and a reference to that varaibale is used in the fileUris.
The extension will download the script and then execute a function locally. Change the commandToExecute to call our script with unrestricted execution policy.
You have a timed window of ~30 minutes to execute your script. If it takes longer then that, your deployment will fail.
# First, we need a Resource Group
az group create --name frankDemo --location eastus
# ALWAYS, always validate first... you will save a lot of time
az group deployment validate --resource-group frankDemo --template-file /home/frank/Dev/DevBox/FrankDevBox.json
#Finally deploy. This script should take between 5 to 10 minutes
az group deployment create --name FrankDevBoxDemo --resource-group frankDemo --template-file /home/frank/Dev/DevBox/FrankDevBox.json --verbose
What's Next?!
We created one template; you could make it better.
Deploy from anywhere
By moving the computerName, adminUsername, adminPassword, and the script url in the parameters section, you could then put the template in a public place like GitHub. Then with use the one click deploy!
Directly from the Github page or from anywhere you just need to build a URL from those two parts: https://portal.azure.com/#create/Microsoft.Template/uri/ and the HTML Encoded URL to your template.
If my template is available at https://raw.githubusercontent.com/FBoucher/SimpleDevBox/master/azure-deploy.json then the full url become:
It's very easy to forget to turn off those VM. And whatever you are paying for them or your using the limited MSDN credit it's a really good practice to turn them down. Why not do that automatically!
That can be very simply done by adding a new resource in the template.
Do you have to know English to be a Programmer? (Scott Hanselman) - Interesting post... At the end, English may not be a blocker...but you need some base. Otherwise, how could you even read this post!
Copy, Download or Upload from-to any combination of Windows, Linux, OS X, or the cloud
Data is and will always be our primary concern. Whether shaped as text files, images, VM VHDs or any other ways, at some point in time, our data will need to be moved. I already wrote about it previously, and the content of this post is still valuable today, but I wanted to share new options and convert all ground (meaning Linux, Windows and OS X).
Scenarios
Here few scenarios why you would want to move data.
Your Microsoft Azure trial is ending, and you wish to keep all the data.
You are creating a new web application, and all those images need to be moved to the Azure subscription.
You have a Virtual Machine that you would like to move to the cloud or to a different subscription.
...
AZCopy
AzCopy is a fantastic command-line tool for copying data to and from Microsoft Azure Blob, File, and Table storage. At the moment, to write this post AzCopy is only available for Windows users. Another solution will be introduced later in this post for Mac and Linux users. Before AzCopy was only available on Windows. However, recently a second version built with .NET Core Framework is available. The commands are very similar but not exactly the same.
AzCopy on Windows
In his simplest expression, an AzCopy command looks like this:
If you earlier have installed an Azure SDK on your machine, you already have it. By default, AzCopy is installed to %ProgramFiles(x86)%\Microsoft SDKs\Azure\AzCopy (64-bit Windows) or %ProgramFiles%\Microsoft SDKs\Azure\AzCopy (32-bit Windows).
If you need only AzCopy for a server, you can download the latest version of AzCopy.
Let's see some frequent usage. First let's say you need do move all those images from your server to an Azure blob storage.
These examples were simple, but AzCopy is a very powerful tool. I invite you to type one of the following commands to discover more about using AzCopy:
For detailed command-line help for AzCopy: AzCopy /?
For command-line examples: AzCopy /?:Samples
AzCopy on Linux
Before you could install AzCopy you will need to install .Net Core. This is done very simply with few commands.
It is very similar to the original version, but parameters are using -- and - instead of the / and where a : was required, it's now a simple space.
Uploading to Azure
Here an example, to copy a single file GlobalDevopsBootcamp.jpg to an Azure Blob Storage. We pass the full local path to the file into --source, the destination is the full URI, and finally the destination blob storage key. Of course, you could also use SAS token if you prefer.
To copy the image to a second Azure subscription, we use the command the source is now an Azure Storage URI, and we pass the source and the destination keys:
Azure CLI is a set of cross-platform commands for the Azure Platform. It gives tools to manipulate all Azure components, but this post will focus on azure storage features.
There are two versions of the Azure Command-Line Interface (CLI) currently available:
Azure CLI 2.0: written in Python, conpatible only with the Resource Manager deployment model.
Azure CLI 1.0: written in Node.js, compatible with both the classic and Resource Manager deployment models.
Azure CLI 1.0 is deprecated and should only be used for support with the Azure Service Management (ASM) model with "classic" resources.
Installing Azure CLI
Let's start by installing Azure CLI. Of course, you can download an installer but since everything is evolving very fast with not getting it from Node Package Manager (npm). The install will be the same, you just need to specify the version if you absolutely need Azure CLI 1.0.
sudo npm install azure-cli -g
To keep the previous scenario, let's try to copy all images to a blob storage. Unfortunately, Azure CLI doesn't offer the same flexibility as AzCopy,and you must upload the file one by one. However, to upload all images from a folder, we can easily put the command in a loop.
for f in Documents/images/*.jpg
do
azure storage blob upload -a frankysnotes -k YoMjXMDe+694FGgOaN0oaRdOF6s1ktMgkB6pBx2vnAr8AOXm3HTF7tT0NQWvGrWnWj5m4X1U0HIPUIAA== $f blogimages
done
In the previous command -a was the account name, and -k was the Access key. This two information can easily be found in the Azure portal. From the portal (https://portal.azure.com), select the storage account. In the right band click-on Access keys.
To copy a file (ex: a VM disk aka VHD) from one storage to another one in a different subscription or region, it's really easy. This time we will use the command azure storage blob copy start and the -a and -k are related to our destination.
The nice thing about this command is that it's asynchronous. To see the status of your copy just execute the command azure storage blob copy show
azure storage blob copy show -a frankshare -k YoMjXMDe+694FGgOaN0oPaRdOF6s1ktMgkB6pBx2vnAr8AOXm3HTF7tT0NQVxsqhWvGrWnWj5m4X1U0HIPUIAA== imagesbackup 20151011_151451.MOV
Azure CLI 2.0 (Windows, Linux, OS X, Docker, Cloud Shell)
The Azure CLI 2.0 is Azure's new command-line optimized for managing and administering Azure resources that work against the Azure Resource Manager. Like the previous version, it will work perfectly on Windows, Linux, OS X, Docker but also from the Cloud Shell!
Cloud Shell is available right from the Azure Portal, without any plugging.
Uploading to Azure
The command if the same as the previous version except that now the command is named az. Here an example to upload a single file into an Azure Blob Storage.
Let's now copy the file to another Azure subscription. A think to be aware is that --account-name and --account-key are for the destination, even if it's not specified.
If you prefer, I also have a video version of that post.
One More Thing
Sometimes, we don't need to script things, and a graphic interface is much better. For this kind of situation, the must is the Azure Storage Explorer. It does a lot! Upload, download, and manage blobs, files, queues, tables, and Cosmos DB entities. And it works on Windows, macOS, and Linux!
It's just the beginning
This post was just an introduction to two very powerful tools. I strongly suggest to go read in the official documentation to learn more. Use the comment to share all your questions and suggestion.
A flexible new way to purchase Azure SQL Database (Alexander (Sasha) Nosov) - A new kind of hybrid way to get your databases in Azure. It's not a full service, neither full pure VM... It definitely looks like less trouble for better performance.
A really amazing book packed of very interesting advice. Things that you kind of already knew, or at least had a feeling you maybe knew are clearly explained to you.
After reading (or listening) this book, you will know why, and you can decide to fight it or change the when... improve your performance and use your time and energy on something else.