Post

How to Setup Azure Functions with Terraform

Terraform is a powerful Infrastructure as Code (IaC) tool that can used to provision cloud resources in Azure.

In this tutorial, we will cover how to provision the Azure resources we require in order to publish an Node.js Azure Function using both Terraform and Azure Function Core Tools.

This content is available in video form on the Cloud Engineer Skills YouTube channel.

How to Deploy Azure Functions to Azure Resources Provisioned by Terraform

Prerequisites

Before we get started for this tutorial you will need to have Terraform installed on your local machine as well as Azure Function Core Tools.

Creating the Terraform Configuration File

We will use main.tf as our Terraform configuration file to define what Azure Resources we want to create to enable us to deploy our Azure Functions.

The main.tf file will be responsible for provisioning the following Azure Resources:

  1. Azure Resource Group
  2. Azure Blob Storage Account
  3. App Service Plan
  4. Azure Function App
  5. Application Insights
  6. Log Analytics Workspace

Here is the main.tf in full.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "=3.110.0"
    }
  }
}

provider "azurerm" {
  features {
    resource_group {
      prevent_deletion_if_contains_resources = false
    }
  }
}

resource "azurerm_resource_group" "rg" {
  name     = "ces-af-terraform-rg"
  location = "West US 2"

  tags = {
    environment = "dev"
    source = "terraform"
    owner = "cloudengineerskills"
  }
}

resource "azurerm_storage_account" "func_storage" {
  name                     = "cloudengineerskillstfsa"
  resource_group_name      = azurerm_resource_group.rg.name
  location                 = azurerm_resource_group.rg.location
  account_tier             = "Standard"
  account_replication_type = "LRS"

  tags = {
    environment = "dev"
    source = "terraform"
    owner = "cloudengineerskills"
  }
}

resource "azurerm_service_plan" "func_consumption_plan" {
  name                = "cloudengineerskillstfconsumptionplan"
  resource_group_name = azurerm_resource_group.rg.name
  location            = azurerm_resource_group.rg.location
  os_type             = "Linux"
  sku_name            = "Y1"

  tags = {
    environment = "dev"
    source = "terraform"
    owner = "cloudengineerskills"
  }
}

resource "azurerm_linux_function_app" "func_app" {
  name                = "cloudengineerskillstffuncapp"
  resource_group_name = azurerm_resource_group.rg.name
  location            = azurerm_resource_group.rg.location

  storage_account_name       = azurerm_storage_account.func_storage.name
  storage_account_access_key = azurerm_storage_account.func_storage.primary_access_key
  service_plan_id = azurerm_service_plan.func_consumption_plan.id

  site_config {
    application_stack {
      node_version = 20
    }

    application_insights_connection_string = azurerm_application_insights.insights.connection_string
    application_insights_key = azurerm_application_insights.insights.instrumentation_key
  }

  tags = {
    environment = "dev"
    source = "terraform"
    owner = "cloudengineerskills"
  }
}

resource "azurerm_log_analytics_workspace" "logs" {
  name                = "cloudengineerskillstf-workspace"
  location            = azurerm_resource_group.rg.location
  resource_group_name = azurerm_resource_group.rg.name
  sku                 = "PerGB2018"
  retention_in_days   = 30

  tags = {
    environment = "dev"
    source = "terraform"
    owner = "cloudengineerskills"
  }
}

resource "azurerm_application_insights" "insights" {
  name                = "cloudengineerskillstf-appinsights"
  location            = azurerm_resource_group.rg.location
  resource_group_name = azurerm_resource_group.rg.name
  workspace_id        = azurerm_log_analytics_workspace.logs.id
  application_type    = "Node.JS"

  tags = {
    environment = "dev"
    source = "terraform"
    owner = "cloudengineerskills"
  }
}

Copy the file contents into a main.tf file, then run terraform init to download the providers required to provision the Azure Resources.

1
terraform init

Next you will need to log in to your Azure account and subscription via the Azure CLI, these credentials will be used by Terraform to provision your resources.

1
az login

Next run terraform apply and enter Yes to provision the resources in Azure.

1
terraform apply

Deploying your Azure Functions to Azure

Next we will initialize an Azure Function Project locallly and add an Azure Function inside it using Azure Function Core Tools.

To learn more about this process follow this previous tutorial.

Run the Azure Function Core Tools func init command to create the Azure Function Project.

1
func init
  1. Select node
  2. Select javascript

Run the Azure Function Core Tools func new command to add a HTTP Trigger Node.js Azure Function to the Azure Function Project.

1
func new
  1. Select HTTP Trigger
  2. Provide a Function name and hit enter

Update the .funcignore to also exclude any Terraform files from getting added into the Azure Function App on deployment.

See the .funcignore below.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
*.js.map
*.ts
.git*
.vscode
local.settings.json
test
getting_started.md
node_modules/@types/
node_modules/azure-functions-core-tools/
node_modules/typescript/
.terraform/
.terraform.lock.hcl
*.tfstate
*.tfstate*
*.tf
*.tfvars

Now you can publish your Azure Function to the Azure Function App with the Azure Function Core Tools func azure functionapp publish command.

1
func azure functionapp publish cloudengineerskillstffuncapp

Once the deployment has completed, the command should output the Invoke url for the httpTrigger Azure function you have just deployed which should be accessible by a web browser.

Clean up resources provisioned by Terraform

One note before you clean up your resources using terraform destroy, Application Insights will automatically create an Application Insights Smart Detection resource inside your Azure Resource Group which is out of Terraform’s control preventing it from deleting the resource group on a terraform destroy

In the main.tf file you will see that the feature flag prevent_deletion_if_contains_resources for the Azure Resource Group has been set to false, by default this is set to true.

This flag will ensure that the Resource Group including the Application Insights Smart Detection resource will all be deleted in full on terraform destroy.

You may now run the terraform destroy command to remove all of those resources.

1
terraform destroy
This post is licensed under CC BY 4.0 by the author.