Built upon the success of the previous post this time I went to deploy a webapp too. It was not more complicated than the previous excercise – only about 20 minutes in total (including typing this post!)

  • terragrunt.hcl file just to have the resource groups ready
  • the main.tf to store the config of the webapp (note: I use sample code and I use a random number in the app’s address…not recommended to production!)
  • output.tf file to display the webapps line
#  cat .\terragrunt.hcl     
include {
  path = find_in_parent_folders()
}

dependencies {
  paths = ["../resource-groups"]
}
# cat .\main.tf
data "azurerm_resource_group" "webapp_rg" {
  name = "my-webapp-rg"
}

# Generate a random integer to create a globally unique name
resource "random_integer" "ri" {
  min = 10000
  max = 99999
}

# Create the Linux App Service Plan
resource "azurerm_service_plan" "appserviceplan" {
  name                = "webapp-asp-${random_integer.ri.result}"
  location            = data.azurerm_resource_group.webapp_rg.location
  resource_group_name = data.azurerm_resource_group.webapp_rg.name
  os_type             = "Linux"
  sku_name            = "B1"
}

# Create the web app, pass in the App Service Plan ID
resource "azurerm_linux_web_app" "webapp" {
  name                = "webapp-${random_integer.ri.result}"
  location            = data.azurerm_resource_group.webapp_rg.location
  resource_group_name = data.azurerm_resource_group.webapp_rg.name
  service_plan_id     = azurerm_service_plan.appserviceplan.id
  https_only          = true
  site_config {
    minimum_tls_version = "1.2"
  }
}

#  Deploy code from a public GitHub repo
resource "azurerm_app_service_source_control" "sourcecontrol" {
  app_id                 = azurerm_linux_web_app.webapp.id
  repo_url               = "https://github.com/Azure-Samples/nodejs-docs-hello-world"
  branch                 = "master"
  use_manual_integration = true
  use_mercurial          = false
}
# cat .\outputs.tf
output "url" {
  value = "http://${azurerm_linux_web_app.webapp.name}.azurewebsites.net/"
}

The result we all been waiting for:

