Published

- 5 min read

Streamlit Deployment Guide Part 3: Azure IaC with Terraform

img of Streamlit Deployment Guide Part 3: Azure IaC with Terraform

This showcases the Terraform code to manage the Infrastructure to host your Streamlit application. It continues a series detailing the process of deploying a Streamlit app to Azure, broken down into the following parts:

Do you want to deploy your Streamlit application on Azure right now? Use the template repository 🚀

TL;DR

See the full Terraform code in the infra directory.

Prerequisites

You need an Azure subscription and a Docker image published to GitHub Container Registry to provision the infrastructure. Additionally, basic knowledge of using Terraform’s HashiCorp Configuration Language is assumed, and Terraform must be installed.

Write Terraform HCL

The code is divided into the following files:

  • main.tf
  • providers.tf
  • variables.tf
  • locals.tf
  • web-app.tf

main.tf

This code assumes the resource group has already been created and permissions assigned only to this resource group for the service principal. It uses the resource_group_name variable to retrieve the azurerm_resource_group information.

See Data Sources

   data "azurerm_resource_group" "rg" {
  name = var.resource_group_name
}

providers.tf

This is the basic providers configuration. As we are using Azure, the azurerm provider is specified along with the backend configuration to store the tfstate in a storage account within Azure. The random provider is also added as it is used to generate some random characters, which will be explained later.

See providers configuration

   terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~> 3.110.0"
    }
    random = {
      source  = "hashicorp/random"
      version = "~> 3.1"
    }
  }

  backend "azurerm" {
    resource_group_name  = "rg-streamlit-poc"
    storage_account_name = "streamlittfstate"
    container_name       = "tfstate"
    key                  = "strealitpoctfstate.tfstate"
  }

  required_version = ">= 1.8.0"
}

provider "azurerm" {
  features {}
}

variables.tf

This file contains all the input variable blocks for our root module, allowing us to provide custom values using CLI options. See the description of each variable to understand its purpose.

See Input Variables

   variable "resource_group_name" {
  type        = string
  default     = "rg-streamlit-poc"
}

variable "docker_image_name" {
  type        = string
  default     = "waynegoosen/azure-streamlit-poc:0.1.1"
}

variable "docker_registry_url" {
  type        = string
  default     = "https://ghcr.io"
}

variable "use_docker_registry_auth" {
  description = "Flag to indicate if Docker registry authentication is required"
  type        = bool
  default     = false
}

variable "docker_registry_username" {
  description = "Docker registry username"
  type        = string
  default     = ""
}

variable "docker_registry_password" {
  description = "Docker registry password"
  type        = string
  default     = ""
  sensitive   = true
}

variable "app_settings" {
  type        = map(string)
  default     = {}
  description = "Application setting"
}

variable "app_service_plan_sku_name" {
  type        = string
  default     = "B1"
  validation {
    condition     = contains(["B1", "B2", "B3", "D1", "F1", "P1v2", "P2v2", "P3v2", "P0v3", "P1v3", "P2v3", "P3v3", "P1mv3", "P2mv3", "P3mv3", "P4mv3", "P5mv3"], var.app_service_plan_sku_name)
    error_message = "The app_service_plan_sku_name must be one of the following: B1, B2, B3, D1, F1, P1v2, P2v2, P3v2, P0v3, P1v3, P2v3, P3v3, P1mv3, P2mv3, P3mv3, P4mv3, P5mv3."
  }
}

variable "app_name" {
  type        = string
  default     = "azure-streamlit-poc"
}

variable "environment" {
  type        = string
  default     = "prod"
}

locals.tf

The locals block allows us to store values that can be shared and built up, such as providing a prefix for the app_service_plan_name.

See Locals

   locals {
  app_service_plan_name = "asp-${var.app_name}"
  linux_web_app_name = "app-${var.app_name}"
  app_settings = {
    ENV = var.environment
  }
}

web-app.tf

This file defines the required resources to set up an Azure Web App. The application_stack block is where the Docker configuration is set. The flag use_docker_registry_auth is used to set the username and password if authentication is required with the Container Registry. Random id is used to generate random chars for the web app name for uniqueness.

   resource "azurerm_service_plan" "service_plan" {
  name                = local.app_service_plan_name
  location            = data.azurerm_resource_group.rg.location
  resource_group_name = data.azurerm_resource_group.rg.name
  os_type             = "Linux"
  sku_name            = var.app_service_plan_sku_name
  tags = {}
}

resource "random_id" "random_chars_web_app_name" {
  byte_length = 2
}

resource "azurerm_linux_web_app" "web-app" {
  name                = "${local.linux_web_app_name}-${random_id.random_chars_web_app_name.hex}"
  location            = data.azurerm_resource_group.rg.location
  resource_group_name = data.azurerm_resource_group.rg.name
  service_plan_id     = azurerm_service_plan.service_plan.id
  app_settings        = merge(local.app_settings, var.app_settings)

  site_config {
    always_on        = true # always_on cannot be set to true when using Free, F1, D1 Sku
    application_stack {
      docker_image_name = var.docker_image_name
      docker_registry_url = var.docker_registry_url
      docker_registry_username = var.use_docker_registry_auth ? var.docker_registry_username : null
      docker_registry_password = var.use_docker_registry_auth ? var.docker_registry_password : null
    }
  }
}

Resources:

Setup Azure Provider

Follow one of the methods for authenticating to Azure. For local testing, I suggest using Azure CLI.

Terraform Plan & Apply

Run terraform plan to view the expected resources to be created:

   terraform plan

You should see the following last line:

Plan: 3 to add, 0 to change, 0 to destroy.

This will create a service plan, a Linux web app, and a random ID for the web app name.

Finally, to create the resources, run terraform apply:

   terraform apply

When prompted, enter yes to create the resources shown. Alternatively, use the -auto-approve option to skip the confirmation step.

View the Website

Follow these steps to view your deployed website:

  1. Open the Azure portal
  2. Navigate to the web app within the resource group rg-streamlit-poc.
  3. In the overview section, you should see ‘Default Domain’ with a link. Click it. The URL should be similar to https://app-azure-streamlit-poc-b548.azurewebsites.net/.
A Streamlit website preview.

In the next part, we will go through automating the infrastructure provisioning via GitHub workflows.