8 – πŸš€ Deploy Azure Functions with Terraform β€” QR Code Generator Mini Project (Step-by-Step)

In this post, I’ll walk you through a complete, working mini project where we deploy an Azure Linux Function App using Terraform and then deploy a Node.js QR Code Generator function using Azure Functions Core Tools.

This is not just theory β€” this is exactly what I built, debugged, fixed, and verified end-to-end. I’ll also call out the gotchas I hit (especially in Step 2), so you don’t lose hours troubleshooting the same issues.

Table of Contents

  1. πŸ”Ή What We Are Building
  2. 🧱 Step 1: Create Core Azure Infrastructure with Terraform
  3. βš™οΈ Step 2: Create the Linux Function App (Most Important Step)
  4. πŸ“¦ Step 3: Prepare the QR Code Generator App
  5. πŸ” Add local.settings.json (Local Only)
  6. 🚫 Add .funcignore
  7. πŸ›  Install Azure Functions Core Tools (Windows)
  8. πŸš€ Deploy the Function Code
  9. πŸ§ͺ Step 4: Test the Function End-to-End
  10. βœ… What This Demo Proves
  11. 🧠 Final Notes
  12. 🎯 Conclusion

πŸ”Ή What We Are Building

  • Azure Resource Group
  • Azure Storage Account
  • Azure App Service Plan (Linux)
  • Azure Linux Function App (Node.js 18)
  • A Node.js HTTP-triggered Azure Function that:
    • Accepts a URL
    • Generates a QR code
    • Stores the QR image in Azure Blob Storage
    • Returns the QR image URL as JSON

🧱 Step 1: Create Core Azure Infrastructure with Terraform

In this step, we create the base infrastructure required for Azure Functions.

Resource Group (rg.tf)

resource "azurerm_resource_group" "rg" {
  name     = "rgminipro767676233"
  location = "Central US"
}

Storage Account (sa.tf)

Azure Functions require a storage account for:

  • Function state
  • Logs
  • Triggers
  • Blob output (our QR codes)
resource "azurerm_storage_account" "sa" {
  name                     = "saminipro7833430909"
  resource_group_name      = azurerm_resource_group.rg.name
  location                 = azurerm_resource_group.rg.location
  account_tier             = "Standard"
  account_replication_type = "LRS"
}

⚠️ Storage account names must be globally unique and lowercase.

App Service Plan (splan.tf)

This defines the compute for the Function App.

resource "azurerm_service_plan" "splan" {
  name                = "splanminipro8787"
  resource_group_name = azurerm_resource_group.rg.name
  location            = azurerm_resource_group.rg.location
  os_type             = "Linux"
  sku_name            = "B1"
}

Apply Terraform

terraform apply

βœ… Verify in Azure Portal:

  • Resource Group created
  • Storage Account exists
  • App Service Plan is Linux (B1)

βš™οΈ Step 2: Create the Linux Function App (Most Important Step)

This step required multiple fixes for the app to actually run, so pay close attention.

Linux Function App (linuxfa.tf)

resource "azurerm_linux_function_app" "linuxfa" {
  name                = "linuxfaminipro8932340"
  resource_group_name = azurerm_resource_group.rg.name
  location            = azurerm_resource_group.rg.location

  storage_account_name       = azurerm_storage_account.sa.name
  storage_account_access_key = azurerm_storage_account.sa.primary_access_key
  service_plan_id            = azurerm_service_plan.splan.id

  app_settings = {
    FUNCTIONS_WORKER_RUNTIME = "node"

    # Required by Azure Functions runtime
    AzureWebJobsStorage = azurerm_storage_account.sa.primary_connection_string

    # Used by our application code
    STORAGE_CONNECTION_STRING = azurerm_storage_account.sa.primary_connection_string

    # Ensures package-based deployment
    WEBSITE_RUN_FROM_PACKAGE = "1"
  }

  site_config {
    application_stack {
      node_version = 18
    }
  }
}

