Learn Terraform and deploy Azure resource via Azure DevOps pipeline (Part 1)

Part 1: Getting started with Terraform

Rohan Islam
10 min readJul 20, 2020

I have started learning terraform and deploying Azure resources using terraform. So, thought to write a blog and share as I progress with the learning. This might be helpful for beginners. Let’s learn together!

I am planning to write simple terraform script to create an Azure resource group and deploy it via Azure DevOps pipeline. Let’s see how it goes.

Target architecture

Target architecture

Introduction to terraform

Terraform is an open source tool, created by HashiCorp. This is one of the most popular infrastructure as code tool. It enables us to deploy, update, manage infrastructure efficiently. We can also maintain versions of our infrastructure using terraform. Honestly, I find it pretty cool but remember we have to handle such powerful tool very carefully.

A terraform configuration file is the file in which we declare the resources or configuration that we want to create or manage. So, this is basically the script and often named as main.tf. A typical terraform configuration file looks like following.

provider "azurerm" {
version = "=2.0.0"
features {}
}
resource "<resource to be created>" "example" {
name = "<name of the resource>"
location = "<Azure location>"
}

In the first block, we declare the Provider, using which we are going to deploy our resource. In this case, it is azurerm as we are going to provision our resource on Azure Resource Manager deployment model.

The second block is where we declare the resources that we want to deploy on Azure. There can be multiple resource blocks in a configuration file. You may need to declare different arguments depending on the resource type but here let’s go with only “name” and “location” as these are the two required arguments for resource group creation. Terraform syntax related to azurerm resources can be found here.

When we can mention all the information related to the resource in the main.tf file but it’s good practice to use variables instead of hard coded values in the configuration file. A main.tf file with variables looks like following, where “my_resource_name” and “location” are the variables.

provider "azurerm" {
version = "=2.0.0"
features {}
}
resource "<resource to be created>" "example" {
name = var.my_resource_name
location = var.location
}

Now that we are using variables in the configuration file, we have to declare these variables somewhere, right? We need to create another file called variables.tf in which we declare all the variables that are used in main.tf. variables.tf file looks like following.

variable "my_resource_name" {
type = string
description = "name of the resource"
}
variable "location" {
type = string
description = "location "
}

Okay, so we have a configuration file (main.tf) and a variable file (variables.tf). Now, we need to specify the values of the variables somewhere. We need to create another file called terraform.tfvars to specify the values of the variables that are used in the configuration file and declared in the variable file. Below is an example of terraform.tfvars file.

my_resource_name = "terraform-demo"
location = "westeurope"

So, in the end we will at least have the following three files for each configuration.

  • main.tf : Configuration file
  • variables.tf : Contains the variables used in the configuration file
  • terraform.tfvars : Contains the values of the variables declared in the variables file

Set up environment

So far we have understood how terraform script should be written. Let’s now set up our environment or prerequisites.

  • Choose a text editor as per your choice (I am using visual studio code)
  • Install git (if not already installed)
  • Install Azure CLI and Azure DevOps extension (if not already installed)
  • Create a folder called “tfdemo” on a suitable path or drive. This will be our terraform project directory.
  • Login to Azure Portal and create a storage account, under which create a blob container. I am creating a storage account called “tfdemosa01” and a container called “tfstate”. Make sure to put it in a different resource group. We will use this storage account for storing terraform state file.

Prepare terraform code

We will now prepare our little terraform code to provision an Azue resource group.

  • Open the folder “tfdemo” from your text editor and create a folder called “azuredeploy” in it. Now create the three files (main.tf, variables.tf and terraform.tfvars) under azuredeploy folder as shown below.
rohan@K42N:~/Documents/tfdemo$ tree
.
└── azuredeploy
├── main.tf
├── terraform.tfvars
└── variables.tf

Configuration file (main.tf)

Notice that I have added an additional block called “terraform” in main.tf. This is required to store terraform state file in an Azure blob storage account, which we will configure later during Azure DevOps pipeline configuration.