terragrunt apply --auto-approve
data.azurerm_resource_group.webapp_rg: Reading...
data.azurerm_resource_group.webapp_rg: Read complete after 1s [id=/subscriptions/23a1af48-a0ad-41c8-9618-231e39f18b12/resourceGroups/my-webapp-rg]

Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # azurerm_app_service_source_control.sourcecontrol will be created
  + resource "azurerm_app_service_source_control" "sourcecontrol" {
      + app_id                 = (known after apply)
      + branch                 = "master"
      + id                     = (known after apply)
      + repo_url               = "https://github.com/Azure-Samples/nodejs-docs-hello-world"
      + rollback_enabled       = false
      + scm_type               = (known after apply)
      + use_local_git          = false
      + use_manual_integration = true
      + use_mercurial          = false
      + uses_github_action     = (known after apply)
    }

  # azurerm_linux_web_app.webapp will be created
  + resource "azurerm_linux_web_app" "webapp" {
      + client_affinity_enabled           = false
      + client_certificate_enabled        = false
      + client_certificate_mode           = "Required"
      + custom_domain_verification_id     = (sensitive value)
      + default_hostname                  = (known after apply)
      + enabled                           = true
      + https_only                        = true
      + id                                = (known after apply)
      + key_vault_reference_identity_id   = (known after apply)
      + kind                              = (known after apply)
      + location                          = "northeurope"
      + name                              = (known after apply)
      + outbound_ip_address_list          = (known after apply)
      + outbound_ip_addresses             = (known after apply)
      + possible_outbound_ip_address_list = (known after apply)
      + possible_outbound_ip_addresses    = (known after apply)
      + resource_group_name               = "my-webapp-rg"
      + service_plan_id                   = (known after apply)
      + site_credential                   = (known after apply)
      + zip_deploy_file                   = (known after apply)

      + auth_settings {
          + additional_login_parameters    = (known after apply)
          + allowed_external_redirect_urls = (known after apply)
          + default_provider               = (known after apply)
          + enabled                        = (known after apply)
          + issuer                         = (known after apply)
          + runtime_version                = (known after apply)
          + token_refresh_extension_hours  = (known after apply)
          + token_store_enabled            = (known after apply)
          + unauthenticated_client_action  = (known after apply)

          + active_directory {
              + allowed_audiences          = (known after apply)
              + client_id                  = (known after apply)
              + client_secret              = (sensitive value)
              + client_secret_setting_name = (known after apply)
            }

          + facebook {
              + app_id                  = (known after apply)
              + app_secret              = (sensitive value)
              + app_secret_setting_name = (known after apply)
              + oauth_scopes            = (known after apply)
            }

          + github {
              + client_id                  = (known after apply)
              + client_secret              = (sensitive value)
              + client_secret_setting_name = (known after apply)
              + oauth_scopes               = (known after apply)
            }

          + google {
              + client_id                  = (known after apply)
              + client_secret              = (sensitive value)
              + client_secret_setting_name = (known after apply)
              + oauth_scopes               = (known after apply)
            }

          + microsoft {
              + client_id                  = (known after apply)
              + client_secret              = (sensitive value)
              + client_secret_setting_name = (known after apply)
              + oauth_scopes               = (known after apply)
            }

          + twitter {
              + consumer_key                 = (known after apply)
              + consumer_secret              = (sensitive value)
              + consumer_secret_setting_name = (known after apply)
            }
        }

      + site_config {
          + always_on                               = true
          + container_registry_use_managed_identity = false
          + default_documents                       = (known after apply)
          + detailed_error_logging_enabled          = (known after apply)
          + ftps_state                              = "Disabled"
          + health_check_eviction_time_in_min       = (known after apply)
          + http2_enabled                           = false
          + ip_restriction                          = (known after apply)
          + linux_fx_version                        = (known after apply)
          + load_balancing_mode                     = "LeastRequests"
          + local_mysql_enabled                     = false
          + managed_pipeline_mode                   = "Integrated"
          + minimum_tls_version                     = "1.2"
          + remote_debugging_enabled                = false
          + remote_debugging_version                = (known after apply)
          + scm_ip_restriction                      = (known after apply)
          + scm_minimum_tls_version                 = "1.2"
          + scm_type                                = (known after apply)
          + scm_use_main_ip_restriction             = false
          + use_32_bit_worker                       = true
          + vnet_route_all_enabled                  = false
          + websockets_enabled                      = false
          + worker_count                            = (known after apply)

          + application_stack {
              + docker_image        = (known after apply)
              + docker_image_tag    = (known after apply)
              + dotnet_version      = (known after apply)
              + java_server         = (known after apply)
              + java_server_version = (known after apply)
              + java_version        = (known after apply)
              + node_version        = (known after apply)
              + php_version         = (known after apply)
              + python_version      = (known after apply)
              + ruby_version        = (known after apply)
            }
        }
    }

  # azurerm_service_plan.appserviceplan will be created
  + resource "azurerm_service_plan" "appserviceplan" {
      + id                           = (known after apply)
      + kind                         = (known after apply)
      + location                     = "northeurope"
      + maximum_elastic_worker_count = (known after apply)
      + name                         = (known after apply)
      + os_type                      = "Linux"
      + per_site_scaling_enabled     = false
      + reserved                     = (known after apply)
      + resource_group_name          = "my-webapp-rg"
      + sku_name                     = "B1"
      + worker_count                 = (known after apply)
    }

  # random_integer.ri will be created
  + resource "random_integer" "ri" {
      + id     = (known after apply)
      + max    = 99999
      + min    = 10000
      + result = (known after apply)
    }

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

Changes to Outputs:
  + url = (known after apply)
random_integer.ri: Creating...
random_integer.ri: Creation complete after 0s [id=70492]
azurerm_service_plan.appserviceplan: Creating...
azurerm_service_plan.appserviceplan: Creation complete after 5s [id=/subscriptions/23a1af48-a0ad-41c8-9618-231e39f18b12/resourceGroups/my-webapp-rg/providers/Microsoft.Web/serverfarms/webapp-asp-70492]
azurerm_linux_web_app.webapp: Creating...
azurerm_linux_web_app.webapp: Still creating... [10s elapsed]
azurerm_linux_web_app.webapp: Still creating... [20s elapsed]
azurerm_linux_web_app.webapp: Still creating... [30s elapsed]
azurerm_linux_web_app.webapp: Creation complete after 39s [id=/subscriptions/23a1af48-a0ad-41c8-9618-231e39f18b12/resourceGroups/my-webapp-rg/providers/Microsoft.Web/sites/webapp-70492]
azurerm_app_service_source_control.sourcecontrol: Creating...
azurerm_app_service_source_control.sourcecontrol: Still creating... [10s elapsed]
azurerm_app_service_source_control.sourcecontrol: Still creating... [20s elapsed]
azurerm_app_service_source_control.sourcecontrol: Still creating... [30s elapsed]
azurerm_app_service_source_control.sourcecontrol: Still creating... [40s elapsed]
azurerm_app_service_source_control.sourcecontrol: Creation complete after 43s [id=/subscriptions/23a1af48-a0ad-41c8-9618-231e39f18b12/resourceGroups/my-webapp-rg/providers/Microsoft.Web/sites/webapp-70492]

Apply complete! Resources: 4 added, 0 changed, 0 destroyed.

Outputs:

url = "http://webapp-70492.azurewebsites.net/"

As I havent deployed anything exciting to the actual application yet, it is slightly depressingly empty, but hey – the webapp is your Oyster!

view in AZ portal
view in browser