I have been using Terraform for the last week or so to create some infrastructure and decided to bring that knowledge back to a problem that I and others suffer from – building environments for presentations, all for the sake of doing some learning.
What is Terraform?
According to the website
HashiCorp Terraform enables you to safely and predictably create, change, and improve infrastructure. It is an open source tool that codifies APIs into declarative configuration files that can be shared amongst team members, treated as code, edited, reviewed, and versioned
This means that I can define my infrastructure as code. If I can do that then I can reliably do the same thing again and again, at work to create environments that have the same configuration or outside of work to repeatedly build the environment I need.
Building an Azure SQL Database with Terraform
To understand how to build a thing the best place to start is the documentation https://www.terraform.io/docs . For an Azure SQL Db in the docs you will find a block of code that looks like this
resource "azurerm_resource_group" "test" {
name = "acceptanceTestResourceGroup1"
location = "West US"
}
resource "azurerm_sql_server" "test" {
name = "mysqlserver"
resource_group_name = "${azurerm_resource_group.test.name}"
location = "West US"
version = "12.0"
administrator_login = "4dm1n157r470r"
administrator_login_password = "4-v3ry-53cr37-p455w0rd"
}
resource "azurerm_sql_database" "test" {
name = "mysqldatabase"
resource_group_name = "${azurerm_resource_group.test.name}"
location = "West US"
server_name = "${azurerm_sql_server.test.name}"
tags = {
environment = "production"
}
}
If you read the code, you can see that there are key value pairs defining information about the resource that is being created. Anything inside a ${} is a dynamic reference. So
resource_group_name = “${azurerm_resource_group.test.name}” refers to the name property in the azure_resource_group block called test (or the name of the resource group 🙂 )
Infrastructure As Code
So I can put that code into a file (name it main.tf) and alter it with the values and “run Terraform” and what I want will be created. Lets take it a step further though because I want to be able to reuse this code. Instead of hard-coding all of the values I am going to use variables. I can do this by creating another file called variables.tf which looks like
variable "presentation" {
description = "The name of the presentation - used for tagging Azure resources so I know what they belong to"
default = "dataindevon"
}
variable "ResourceGroupName" {
description = "The Resource Group Name"
default = "beardrules"
}
variable "location" {
description = "The Azure Region in which the resources in this example should exist"
default = "uksouth"
}
variable "SqlServerName" {
description = "The name of the Azure SQL Server to be created or to have the database on - needs to be unique, lowercase between 3 and 24 characters including the prefix"
default = "jeremy"
}
variable "SQLServerAdminUser" {
description = "The name of the Azure SQL Server Admin user for the Azure SQL Database"
default = "Beard"
}
variable "SQLServerAdminPassword" {
description = "The Azure SQL Database users password"
default = "JonathanlovesR3ge%"
}
variable "SqlDatabaseName" {
description = "The name of the Azure SQL database on - needs to be unique, lowercase between 3 and 24 characters including the prefix"
default = "jsdb"
}
variable "Edition" {
description = "The Edition of the Database - Basic, Standard, Premium, or DataWarehouse"
default = "Standard"
}
variable "ServiceObjective" {
description = "The Service Tier S0, S1, S2, S3, P1, P2, P4, P6, P11 and ElasticPool"
default = "S0"
}
and my main.tf then looks like this.
provider "azurerm" {
version = "=1.24.0"
}
resource "azurerm_resource_group" "presentation" {
name = "${var.ResourceGroupName}"
location = "${var.location}"
tags = {
environment = "${var.presentation}"
}
}
resource "azurerm_sql_server" "presentation" {
name = "${var.SqlServerName}"
resource_group_name = "${azurerm_resource_group. presentation.name}"
location = "${var.location}"
version = "12.0"
administrator_login = "${var.SQLServerAdminUser}"
administrator_login_password = "${var.SQLServerAdminPassword} "
tags = {
environment = "${var.presentation}"
}
}
resource "azurerm_sql_database" "presentation" {
name = "${var.SqlDatabaseName}"
resource_group_name = "${azurerm_sql_server.presentation. resource_group_name}"
location = "${var.location}"
server_name = "${azurerm_sql_server.presentation. name}"
edition = "${var.Edition}"
requested_service_objective_name = "${var.ServiceObjective}"
tags = {
environment = "${var.presentation}"
}
}
You can find these files in my GitHub Repository here.
Alright – deploy something
To deploy the code that I have written I need to download Terraform from https://www.terraform.io/downloads.html and then extract the exe to a folder in my PATH. (I chose C:\Windows). Then in Visual Studio Code I installed two extensions The Terraform Extension by Mikael Olenfalk which enables syntax highlighting and auto-completion for the tf files and the Azure Terraform extension. You will need also need Node.js from here.
With those in place I navigated to the directory holding my files in Visual Studio Code and pressed F1 and started typing azure terraform and chose Azure Terraform Init
I was then prompted to use Cloud Shell and a browser opened to login. Once I had logged in I waited until I saw this
I press F1 again and this time choose Azure Terraform plan. This is going to show me what Terraform is going to do if it applies this configuration.
You can see the what is going to be created. It is going to create 3 things
Once you have checked that the plan is what you want, press F1 again and choose Azure Terraform Apply
You are then asked to confirm that this is what you want. Only “yes” will be accepted. Then you will see the infrastructure being created
and a minute later
and Jeremy exists in the beardrules resource group
Then once I have finished with using the sqlinstance. I can press F1 again and choose Azure Terraform Destroy. Again there is a confirmation required.
and you will see the progress for 46 seconds
and all of the resources have gone.
Thats a good start. This enables me to create resources quickly and easily and keep the configuration for them safely in source control and easy to use.
In my next post I will create an Azure DevOps pipeline to deploy an AZure SQL Db withTerraform.