Back to Blog

Deploying Web Apps with Terraform on Azure

Complete tutorial about azurerm_app_service in Terraform. Learn app service plans, web apps, deployment slots.

Deploying Web Apps with Terraform on Azure

Deploying Web Apps with Terraform on Azure

Introduction

Deploying web applications in the cloud has become essential for modern software development. With Azure App Service, developers can build and host web applications in a fully managed environment, allowing them to focus on coding rather than managing infrastructure. Terraform, an Infrastructure as Code (IaC) tool, enables developers to automate the deployment of Azure resources, including App Services, using HashiCorp Configuration Language (HCL).

Infrastructure as Code (IaC) is a practice that allows you to manage and provision your infrastructure using code, which can be version-controlled and reused. This method minimizes errors and enhances scalability, making it a preferred choice for managing cloud resources. Common use cases for Azure App Services include hosting websites, REST APIs, and mobile backends.

In this tutorial, we will explore how to deploy web applications on Azure using Terraform, focusing on App Service Plans, Web Apps, and Deployment Slots.

Prerequisites

Before you begin, ensure you have the following:

  • Terraform CLI: Install Terraform from the official website.
  • Azure Subscription: If you don’t have one, you can create a free account.
  • Azure CLI: Install the Azure CLI for managing Azure resources from your local machine. You can find it here.
  • Service Principal: Create a service principal for Terraform to authenticate against Azure.
az login
az ad sp create-for-rbac --name "TerraformSP" --role Contributor --scopes /subscriptions/{subscription-id}

Fundamental Concepts

Key Terminology

  • App Service Plan: Defines the region (datacenter) of the app, and the underlying compute resources for hosting the app.
  • Web App: The actual application that runs in the App Service.
  • Deployment Slots: Clone of the web app that allows you to host different versions of your application. These can be used for staging, testing, or production environments.

Resource Dependencies

Understanding the dependencies between resources is crucial. For example, a Web App needs an App Service Plan to run. Deployment slots are tied to their respective web apps.

State Management

Terraform manages the state of your infrastructure through a state file. This file keeps track of the resources it manages, allowing Terraform to understand the current configuration and make necessary updates.

Resource Syntax

The following is the HCL syntax for the azurerm_app_service resource, which is part of the Azure Provider.

resource "azurerm_app_service" "example" {
  name                = "example-app-service"
  location            = azurerm_resource_group.example.location
  resource_group_name = azurerm_resource_group.example.name
  app_service_plan_id = azurerm_app_service_plan.example.id

  site_config {
    always_on = true
    dotnet_version = "v6.0"
  }

  identity {
    type = "SystemAssigned"
  }
}

Arguments Table

Argument Description
name The name of the App Service.
location The Azure region where the App Service is hosted.
resource_group_name The name of the resource group.
app_service_plan_id The ID of the App Service Plan.
site_config Configuration options for the app.
identity Managed identity configuration.

Practical Examples

1. Basic App Service Plan Creation

resource "azurerm_app_service_plan" "example" {
  name                = "example-app-service-plan"
  location            = "East US"
  resource_group_name = azurerm_resource_group.example.name
  sku {
    tier     = "Standard"
    size     = "S1"
  }
}

2. Creating a Basic Web App

resource "azurerm_app_service" "example" {
  name                = "example-web-app"
  location            = azurerm_resource_group.example.location
  resource_group_name = azurerm_resource_group.example.name
  app_service_plan_id = azurerm_app_service_plan.example.id

  site_config {
    always_on = true
    dotnet_version = "v6.0"
  }
}

3. Adding Deployment Slots

resource "azurerm_app_service_slot" "staging" {
  name                = "staging"
  resource_group_name = azurerm_resource_group.example.name
  app_service_name    = azurerm_app_service.example.name
  app_service_plan_id = azurerm_app_service_plan.example.id

  site_config {
    always_on = true
  }
}

4. Configuring Connection Strings

resource "azurerm_app_service" "example" {
  name                = "example-web-app"
  location            = azurerm_resource_group.example.location
  resource_group_name = azurerm_resource_group.example.name
  app_service_plan_id = azurerm_app_service_plan.example.id

  connection_string {
    name  = "DatabaseConnectionString"
    value = "Your_Connection_String"
    type  = "SQLAzure"
  }
}

5. Setting Environment Variables

resource "azurerm_app_service" "example" {
  name                = "example-web-app"
  location            = azurerm_resource_group.example.location
  resource_group_name = azurerm_resource_group.example.name
  app_service_plan_id = azurerm_app_service_plan.example.id

  app_settings = {
    "ASPNETCORE_ENVIRONMENT" = "Development"
    "SOME_API_KEY"           = "your_api_key"
  }
}

6. Integrating with Azure Monitor

resource "azurerm_monitor_diagnostic_setting" "example" {
  name               = "example-diagnostic-setting"
  target_resource_id = azurerm_app_service.example.id

  log_analytics {
    workspace_id = azurerm_log_analytics_workspace.example.id

    logs {
      category = "AppServiceHTTPLogs"
      retention_policy {
        enabled = false
      }
    }
  }
}

