Terraform for Azure: Basics (3)

Azure Resource Group logo

Build Pipeline and Resource Deployment

This is the third post in a series dealing with the basics of Terraform for Microsoft Azure using Azure DevOps. This post will work through the process of creating a build pipeline and deploying a simple resource. Previous posts have covered the prerequisites and repositories & pipelines. This series is designed as a memory aid for myself, that can maybe help others out going through the same learning process about Terraform and Azure. It’s not a detailed guide for somebody new to Terraform, DevOps or Azure, it probably doesn’t meet best practices in the DevOps industry, but it’s what I’ve found works for me!

Note that I’m writing this in the middle of 2024, and technology moves on quickly – things may well have changed by the time you’re reading it. As always I’d like to thank James Meegan for his original documentation which I’ve used as a foundation for this series.

Synchronise your Pipeline

In the second post of this series, we created a YAML pipeline directly in Azure DevOps. To enable better editing and manipulation of our files, we need to copy them down to our local computer. As before, when synchronising the basic Terraform code up to our repository, we’ll use Visual Studio Code to synchronise the new changes back down. The pipeline was associated with our repository, so it should be available now along with all the other files.

Open VS Code and whilst in the “Explorer” (VS Code Explorer Icon) view, click on the synchronise (VS Code Synchronise icon) button in the bottom left of the window:

Your validation.yml file should now appear in the files list:

There are other ways to synchronise the files, with say a pull request in the source control view, or a git pull command in terminal, but this is the way I prefer.

Create the code to deploy a Resource Group

Create the Code

Our pipeline is now in place to validate our code in Azure DevOps. We saw in the last post when looking at the output of the pipeline job, that no infrastructure was to be deployed, so now let’s change that. The process is broadly similar for pretty much all Azure resources, so we’ll start with a general prerequisite for most things, the Resource Group.

When creating your code, it’s always a good idea to look at HashiCorp’s reference site for that resource. It will give you some example code, all relevant variables. arguments and attributes, and it can really speed up your development time. The specific page for a Resource Group is here.

The file we use to store the code for resource deployment is our main.tf file (but remember it can be named anything – I use main.tf to keep things logical in my mind). Copy the example code from the HashiCorp site and paste it at the top of your main.tf file in VS Code:

resource "azurerm_resource_group" "example" {
  name     = "example"
  location = "West Europe"

I want things to be a little different than their example. I want to use my own naming conventions and I want to use a different region, so I’ll just edit the code:

resource "azurerm_resource_group" "first_uks_rg" {
  name     = "uks-example-rg-01"
  location = "UK South"

The code above is known as a resource block, and I’ve called this resource block “first_uks_rg”. That name isn’t used anywhere in Azure, but it can be referenced later in our code, which we’ll see later in this series. I’ve also changed the resource group name to match my naming convention of “<region>-<purpose>-<resourceType>-<uniqueNumberIdentifier>”. The location I’ve set to my preferred region of UK South. You can now, as we did in a previous post, save that file, check your formatting (run “terraform fmt -recursive” in the terminal window), then in the “Source Control” window commit and sync to your repository in Azure DevOps along with a sensible comment:

Run the Pipeline

In Azure DevOps, you should be able to now see the synchronised code in your Repo. Select “Pipelines” and hover over the right-hand side of the validation pipeline’s box where a “more options” menu (More Options icon) will appear. Click that and select “Run Pipeline”:

Click “Run” in the resulting dialogue box, then click on “Job” in the lower part of the screen:

When the job is complete, highlight “Run Terraform Plan”, and you’ll see that the resource group will be created:

If there are any mistakes in your code that haven’t been picked up by your terraform fmt – recursive command in VS Code, the pipeline will fail at either the init or plan stage, giving full error details in the right-hand pane. This pane can be very useful for understanding where things have gone wrong (and they will!), and what you need to do to fix them.

Reviewing the Terraform Plan output after every commit is a good habit to get into. You will see exactly what tasks are going to be performed, and you’ll quickly see if any resources will be destroyed or deleted, giving you chance to change the code if that’s not what you want.

Create the “Build” Pipeline

Write the Pipeline Code

We now have some code ready to deploy a Resource Group, and a validation pipeline checking that our code is correct and confirming what it’s going to do. The next step for us is to create a “build” pipeline that will actually apply the code and deploy (or delete!) the resource(s) in Azure. Although we could put the “apply” code in the same “validation” file as our plan, it is best practice to keep the two separate, giving us the opportunity to change things if the plan doesn’t go according to, well, plan… Doing this also helps us to keep our development code in a separate “branch”. I briefly mentioned branches in a previous post, and we’ll go into more detail in a future post, but in essence our testing and planning will happen in a development branch, which is effectively sandboxed from the Azure and can’t impact anything, then when we’re happy we’ll pull that code into the main branch, where our apply pipeline will kick in and deploy the resource(s).

Rather than create the pipeline in Azure DevOps as we did before, this time we’ll create and edit the file in VS Code. To give us a head start, simply copy the validation.yml file in either VS Code or Windows Explorer to a new file in the same folder called apply.yml (or any other .yml name you want). In the new .yml file, edit the comments that describe the pipeline:

Now copy the whole “Plan” task and paste directly below, updating the comment and changing the display name and the command:

Although not strictly necessary, we should now add options to each of the plan and apply blocks, which output from the plan what will happen, and then allow the apply task to accept that output as an input. This gives us the following pair of code blocks:

# Terraform Plan
- task: TerraformTaskV4@4
  displayName: Run Terraform Plan
    provider: 'azurerm'
    command: 'plan'
    commandOptions: -out=plan
    environmentServiceNameAzureRM: 'terraform-series-sc'

# Terraform Apply
- task: TerraformTaskV4@4
  displayName: Run Terraform Apply
    provider: 'azurerm'
    command: 'apply'
    commandOptions: plan
    environmentServiceNameAzureRM: 'terraform-series-sc'

Our pipeline code is now created, so we should save the file, validate the formatting, then commit and synchronise with a descriptive comment. Although this pipeline code will synchronise to our repository, we have not yet created the pipeline that will use the code; this is our next step.

Create the Pipeline

In Azure DevOps, select “Pipelines” on the left and click “New Pipeline” in the top right hand corner. Again this will be an “Azure Repos Git” pipeline so click that, then click your repo. At the next stage, we have created the code already so we need to click “Existing Azure Pipelines YAML file”:

In the “Path” dropdown, select your new apply.yml file then click “Continue”:

Make sure the displayed code matches what you created in VS Code, then click “Run”. You can check your pipeline’s progress again by clicking “Job”. If you select the “Run Terraform Apply” stage, you’ll see that the Resource Group has been deployed:

You can confirm this by going into the Azure Portal and looking for your resource groups in your subscription:

And that’s it. In its most basic form you have the foundations to deploy any resources into Azure that you want. Why not have a play around, see what other resources you can deploy by adding the code to your main.tf file, synchronising and running your apply pipeline? If you want to destroy those resources, just comment out the lines in main.tf, synchronise and run the apply pipeline again (usually a good idea to make sure you’re not charged for any resources that are just hanging around in Azure unused). I’d love to hear what you’ve managed to achieve up to this point, and if you’re finding the series useful. Leave me a comment!

Next up in our series we’ll be looking at branches, putting the build pipeline after the validation pipeline, and adding some governance around your deployments such as approval checks.

Until next time…

– The Zoo Keeper

By TheZooKeeper

An Azure Cloud Architect with a background in messaging and infrastructure (Wintel). Bearded dog parent who likes chocolate, doughnuts and Frank's RedHot sauce, but has not yet attempted to try all three in combination!

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.