Angular Azure — Auth, CI/CD, IaC, and Serverless — Part 2

Jay Watson
5 min readJun 27, 2021

IaC — Terraform

What is Terraform? The following snippet is from the Terraform website — terraform.io.

Terraform allows infrastructure to be expressed as code in a simple, human readable language called HCL (HashiCorp Configuration Language). It reads configuration files and provides an execution plan of changes, which can be reviewed for safety and then applied and provisioned.

Yeah. Yeah. Meh. Terraform is an IaC tool, so what’s the big deal. Well..

  1. ARM is for Azure. CloudFormation is for AWS. But Terraform is platform agnostic — meaning, you can use it anywhere!
  2. Terraform is pretty — at least for us humans. If you’ve utilized ARM templates before, trust me, you’ll appreciate the readability of Terraform.
  3. Terraform is easy to learn. This probably goes along with point two. But if you work through the basic Terraform “Hello World” tut and do the same with Ansible, I feel confident of what preference you’ll have.
  4. State management. You ‘Declare’ the state of your infrastructure (see declarative versus imperative) and Terraform attempts to maintain that state. Terraform also makes state easy to manage for teams.

Start Building

That’s all the detail, I’m going to go into. Let’s get started by creating tf-az-folder within our project. We’ll then create 3 files.

  • variables.tf
  • terraform.tfvars
  • main.tf

Define your variables in variables.tf.

variable "location" { type        = string description = "Azure Region Location"}variable "resource_group" { type        = string description = "Resource Group Name"}variable "storage_account" { type        = string description = "Storage Account Name"}

Provide the actual values for your variables in terraform.tfvars.

location        = "eastus"resource_group  = "ngmsalfcc"storage_account = "ngmsalfcc"

Now, let’s move to main.tf and create our infrastructure as code.

First, use the azurerm provider and create a resource group. Note that we are pulling in variables from terraform.tfvars.

provider "azurerm" {  features {}}// create resource groupresource "azurerm_resource_group" "resource_group" {  name     = var.resource_group  location = var.location}

Next, create and configure your storage account.

// create storage accountresource "azurerm_storage_account" "storage_account" {  name                = var.storage_account  resource_group_name = azurerm_resource_group.resource_group.name  location                 = var.location  account_tier             = "Standard"  account_replication_type = "LRS"  account_kind             = "StorageV2"  static_website {    index_document = "index.html"  }}

Finally, add a $web blob container. Note that we are also adding an index.html file to blob so that it’s seeded. Go ahead and create this.

// add placeholder index.html to blobresource "azurerm_storage_blob" "example" {  name                   = "index.html"  storage_account_name   =  
azurerm_storage_account.storage_account.name
storage_container_name = "$web" type = "Block" content_type = "text/html" source = "index.html"}

CI/CD Pipeline — Azure DevOps

Go to dev.azure.com. You may need to create an account.

Once logged in, you’ll need to create an organization and a new project.

After you’ve created the project, then need to create a pipeline.

You’ll first need to connect Az DevOps to your GitHub. It’s pretty straightforward.

Then, you’ll add a Node task.

And a Command Line task, which you’ll utilize to install the Angular CLI.

And then an NPM task. This will simply just install the Node modules. You could use a Command Line task if you wanted. It doesn’t matter.

And then another Command Line task that we’ll utilize to use the Angular CLI build the project.

Now, it’s time to prep for release. Pull in a Copy Files task and specify the —

  • Display Name: Copy Files to: $(Build.ArtifactStagingDirectory)
  • Source folder: $(Build.SourcesDirectory)/dist
    ^unless you changed it, the dist folder
  • Contents: **
    ^We want all the content
  • Target folder: $(Build.ArtifactStagingDirectory)

Now, bring in an Archive task because we want to zip and specify —

  • Display Name: Archive $(Build.SourcesDirectory)/dist
  • Root folder or file to archive: $(Build.SourcesDirectory)/dist
  • Archive type: zip
  • Archive file to create: $(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip

Finally, publish your zipped file with a Publish Artifact task with the following options set.

  • Display name: Publish Artifact: drop
  • Path to publish: $(Build.ArtifactStagingDirectory)
  • Artifact publish location: Azure pipelines

Release the Kraken…er…the Pipeline

First, create a new release.

Select the source location (where your build just released to).

Create a Stage.

Add an Extract Files task and set —

  • Archive file patterns: **/$(Build.BuildId).zip
  • Destination folder: $(System.DefaultWorkingDirectory)/$(Build.BuildId)

Finally, pull in an AZ CLI task and configure —

  • Azure Resource Manager connection: <your subscription>
    **You may need to add it if it’s not showing up.
  • Script type: PowerShell
  • Script location: Inline Script
  • Inline Script (see below)
az storage blob upload-batch 
--account-name <get this from your az storage container>
--account-key <get this from your az storage container>
--destination '$web' --source ./
  • Working directory: $(System.DefaultWorkingDirectory)/$(Build.BuildId)/dist/ng-msal-fcc

Finally, we are set to release! Now, create your release and let me know how it goes in the comments.

--

--