Published
- 5 min read
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:
- Part 1: Containerizing a Streamlit app.
- Part 2: GitHub Workflow for Building and Publishing to ghcr.io
- Part 3: Azure Infrastructure via Terraform You are here 😊
- Part 4: GitHub Workflow for Terraform Apply & Destroy
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.
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:
- Open the Azure portal
- Navigate to the web app within the resource group rg-streamlit-poc.
- 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/.
In the next part, we will go through automating the infrastructure provisioning via GitHub workflows.