terraform {
backend "azurerm" {}
}
provider "azurerm" {
version = "=2.0.0"
features {}
}
resource "azurerm_resource_group" "rg" {
name = var.resource_group_name
location = var.location
}

Variable file (variables.tf)

variable "resource_group_name" {
type = string
description = "name of the resource group"
}
variable "location" { type = string
description = "location "
}

Variable value file (terraform.tfvars)

resource_group_name = "terrform-demo-rg"
location = "westeurope"

Create local git repo

On your PC, run the following commands on a terminal or command prompt within “tfdemo” folder to prepare the local git repository. (I am working on a Linux based machines)

rohan@K42N:~/Documents/tfdemo$ git init
Initialized empty Git repository in /home/rohan/Documents/tfdemo/.git/
rohan@K42N:~/Documents/tfdemo$ git add .
rohan@K42N:~/Documents/tfdemo$ git commit -m "my first commit"
[master (root-commit) 9e9d3c9] my first commit
3 files changed, 24 insertions(+)
create mode 100644 azuredeploy/main.tf
create mode 100644 azuredeploy/terraform.tfvars
create mode 100644 azuredeploy/variables.tf
rohan@K42N:~/Documents/tfdemo$

Create Azure DevOps project

Now we have to create an Azure DevOps project, to do that follow the instructions below.

  • Go to Azure DevOps portal. Create a free account if you do not have already.
  • Install Azure DevOps terrafrom extension from marketplace to your Azure DevOps organisation.
  • Create a project. I am creating a project called “tfdemo”.
  • Go to the project settings and create a service connection. This will allow the Azure DevOps project to access and deploy resources on your Azure Subscription.
  • Select “Service principal (automatic)” option and click next. If you are comfortable, you can select other methods as well.
  • Select “Subscription” as the “Scope level”. Your subscription will be automatically populated under subscription field. You will be asked to login to your Azure tenant. If you have multiple subscriptions choose the one under which you want to deploy the resource group. I am leaving the resource group field as blank as I am not not going restrict the scope on a specific resource group. If I want to create a resource group via Azure DevOps pipeline, I certainly need to grant this access on the subscription level. Give this connection a name (tfdemo-connection) and save it. Once you save this connection, it will create an Azure AD service principal and assign “Contributor role” on the subscription you selected.
Create Azure DevOps project and set up a Service Connection

Okay, so at this stage we have an AzureDevOps project created and a service connection has been established with Azure subscription.

Push code to Azure DevOps repo

Now we have to initialize the repo of the Azure DevOps project that we just created.

  • Go to “Repos” and copy the https url from “Clone to your computer” section. I will call it clone url. Also, click on “Generate Git Credential” and keep it, you will need this later. However, you can generate the credential later as well.
Azure DevOps repo
  • Go back to your PC and open terminal or command prompt. I am working on the terminal of visual studio code.
  • Now clone local git repo to this newly created Azure DevOps project repo by running the following commands. Here you have to use the clone url and git credential mentioned earlier. Make sure to generate git credential before running this command.
rohan@K42N:~/Documents/tfdemo$ git remote add origin <clone url>
rohan@K42N:~/Documents/tfdemo$ git push origin master
Enumerating objects: 6, done.
Counting objects: 100% (6/6), done.
Compressing objects: 100% (5/5), done.
Writing objects: 100% (6/6), 643 bytes | 643.00 KiB/s, done.
Total 6 (delta 0), reused 0 (delta 0)
remote: Analyzing objects... (6/6) (5 ms)
remote: Storing packfile... done (46 ms)
remote: Storing index... done (31 ms)
To https://dev.azure.com/<your azuredevops organisation>/tfdemo/_git/tfdemo
* [new branch] master -> master
rohan@K42N:~/Documents/tfdemo$
  • Refresh the Azure DevOps project and you can see your code is available in the Azure DevOps repo.
Azure DevOps repo

We are all set to create Azure DevOps pipeline to deploy our code. So, let’s go ahead and create the pipelines.

Create Azure DevOps pipeline

Build pipeline

