Provisioning Azure Functions Using Terraform
The Azure Portal is an intuitive web app to manage cloud resources. It is so easy to use that sometimes I feel like I have years of Azure experience. As every good web app, it keeps evolving and simplifying our work, but this constant evolution makes the life of writers like me very hard. If I try to give detailed instructions about the steps to create resources there, it will be obsolete in a matter of weeks. Yet, if I don’t explain the cloud side of my articles, they end up being incomplete, frustrating my readers. So, how can I possibly solve this problem? Long story short: Infrastructure as Code.
Short story long: A way to be precise about cloud infrastructure while keeping articles useful for longer is to use code. This is the thing in technology that takes longer to become obsolete. Good programming languages evolve over time but also preserve backwards compatibility, making sure that old software still compiles in modern technology. When it is time break compatibility they try to do it gracefully, giving developers time to adapt.
Using code to build infrastructure is a practice known as “Infrastructure as Code”. Cloud providers have been serving APIs to create and maintain resources for years now. But some clever people out there have built tools that take care of the hard part and make available domain-specific languages to better describe cloud resources. The most popular tools out there are Ansible and Terraform. Ansible is cool, but I’m going to work with Terraform because it is written in Go, a language that I’m particularly passionate about.
We have provisioned some resources when Deploying an Azure Function in Go, using Azure CLI. We created a resource group, a storage account, and a function app. Behind the scene, it also created an application service plan and an application insights. We can do the same using Terraform. The subfolder /terraform
in this repo contains the scripts that demonstrate that. Let’s start explaining the main.tf
file:
This is written in the Terraform Configuration Language. It is using the Azure Resource Manager (azurerm), an extension that speaks with Azure’s APIs. It creates 5 resources mentioned above, leaving everything ready to deploy the function. Notice that we have some hardcoded values that are essential for the Go function and some variables prefixed with “var.”. These variables are defined in the file variables.tf
, as you can see below:
These variables are what need to change between my environment and yours. So, you can reuse this script as long as you define unique values for these variables. We can do that by assigning values to the variables with a .tfvars
file. My values are defined in the file env.tfvars
.
location = "eastus"
resource_group_name = "buyersmarket"
storage_account_name = "buyersmarketstore"
app_service_plan_name = "buyersmarketasp"
app_insights_name = "buyersmarket"
function_name = "buyersmarket"
Make sure the files main.tf
, variables.tf
, and env.tfvars
are together in a subfolder of your project. To run this code, Terraform needs to be installed and available in the command line. Download it from the Terraform website and follow the instructions for your operating system. In the command line, go to the folder where the scripts are located and initialize it:
$ cd azure/function/terraform
$ terraform init
The initialization install the dependencies required by our script. Next, Terraform uses Azure CLI to authenticate to Azure. So, make sure you are authenticated:
$ az login
Once authenticated, we are ready to compare what is defined in our scripts with what we have on Azure. We do it with the plan
argument:
$ terraform plan -var-file=env.tfvars
This command lists a detailed description of everything that will be created on Azure without actually creating it. Review it and if everything looks good, apply it:
$ terraform apply -var-file=env.tfvars
Once applied, the function is ready to be deployed, as we did when Deploying an Azure Function in Go:
$ cd azure/function
$ func azure functionapp publish buyersmarket
After a few seconds, call the URL:
$ curl 'https://buyersmarket.azurewebsites.net/api/offer?savings=134507&listingPrice=700000&downPayment=10&closingCosts=17000'
If you are just playing or don’t need the resources anymore, just destroy them:
$ terraform destroy -var-file=env.tfvars
I have to admit that preparing these scripts is a lot more work than running a couple of Azure CLI commands, but doing it with Terraform has some advantages:
-
The infrastructure as code is described in details. We can document and even explain why we made those architectural decisions without relying on diagrams that becomes obsolete very quickly.
-
The same script can be used to create several environments, such as development, test, and production, by simply referring to the corresponding
.tfvars
file. -
Changes to the infrastructure can be versioned. This is important to preserve the technical decisions made over time and even revert bad decisions. Versioning also shares the scripts with a continuous integration service that can propagate changes in several environments.
-
We are working with a simple example here, but the infrastructure can become very complex over time. So, using command line instructions might be unmanageable with a feel more resources. Terraform allows reusing and redefining values, which is hard to do in command line instructions.
The source code of the Azure Resource Manager is available on Github. Have fun with the examples there.