Why Each Setting Matters

  • FUNCTIONS_WORKER_RUNTIME
    • Tells Azure this is a Node.js function app
  • AzureWebJobsStorage
    • Mandatory for Azure Functions to start
  • STORAGE_CONNECTION_STRING
    • Used by our QR code logic to upload images
  • WEBSITE_RUN_FROM_PACKAGE
    • Ensures consistent zip/package deployment
  • node_version = 18
    • Must match your app runtime

Apply Terraform Again

terraform apply

βœ… Verify in Azure Portal:

  • Function App is Running
  • Runtime stack shows Node.js 18
  • No startup errors

πŸ“¦ Step 3: Prepare the QR Code Generator App

Download the App

Clone or download the QR code generator repository:

git clone https://github.com/rishabkumar7/azure-qr-code

Navigate to the function root directory (where host.json exists).

Run npm install

npm install

This creates the node_modules folder β€” without this, the function will fail at runtime.

Expected Folder Structure

qrCodeGenerator/
β”‚
β”œβ”€β”€ GenerateQRCode/
β”‚   β”œβ”€β”€ index.js
β”‚   └── function.json
β”‚
β”œβ”€β”€ host.json
β”œβ”€β”€ package.json
β”œβ”€β”€ package-lock.json
β”œβ”€β”€ node_modules/

πŸ” Add local.settings.json (Local Only)

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "<Storage Account Connection String>",
    "FUNCTIONS_WORKER_RUNTIME": "node"
  }
}

❗ This file is NOT deployed to Azure and should never be committed.


🚫 Add .funcignore

This controls what gets deployed.

.git*
.vscode
local.settings.json
test
getting_started.md
*.js.map
*.ts
node_modules/@types/
node_modules/azure-functions-core-tools/
node_modules/typescript/

βœ… We keep node_modules because this project depends on native Node packages.


πŸ›  Install Azure Functions Core Tools (Windows)

winget install Microsoft.Azure.FunctionsCoreTools

Restart PowerShell and verify:

func -v

πŸš€ Deploy the Function Code

Navigate to the directory where host.json exists:

cd path/to/qrCodeGenerator

Publish the function:

func azure functionapp publish linuxfaminipro8932340 --javascript --force

Successful Output Looks Like This

Upload completed successfully.
Deployment completed successfully.
Functions in linuxfaminipro8932340:
    GenerateQRCode - [httpTrigger]
        Invoke url: https://linuxfaminipro8932340.azurewebsites.net/api/generateqrcode

πŸ§ͺ Step 4: Test the Function End-to-End

Invoke the Function

https://linuxfaminipro8932340.azurewebsites.net/api/generateqrcode?url=https://example.com

Sample Response

{
  "qr_code_url": "https://saminipro7833430909.blob.core.windows.net/qr-codes/example.com.png"
}

Download the QR Code

Open the returned Blob URL in your browser:

https://saminipro7833430909.blob.core.windows.net/qr-codes/example.com.png

πŸŽ‰ You’ll see the QR code image stored in Azure Blob Storage.


βœ… What This Demo Proves

  • Terraform successfully provisions Azure Functions infrastructure
  • App settings are critical for runtime stability
  • Azure Functions Core Tools deploy code from the current directory
  • Missing npm install causes runtime failures
  • Blob Storage integration works end-to-end
  • Azure Functions can be tested via simple HTTP requests

🧠 Final Notes

  • Warnings about extension bundle versions were intentionally ignored
  • This demo focuses on learning Terraform + Azure Functions, not production hardening
  • In real projects, code deployment is usually handled via CI/CD pipelines

🎯 Conclusion

This mini project demonstrates how Infrastructure as Code (Terraform) and Serverless (Azure Functions) work together in a practical, real-world scenario.

If you can build and debug this, you’re well on your way to mastering Azure + Terraform.

Happy learning πŸš€

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

TechMilestoneHub

Build Skills, Unlock Milestones

This is a test – edited from front page