7. Swapping Deployment Slots

resource "azurerm_app_service_slot" "staging" {
  name                = "staging"
  resource_group_name = azurerm_resource_group.example.name
  app_service_name    = azurerm_app_service.example.name
  app_service_plan_id = azurerm_app_service_plan.example.id

  site_config {
    always_on = true
  }
}

resource "azurerm_app_service_slot_swap" "example" {
  name                = "example-app-service"
  resource_group_name = azurerm_resource_group.example.name
  source_slot_name    = azurerm_app_service_slot.staging.name
  destination_slot_name = "production"
}

8. Complete Infrastructure Example

provider "azurerm" {
  features {}
}

resource "azurerm_resource_group" "example" {
  name     = "example-resources"
  location = "East US"
}

resource "azurerm_app_service_plan" "example" {
  name                = "example-app-service-plan"
  location            = azurerm_resource_group.example.location
  resource_group_name = azurerm_resource_group.example.name
  sku {
    tier = "Standard"
    size = "S1"
  }
}

resource "azurerm_app_service" "example" {
  name                = "example-web-app"
  location            = azurerm_resource_group.example.location
  resource_group_name = azurerm_resource_group.example.name
  app_service_plan_id = azurerm_app_service_plan.example.id

  app_settings = {
    "ASPNETCORE_ENVIRONMENT" = "Development"
  }
}

resource "azurerm_app_service_slot" "staging" {
  name                = "staging"
  resource_group_name = azurerm_resource_group.example.name
  app_service_name    = azurerm_app_service.example.name
  app_service_plan_id = azurerm_app_service_plan.example.id

  site_config {
    always_on = true
  }
}

Real-World Use Cases

  1. Continuous Delivery: Using deployment slots for staging and production, teams can push changes to the staging slot, validate them, and then swap them into production seamlessly. This minimizes downtime and risk.

  2. A/B Testing: You can deploy two versions of your application in different slots and route a portion of traffic to each slot to analyze performance and user engagement.

  3. Rollback Strategy: In case of a failed deployment, you can quickly swap back to the previous version of your app without downtime, ensuring business continuity.

Best Practices

  • Use Variables: Manage environment-specific configurations with Terraform variables.
  • State Management: Store state files in a remote backend (like Azure Storage) to avoid potential conflicts.
  • Naming Conventions: Use clear and consistent naming conventions for resources to improve readability.
  • Access Control: Limit access to your Azure resources and Terraform state files to ensure security.
  • Modularize Code: Break your Terraform code into reusable modules for better organization and maintainability.

Common Errors

  1. Resource Already Exists:

    • Error: Error: Error creating App Service "example-web-app": Name is already in use
    • Solution: Ensure the name is unique across Azure.
  2. Invalid Resource Group:

    • Error: Error: Resource group 'example-resources' not found
    • Solution: Verify the resource group exists before deployment.
  3. Insufficient Permissions:

    • Error: Error: AuthorizationFailed
    • Solution: Ensure that the service principal has the necessary permissions to create resources.
  4. Invalid Slot Name:

    • Error: Error: Invalid slot name
    • Solution: Ensure the slot name follows Azure naming rules and is unique.

Related Resources

Resource Type Documentation Link
Azure App Service Azure App Service Documentation
Terraform Azure Provider Terraform Azure Provider Docs
Terraform CLI Terraform Documentation
Azure CLI Azure CLI Documentation

Complete Infrastructure Script

provider "azurerm" {
  features {}
}

resource "azurerm_resource_group" "example" {
  name     = "example-resources"
  location = "East US"
}

resource "azurerm_app_service_plan" "example" {
  name                = "example-app-service-plan"
  location            = azurerm_resource_group.example.location
  resource_group_name = azurerm_resource_group.example.name
  sku {
    tier = "Standard"
    size = "S1"
  }
}

resource "azurerm_app_service" "example" {
  name                = "example-web-app"
  location            = azurerm_resource_group.example.location
  resource_group_name = azurerm_resource_group.example.name
  app_service_plan_id = azurerm_app_service_plan.example.id

  app_settings = {
    "ASPNETCORE_ENVIRONMENT" = "Development"
  }
}

resource "azurerm_app_service_slot" "staging" {
  name                = "staging"
  resource_group_name = azurerm_resource_group.example.name
  app_service_name    = azurerm_app_service.example.name
  app_service_plan_id = azurerm_app_service_plan.example.id

  site_config {
    always_on = true
  }
}

Conclusion

In this tutorial, we explored how to deploy web apps on Azure using Terraform. We covered the creation of App Service Plans, Web Apps, and Deployment Slots, providing a comprehensive understanding of how to manage infrastructure as code. By leveraging these tools and best practices, developers can streamline their deployment processes, enhance collaboration, and ensure robust application performance in the cloud.

Next Steps

You can experiment with more advanced configurations, such as connecting your web apps to databases or setting up CI/CD pipelines using Azure DevOps.

References


This tutorial serves as a solid foundation for deploying web applications on Azure using Terraform. Happy coding! 🚀