At first, we have to create a build pipeline to build the code and drop it in Azure DevOps Artifacts location.

  • Go to the Azure DevOps project “tfdemo” and click on “Pipeline”.
  • On the “Connect” window click on “Use the classic editor to create a pipeline without YAML
  • On the “Select a source” window select the project we created and click “Continue”.
  • On “Select a template” window click on “Empty job”.
  • This will create the build job. Let’s go with the default name and agent. Click the drop down “Save & queue” then “Save” the build pipeline under root.
Azure DevOps build pipeline

Now, we will have to add tasks under the build job.

  • Click the “+” symbol on the “Agent job” then search for copy task and add “Copy files” task to the job.
  • Specify the “Source folder”. This is the root folder of Azure DevOps repo. Let’s go with the default “Target folder” location by using the default variable. This is the path on the Agent where the code is going to be copied.
  • Again click the “+” symbol on the “Agent job” then add “Publish build artifacts” task.
  • Let’s go with the default setting and click on “Save & queue”. On the next window click “save and run” to run the build pipeline.
  • Click on the link “1 published” to view the published artifacts.
  • The code is now published under default “drop” folder which we specified in the task.
Azure DevOps build pipeline tasks

Release pipeline

Now that we have successfully built our code, it’s time to create a release pipeline and deploy code but before that we have to figure out how we are going to run terraform code. Turns out it’s not that complex!

  • Install terraform: First of all we have to install terraform on the machine from where the code will be executed. In this case, this is the Azure DevOps agent.
  • Terraform init: Run terraform init command to initialize the working directory which contains terraform configuration files
  • Terraform plan: This command creates an execution plan of the configurations
  • Terraform validate: This command validates the configuration files in the working directory
  • Terraform apply: This command applies the changes as per the configuration files to reach the desired state

There are sevaral other terraform commands but these basic commands are the primary commands required to execute a terraform configuration file.

Now that we know what we have to do to execute the code that we built in the artifacts by running the build pipeline. We will go ahead and create a release pipeline.

  • Go to the the Azure DevOps project we created and click on “Releases” under “Pipeline
  • Now click on “Empty job
  • Rename “Stage 1” to “tfdemo-env” to give it a name.
  • Click “Save” to save the pipeline under root
Azure DevOps release pipeline

Now, we have to edit the release pipeline to add the artifact location which we created by the build pipeline and add terraform tasks to deploy the code.

  • Click on “Add an artifact” and add the source then click on “1 job, 0 task” link in “tfdemo-env” stage.
  • Click the “+” symbol on “Agent job” and search for terraform and add “Teraform tool installer” task. This task will install latest version of terraform on the Azure DevOps agent. This task made it really simple.
  • Again click the “+” symbol on the “Agent job” and search for terraform then add “Terraform” task. This task is required to execute terraform commands.
  • Let’s configure the task. This task will execute our first terraform command which is “terraform init” so I renamed that name of the task accordingly. Select the other fields as per the picture below in this section.
  • On the “Terraform init” task we will now have to configure the AzureRm backend to establish a connectivity with Azure on the same task. Select the Service connection we created under “Azure subscription” field. In the “Resource group” field select the resource group in which we created the storage account to store the terraform state file. Select the storage account and container we created before under respective fields. In the “Key” field we will have to put the file name where the terraform state will be stored. This is typically named as “terraform.tfstate”.
  • Add the same “Terraform” task again in the same way but select “terraform plan” command.
  • Okay so the final task is “terraform validate and apply”. Add the same “Terraform” task again and select “validate and apply” command.
  • Click on “Save” to save to the release pipeline.
Azure DevOps release pipeline tasks
  • Click on “Create release” to trigger a release.
Trigger Azure DevOps release pipeline
  • Now click on the highlighted link as per the picture below to go the the release job.
Azure DevOps release
  • I can see my release job completed successfully.
Azure DevOps release status
  • Now, let’s go to the portal and verify whether the resource group has been created or not. I can see the resource group is created under my Azure subscription.
Azure

Next steps:

Thanks for reading, give it a 👏 if you like it. Please leave a comment and let me know if you have any feedback.

--

--

Rohan Islam

Cloud Architect | Continuous learner | Passionate about technologies