Deploying a Website with Content through Visual Studio with Resource Groups
UPDATED: This post has been updated to reflect the recent changes.
If you are like me you were glued to the computer watching all of the Build and Ignite sessions, what an exciting couple weeks. One of the great things that came out was the Azure SDK 2.6 for .NET. With this we got..
- Azure Resource Manager Tools
- Diagnostics improvements for Cloud Services
- Azure App Service Tools
- HDInsight tools
I am going to focus on Resource Manager Tools. If you have not played with Azure Resource Manager (ARM) you are missing out, it has some great features over the existing Service Management tools. One of these is being able to deploy resource groups, now you may be saying well Resource Groups have been around for a while. While that is the case there is a lot of great new things that were announced. The new v2 versions of VMs, Storage Accounts, Network adapters.. these are all amazing things.
In this blog though I am going to take you through deploying a full functional website leveraging Resource Groups, Visual Studio and WebDeploy.
Before starting visit the download site https://azure.microsoft.com/en-us/downloads/ to download the SDK for your version of Visual Studio.
Create your web content
For the sake of the blog I will step you through creating example content for your site, for this you will need to launch Visual Studio, Create a new ASP.NET Web Application.
For this example lets choose Web API which should be the default and click OK. While you may be tempted to click Host in the cloud, leave that unchecked for now. Visual Studio does a great job of deploying websites to Azure and adding Application Insights, but we are going to do it differently.
Now lets right click the Project name and click Publish, for the publish target click Custom and give it a name and click Ok
For the Publish method we are going to choose a Web Deploy Package, this way we can save the package offline on our system and use that to deploy out our site, choose a Package location and give your site a name, finally click Publish. Now note where you saved that package as we are going to use it a little later.
Create your Resource Group Project
Keeping that existing solution opened we created, create a new Project in the solution by Right Clicking the solution, choose Add then New Project…
Choos Visual C#, Cloud and Azure Resource Group, give your project a name and click OK this will create another project in our solution specifically for our Resource Group.
Now there is already a template for Web App here, but I am going to take you through creating this from a blank template so you get a better understanding of the capabilities. Find Blank Template and click OK.
Expand out the Templates folder and double click DeploymentTemplate.json, and a basically empty json document will open, here it has the major components to a Resource Group Template
- Parameters – These will be used to pass data into your Resource Group Template Deployment
- Variables – These help will defining variables that can be used to define values you may reuse
- Resources – These are the resources that you will be adding to the resource group (NICS, VMs, Websites, etc)
- Output – This is for defining any output that you may have.
All of these items are shown as well in the left panel in the JSON Outline window. These will be our graphical representation of our JSON file. Go ahead and click the cube with the plus sign to add a Resource. For the Website we are going to create we need 4 different items.
- App Service Plan
- Application Insights for Web Apps
- Web App
- Web Deploy for Web Apps
First Choose the App Service Plan (Server Farm) give it a name and click Add
You will see in the outline by adding that Resource we now have 1 Resource and 4 Parameters.. These parameters come with the App Service Plan Template
If you click on any of the Parameters it will focus the DeploymentTemplate.json file to the item you clicked. As you notice those parameters have their definitions, all are string values, but the SerferFarmSKU and ServerFarmWorkerSize have defined values they can be. This is useful to force people when reusing your template to make sure they put in correct values. For instance the SKU relates to the type of website, in Azure we have Free Shared, Basic and Standard.
There is nothing left to do now for the App Service Plan so lets move on to the Web App. Click the Cube with a plus in the JSON Outline window and choose a Web App this time, give it a name, now you will notice since your file already has a Service Plan it will be automatically selected. This is great as it will build out your dependencies for you in the JSON Template file. Once you are done go ahead and click Add
So now if we wanted to deploy it now we could and have a basic website. But remember we created that Web Deploy Package earlier. Lets get that Web Deploy Package as well. Click the cube with the plus sign and choose Web Deploy for Web Apps. Give it a name and just as before the dependencies, in this case a Web App was already selected. Now just click Add
By now if you look in the JSON Outline we have some more items for the Web App and the Web Deploy for Web Apps. Take note that the Web Deploy for Web Apps is nested under the WebApp, it is a child in the hierarchy.
Now we need to get that Web Deploy Package we created earlier where it needs to be. First we need to quickly Build what we have so far. On the Menu click Built and then Build Solution.
Once the build is done we will right click the Project and choose Open Folder in File Explorer, when the folder opens navigate to bin\Debug\Artifacts\<Project Name>
Navigate to where you saved your Web Deploy Package and paste it in this folder. This file needs to be in the folder as when you deploy the deployment script will look in this folder for any artifacts and can deploy them to a storage account to be referenced later by the script later.
Now we will go ahead and add Application Insights to the Web App, again click the cube with the plus signs, this time choose Application Insights for Web Apps. Give it a Name and as noted before since we only have one App Service Plan and one Web App they are already preselected. Then click Add to add it to our resource group
For the sake of this blog post we wont modify the JSON but as you can see it added a few predefined settings for AppInsights, CPU, Queues, Server Errors, etc to be monitored.
Now we are just about ready to deploy. In the Solution Explorer, right click your project, choose deploy and New Deployment…
When the window pops up if not already signed in click the Sign In button
Once you are signed in, choose your subscription, you could add this to an existing Resource Group but we will add it to a new one for the sake of the blog post. Pull down the drop down on Resource Group and choose <Create New…>
Give the Resource Group a name and choose a location, we will use this location later as well.
Choose a Storage account for your Artifacts, in this case our Web Deploy package, this can not be created on the fly it must be an existing one in your subscription. When you are ready click Deploy.
When you click deploy you will get an Edit Parameters window. In here we need to fill in the parameters. These could be updated in your azuredeploy.parameters.json file, but since we just have a few options we will fill it out by hand. As you can see the SKU and Worker Size we saw earlier are drop down boxes, that is because we allowed it to have a few different values. Since we put our Web Deploy package in the main folder, put in your Project name, this folder will be created by default, if you were to make a sub folder you could enter it as <ProjectName>\<Myfolder>. Fill out the fields and click Save
When you are done you will see output similar to below.
20:39:02 - Build started.
20:39:02 – Project "MyAwesomeWebsiteResourceGroup.deployproj" (StageArtifacts target(s)):
20:39:02 - Project "MyAwesomeWebsiteResourceGroup.deployproj" (ContentFilesProjectOutputGroup target(s)):
20:39:02 - Done building project "MyAwesomeWebsiteResourceGroup.deployproj".
20:39:02 - Done building project "MyAwesomeWebsiteResourceGroup.deployproj".
20:39:02 - Build succeeded.
20:39:02 - The following parameter values will be used for this deployment:
20:39:02 - MyAwesomeWebsiteServerFarmName: MyAwesomeWebsite
20:39:02 - MyAwesomeWebsiteServerFarmSKU: Free
20:39:02 - MyAwesomeWebsiteServerFarmWorkerSize: 0
20:39:02 - _artifactsLocation:
20:39:02 - _artifactsLocationSasToken: <securestring>
20:39:02 - MyAwesomeWebsiteWebDeployPackageFolder: MyAwesomeWebsiteResourceGroup
20:39:02 - MyAwesomeWebsiteWebDeployPackageFileName: MyAwesomeWebSite.zip
20:39:02 - Launching deployment PowerShell script with the following command:
20:39:02 - 'c:\users\username\documents\visual studio 2015\projects\myawesomewebsiteresourcegroup\myawesomewebsiteresourcegroup\Scripts\Deploy-AzureResourceGroup.ps1' -StorageAccountName 'azril302gvbf' -ResourceGroupName 'azril302nbv' -ResourceGroupLocation 'eastus' -TemplateFile 'c:\users\username\documents\visual studio 2015\projects\myawesomewebsiteresourcegroup\myawesomewebsiteresourcegroup\templates\azuredeploy.json' -TemplateParametersFile 'c:\users\username\documents\visual studio 2015\projects\myawesomewebsiteresourcegroup\myawesomewebsiteresourcegroup\templates\azuredeploy.parameters.json' -ArtifactStagingDirectory '..\bin\Debug\staging' -UploadArtifacts -StorageAccountResourceGroupName 'azril302nbv'
20:39:09 -
20:39:09 -
20:39:09 - Environment : AzureCloud
20:39:09 - Account : username@live.com
20:39:09 - TenantId : xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
20:39:09 - SubscriptionId : xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
20:39:09 - CurrentStorageAccount :
20:39:09 -
20:39:54 -
20:39:54 - Transfer summary:
20:39:54 - -----------------
20:39:54 - Total files transferred: 10
20:39:54 - Transfer successfully: 10
20:39:54 - Transfer failed: 0
20:39:54 - Elapsed time: 00.00:00:41
20:39:54 - https://azril302gvbf.blob.core.windows.net/azril302nbv-stageartifacts
20:39:55 - [VERBOSE] 8:39:55 PM - Created resource group 'azril302nbv' in location 'eastus'
20:39:56 -
20:39:56 - ResourceGroupName : azril302nbv
20:39:56 - Location : eastus
20:39:56 - Resources : {bob0, bob2, CPUHigh MyAwesomeWebsite, CPUHigh
20:39:56 - qq2w43141245125...}
20:39:56 - ResourcesTable :
20:39:56 - Name Type
20:39:56 - Location
20:39:56 - =============================================
20:39:56 - ======================================= ==============
20:39:56 - bob0
20:39:56 - Microsoft.Compute/virtualMachines eastus
20:39:56 - bob2
20:39:56 - Microsoft.Compute/virtualMachines eastus
20:39:56 - CPUHigh MyAwesomeWebsite
20:39:56 - Microsoft.Insights/alertrules eastus
20:39:56 - CPUHigh qq2w43141245125
20:39:56 - microsoft.insights/alertrules eastus
20:39:56 - ForbiddenRequests georgenugettestdave
20:39:56 - microsoft.insights/alertrules eastus
20:39:56 - ForbiddenRequests MyAwesomeWebSiteAppInsights
20:39:56 - Microsoft.Insights/alertrules eastus
20:39:56 - LongHttpQueue MyAwesomeWebsite
20:39:56 - Microsoft.Insights/alertrules eastus
20:39:56 - LongHttpQueue qq2w43141245125
20:39:56 - microsoft.insights/alertrules eastus
20:39:56 - ServerErrors georgenugettestdave
20:39:56 - microsoft.insights/alertrules eastus
20:39:56 - ServerErrors MyAwesomeWebSiteAppInsights
20:39:56 - Microsoft.Insights/alertrules eastus
20:39:56 - MyAwesomeWebsite-azril302nbv
20:39:56 - Microsoft.Insights/autoscalesettings eastus
20:39:56 - qq2w43141245125-azril302nbv
20:39:56 - microsoft.insights/autoscalesettings eastus
20:39:56 - georgenugettestdave
20:39:56 - microsoft.insights/components centralus
20:39:56 - MyAwesomeWebSiteAppInsights
20:39:56 - Microsoft.Insights/components centralus
20:39:56 - nic0
20:39:56 - Microsoft.Network/networkInterfaces eastus
20:39:56 - nic2
20:39:56 - Microsoft.Network/networkInterfaces eastus
20:39:56 - asdasd
20:39:56 - Microsoft.Network/networkSecurityGroups northcentralus
20:39:56 - publicIP0
20:39:56 - Microsoft.Network/publicIPAddresses eastus
20:39:56 - publicIP2
20:39:56 - Microsoft.Network/publicIPAddresses eastus
20:39:56 - 1qa2sanetwork
20:39:56 - Microsoft.Network/virtualNetworks eastus
20:39:56 - azril302gvbf
20:39:56 - Microsoft.Storage/storageAccounts eastus
20:39:56 - MyAwesomeWebsite
20:39:56 - Microsoft.Web/serverFarms eastus
20:39:56 - qq2w43141245125
20:39:56 - Microsoft.Web/serverFarms eastus
20:39:56 - georgenugettestdave
20:39:56 - Microsoft.Web/sites eastus
20:39:56 - MyAwesomeWebsitepjeak2lppue2k
20:39:56 - Microsoft.Web/sites eastus
20:39:56 -
20:39:56 - ProvisioningState : Succeeded
20:39:56 - Tags : {}
20:39:56 - TagsTable :
20:39:56 - ResourceId : /subscriptions/590d019c-bc64-4ce4-a118-002c35d4086b/resourc
20:39:56 - eGroups/azril302nbv
20:39:56 -
20:40:01 - [VERBOSE] 8:40:01 PM - Create template deployment 'azuredeploy-0323-0239'.
20:40:04 - [VERBOSE] 8:40:04 PM - Resource Microsoft.Web/serverfarms 'MyAwesomeWebsite' provisioning status is succeeded
20:40:09 - [VERBOSE] 8:40:09 PM - Resource Microsoft.Insights/alertrules 'CPUHigh MyAwesomeWebsite' provisioning status is succeeded
20:40:09 - [VERBOSE] 8:40:09 PM - Resource Microsoft.Insights/alertrules 'LongHttpQueue MyAwesomeWebsite' provisioning status is succeeded
20:40:09 - [VERBOSE] 8:40:09 PM - Resource Microsoft.Insights/autoscalesettings 'MyAwesomeWebsite-azril302nbv' provisioning status is succeeded
20:40:55 - [VERBOSE] 8:40:55 PM - Resource Microsoft.Web/sites 'MyAwesomeWebsitepjeak2lppue2k' provisioning status is succeeded
20:41:02 - [VERBOSE] 8:41:02 PM - Resource Microsoft.Insights/alertrules 'ForbiddenRequests MyAwesomeWebSiteAppInsights' provisioning status is succeeded
20:41:05 - [VERBOSE] 8:41:05 PM - Resource Microsoft.Insights/alertrules 'ServerErrors MyAwesomeWebSiteAppInsights' provisioning status is succeeded
20:41:05 - [VERBOSE] 8:41:05 PM - Resource Microsoft.Web/sites/extensions 'MyAwesomeWebsitepjeak2lppue2k/MSDeploy' provisioning status is running
20:41:05 - [VERBOSE] 8:41:05 PM - Resource Microsoft.Insights/components 'MyAwesomeWebSiteAppInsights' provisioning status is succeeded
20:41:11 - [VERBOSE] 8:41:11 PM - Resource Microsoft.Web/sites/extensions 'MyAwesomeWebsitepjeak2lppue2k/MSDeploy' provisioning status is succeeded
20:41:15 -
20:41:15 - DeploymentName : azuredeploy-0323-0239
20:41:15 - CorrelationId : 9bd2d07e-56b5-4c67-8d05-6849a35f366e
20:41:15 - ResourceGroupName : azril302nbv
20:41:15 - ProvisioningState : Succeeded
20:41:15 - Timestamp : 3/23/2016 2:41:10 AM
20:41:15 - Mode : Incremental
20:41:15 - TemplateLink :
20:41:15 - TemplateLinkString :
20:41:15 - Parameters : {[myAwesomeWebsiteServerFarmName, Microsoft.Azure.Commands
20:41:15 - .Resources.Models.DeploymentVariable],
20:41:15 - [myAwesomeWebsiteServerFarmSKU, Microsoft.Azure.Commands.R
20:41:15 - esources.Models.DeploymentVariable],
20:41:15 - [myAwesomeWebsiteServerFarmWorkerSize, Microsoft.Azure.Com
20:41:15 - mands.Resources.Models.DeploymentVariable],
20:41:15 - [_artifactsLocation, Microsoft.Azure.Commands.Resources.Mo
20:41:15 - dels.DeploymentVariable]...}
20:41:15 - ParametersString :
20:41:15 - Name Type Value
20:41:15 - =============== ========================= ==========
20:41:15 - myAwesomeWebsiteServerFarmName String
20:41:15 - MyAwesomeWebsite
20:41:15 - myAwesomeWebsiteServerFarmSKU String
20:41:15 - Free
20:41:15 - myAwesomeWebsiteServerFarmWorkerSize String
20:41:15 - 0
20:41:15 - _artifactsLocation String https://azr
20:41:15 - il302gvbf.blob.core.windows.net/azril302nbv-stageartifacts
20:41:15 - _artifactsLocationSasToken SecureString
20:41:15 -
20:41:15 - myAwesomeWebsiteWebDeployPackageFolder String
20:41:15 - MyAwesomeWebsiteResourceGroup
20:41:15 - myAwesomeWebsiteWebDeployPackageFileName String
20:41:15 - MyAwesomeWebSite.zip
20:41:15 -
20:41:15 - Outputs : {}
20:41:15 - OutputsString :
20:41:15 -
20:41:16 -
20:41:16 -
20:41:16 -
20:41:16 - Successfully deployed template 'c:\users\username\documents\visual studio 2015\projects\myawesomewebsiteresourcegroup\myawesomewebsiteresourcegroup\templates\azuredeploy.json' to resource group 'azril302nbv'.
When it is done give it a few minutes for the web deploy to finish and then navigate to your website… you will see the .net example we deployed is now there.
MyAwesomeWebsiteResourceGroup.zip
Comments
- Anonymous
November 10, 2015
Excellent! I spent ages searching for how to do this! ( By the way, small correction Save your changes and we are NOW ready to deploy ) - Anonymous
December 14, 2015
I am getting below error while following your steps, any help in finding out where I went wrong would be very useful
15:27:29 - [ERROR] New-AzureRmResourceGroupDeployment : 15:27:29 - Resource
15:27:29 - [ERROR] Microsoft.Web/sites/extensions 'WebAppui/MSDeploy' failed
15:27:29 - [ERROR] with message 'The resource operation completed with terminal provisioning
15:27:29 - [ERROR] state 'Failed'.'
15:27:29 - [ERROR] At C:projectstreamingoct16azureresourcegroupScriptsDeploy-AzureResourceG
15:27:29 - [ERROR] roup.ps1:99 char:1
15:27:29 - [ERROR] + New-AzureRmResourceGroupDeployment -Name ((Get-ChildItem
15:27:29 - [ERROR] $TemplateFile).BaseName ...
15:27:29 - [ERROR] + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
15:27:29 - [ERROR] ~~~
15:27:29 - [ERROR] + CategoryInfo : NotSpecified: (:) [New-AzureRmResourceGroupDeplo
15:27:29 - [ERROR] yment], Exception
15:27:29 - [ERROR] + FullyQualifiedErrorId : Microsoft.Azure.Commands.Resources.NewAzureResou
15:27:29 - [ERROR] rceGroupDeploymentCommand
15:27:29 - [ERROR] - Anonymous
December 14, 2015
Excellent article !
a href="http://jeanclaudegonnet.hautetfort.com/">Jean-Claude Gonnet - Anonymous
March 19, 2016
The comment has been removed - Anonymous
March 19, 2016
I followed the steps from this article (and from others), but deployment always fails. When I check error logs (as described in my previous comment) I see: AppGallery Deploy Failed: 'Microsoft.WindowsAzure.StorageClient.StorageClientException: The value for one of the HTTP headers is not in the correct format.
Has anyone else seen this error? Thanks - Anonymous
March 20, 2016
I know I need to update the article as the latest SDK changes have changed how it works.. I.e artifacts folder no long exists. That said, it sounds like the uri for your artifact that you are referencing is not correct, can you share what you have foe the path? - Anonymous
March 21, 2016
Thanks for coming back to me George!
It would be awesome to update the article, but there weren't a many changes to be honest.. it was still easy to follow.
Anyway, I believe that my paths are correct. I've made some screenshots showing it.
Here is the error message I see on Kudu:
http://i.imgur.com/TfNAcjk.png
Here is the content of my blob (the paths are the same as in the above image):
http://i.imgur.com/PVeccVY.png
That's the output of running Deployment from VS:
http://i.imgur.com/q9C2oIA.png
(probably not interesting)
Could you please check if there is some obvious mistake which I am missing? Thanks!
Thanks a lot for this article btw.. it is surprisingly difficult to find documentation about Azure resource manager. - Anonymous
March 22, 2016
I posted a question on SO: http://stackoverflow.com/questions/36152165/how-to-deploy-package-to-azure-web-app-using-msdeploy-extension-the-value-for - Anonymous
March 22, 2016
On the road right now but tonight when I am back at my hotel I will look Inyo your issue and rewrite this post using thr latest SDK. Looking at what you are doing I don't see any issue. - Anonymous
March 22, 2016
Jak221, Just updated the instructions to map to what is currently in the SDK. Just tested with a new project and the web deploy worked perfectly. Would be curious to see your actual project, without your webdeploy package.. I also don't mind to send mine to you if you want to test. The only thing I can think is there is an issue with the packageuri. you click the contect blog author and can send you the info.