How To: Publish an AngularJS Website with Azure Resource Manager Templates

If you're looking for help with C#, .NET, Azure, Architecture, or would simply value an independent opinion then please get in touch here or over on Twitter.

I’ve recently been working on the deployment of some fairly complex micro-service projects using the new Azure Resource Manager and in the Microsoft space everything went fine, it’s all pretty self-explanatory, there’s some useful tooling in Visual Studio and some great quick-start templates.

Then I hit my UI layer. This is an AngularJS app which I prefer to work on outside of Visual Studio – I like to use the best tools for the job and while I definitely find Visual Studio is just that for C# and other Microsoft native technologies I find it often lags behind in the web space, though it’s got and continues to get a lot better.

Basically I have a folder in my project folder space (not in the .sln file) containing my AngularJS app and a bunch of typical web tools to run the build and packages: npm, bower and grunt. For various reasons although the project source is in GitHub I couldn’t (without a fair bit of hassle) deploy directly from their using the source code deployment model.

And so how do you publish a folder of files to an Azure website using Azure Resource Manager?

Below I’ll present one way using the Yeoman generated Angular template as a sample which, using grunt, builds to a folder called dist. As a prerequisite for this you’ll need Azure Powershell -I’m using 0.8 at the time of writing (1.0 contains some changes to the Azure Resource Manager cmdlets but as I write this it’s in preview, the changes are nothing earth shattering).

You can find source code for the below in GitHub.

Firstly you need to create an Azure Resource Manager template – the one we’re using is here. I’ve not going to cover every bit of this as Microsoft have plenty of documentation and samples however it’s worth looking at this bit towards the end:

"resources": [
  {
    "name": "MSDeploy",
    "type": "extensions",
    "location": "[parameters('location')]",
    "apiVersion": "2014-06-01",
    "dependsOn": [
      "[concat('Microsoft.Web/sites/', parameters('siteName'))]"
    ],
    "tags": {
      "displayName": "ContentDeploy"
    },
    "properties": {
      "packageUri": "[concat(parameters('packageUrl'), parameters('sasToken'))]",
      "dbType": "None",
      "connectionString": "",
      "setParameters": {
          "IIS Web Application Name": "[parameters('siteName')]"
      }
    }
  }
]

This invokes the deployment of a Web Deployment package at URL specified by packageUrl. I’m using an Azure Storage Account for this and so to access the package do so we need a Shared Access Signature which we’ll see how to generate later.

As I want to automate everything I’ve also got a template for creating a storage account into which the package can be uploaded and you can see this template here.

I’m going to glue these two templates together with a Powershell script using the Azure Powershell cmdlets. To get started with this launch Azure Powershell and before running any scripts add your Azure subscription:

Add-AzureAccount

You’ll be prompted to log into your account.

The Powershell script I’m using to glue all this is called deploy.ps1 and you can find it here. I’m going to break this down section by section. Firstly we just deploy a bunch of fairly (if you know Azure) self explanatory settings – the hosting plan, resource group, website and storage account to create / use and the location of those resources:

# Deployment settings
$hostingPlanName = "ArmAngularSampleHostingPlan"
$resourceGroupName = "ArmAngularSample"
$storageAccountName = "armangularsamplesa"
$location = "West Europe"
$siteName = "ArmAngularSampleWebsite"

Then we optionally select an Azure subscription (if you only have one subscription you won’t need to do this) and switch Powershell into Azure Resource Manager mode.

# Configure Azure and the Powershell shell
# Select-AzureSubscription -SubscriptionId {{your-subscription-id}}
Switch-AzureMode AzureResourceManager

Now we create the resource group within which our templates are going to run:

# Create Azure Resoure Group
New-AzureResourceGroup -Name $resourceGroupName -Location $location -Force

Next we deploy our storage resources using Azure Resource Manager and then we get hold of the access key – we’ll need that in a minute. In such a small deployment this split of storage and service might seem a little naive but in more complex scenarios it’s fairly common to do a bunch of work on storage before deploying updated services (and vice versa):

# Deploy storage
New-AzureResourceGroupDeployment -ResourceGroupName $resourceGroupName `
                                 -Name AzmSampleStorageDeployment `
                                 -TemplateFile "storagedeploy.json" `
                                 -appStorageAccountName $storageAccountName 				 
$storageAccountKey = (Get-AzureStorageAccountKey -ResourceGroupName $resourceGroupName -Name $storageAccountName).Key1

Having done that we get grunt to build a distribution version of our Angular site and then we invoke MSBuild to create a deployment package from the folder. To do this MSBuild needs a project file and nearly every example you see will use a .csproj file – which is fine if you’re using Visual Studio but what if we’re not? Well you can also use a .publishproj file which you can find here. This file is absolute boilerplate – it will work for any folder and so you can copy and use mine for your own projects. We need to move this into the dist folder that grunt has created (you can use it elsewhere but as dist is cleaned each time this is easiest).

# Build deployment package
grunt build
cp .\website.publishproj .\dist\website.publishproj
C:\"Program Files (x86)"\MSBuild\14.0\bin\msbuild.exe .\dist\website.publishproj /T:Package /P:PackageLocation="." /P:_PackageTempDir="packagetmp"
$websitePackage = ".\dist\website.zip"

The setting of /P:PackageLocation=”.” causes the package to be dropped in the dist folder and the /P:_PackageTempDir=”packagetmp” causes MSBuild to use a packagetmp subfolder of dist to be used for temporary files – this can be useful as it’s easy to run into the “classic” Windows file length issues otherwise (it will use a temp location in AppData by default).

Having generated a package (called website.zip and located in the dist folder) we need to upload it to somewhere Azure can access. I’m using the storage account we created earlier. So that the Azure Resoure Manager incarnation of Web Deploy can access the package we generate a Shared Access Signature with read privileges:

# Upload packages
$storageCtx = New-AzureStorageContext -StorageAccountName $storageAccountName -StorageAccountKey $storageAccountKey
if (-Not (Get-AzureStorageContainer -Context $storageCtx | Where-Object { $_.Name -eq "packages" }) ) {
    New-AzureStorageContainer -Name "packages" -Context $storageCtx -Permission Off
}
Set-AzureStorageBlobContent -File $websitePackage -Container "packages" -Blob website.zip -Context $storageCtx -Force
$uploadedPackage = "https://$storageAccountName.blob.core.windows.net/packages/website.zip"
$sasToken = New-AzureStorageContainerSASToken -Container "packages" -Context $storageCtx -Permission r
$sasToken = ConvertTo-SecureString $sasToken -AsPlainText -Force

And finally we deploy our services via the Azure Resource Manager template we saw earlier:

New-AzureResourceGroupDeployment -ResourceGroupName $resourceGroupName `
                                 -Name AnalyticsLiveServiceDeployment `
                                 -TemplateFile "azuredeploy.json" `
                                 -hostingPlanName $hostingPlanName `
                                 -location $location `
                                 -siteName $siteName `
                                 -packageUrl $uploadedPackage `
                                 -sasToken $sasToken

And that’s it. If you run .\deploy.ps1 (you’ll need to set your own unique storage account and website name) then as long as you have an Azure subscription this will deploy and you’ll be able to see the Yeoman template running in Azure.

Hopefully that’s helpful and will save you some of the pain that always seems to come with the territory of deployment – particularly where MSBuild is involved!

4 thoughts on “How To: Publish an AngularJS Website with Azure Resource Manager Templates

  1. Is there any way that you can use this with visual studio’s automatically generated Deploy-AzureResourceGroup.ps1? I can see a lot of similarities.

    I’ve tried adding the build deployment package section to the script but can’t seem to pass the correct parameters to get it to deploy.

    1. Hi, there’s no reason you can’t use this with the auto-generated script and template but you might need to hack it round quite a bit. The PowerShell script is just a wrapper for an ARM template as I recall. To get it to work you’d probably need to expand the parameters it takes and the json file that contains those and then add the web site block. Have you got a link to your json file and PowerShell script? If I get a chance I’ll take a quick look at them and see if I can spot anything obvious.

Leave a Reply

Your email address will not be published. Required fields are marked *

Contact

  • If you're looking for help with C#, .NET, Azure, Architecture, or would simply value an independent opinion then please get in touch here or over on Twitter.

Recent Posts

Recent Tweets

Invalid or expired token.

Recent Comments

Archives

Categories

Meta

GiottoPress by Enrique Chavez