Edit

Quickstart: Deploy Azure ALB Controller on AKS using Terraform

Application Gateway for Containers is a managed layer 7 load balancing and ingress service for Kubernetes workloads. The ALB Controller is the Kubernetes controller that runs in your Azure Kubernetes Service (AKS) cluster and translates Gateway API and Ingress API configuration into Application Gateway for Containers load balancing rules. In this quickstart, you use Terraform to deploy an AKS cluster, enable the Application Gateway for Containers ALB Controller add-on, and install the managed Gateway API implementation that the add-on requires.

Terraform enables the definition, preview, and deployment of cloud infrastructure. Using Terraform, you create configuration files using HCL syntax. The HCL syntax allows you to specify the cloud provider - such as Azure - and the elements that make up your cloud infrastructure. After you create your configuration files, you create an execution plan that allows you to preview your infrastructure changes before they're deployed. Once you verify the changes, you apply the execution plan to deploy the infrastructure.

In this article, you learn how to:

Prerequisites

  • Install and configure Terraform.

  • An Azure account with an active subscription and permission to create AKS resources and assign roles in that subscription. If you don't have an Azure account, create one for free.

  • Terraform version 1.6.0 or later.

  • Azure CLI installed, and signed in with az login.

  • kubectl installed.

  • This quickstart deploys a new AKS cluster, so you don't need an existing cluster before you begin. The cluster that Terraform creates uses Azure CNI networking. AKS Automatic clusters aren't supported for this scenario.

  • The Microsoft.ContainerService and Microsoft.ServiceNetworking resource providers registered in your subscription. For more information, see Azure resource providers and types.

  • A supported Azure region for Application Gateway for Containers.

  • The Application Gateway for Containers ALB Controller add-on and the AKS-managed Gateway API installation are in preview. Preview features are governed by the Supplemental Terms of Use for Microsoft Azure Previews.

  • The ApplicationLoadBalancerPreview and ManagedGatewayAPIPreview preview features registered on the Microsoft.ContainerService resource provider in your subscription. Feature registration is subscription-wide, so if another cluster in the subscription already registered these features, you don't need to register them again. Registration is asynchronous and can take several minutes to propagate. The Terraform configuration in this quickstart registers the features and waits for the registration to propagate, but you can also register them ahead of time:

    az feature register --namespace Microsoft.ContainerService --name ApplicationLoadBalancerPreview
    az feature register --namespace Microsoft.ContainerService --name ManagedGatewayAPIPreview
    az provider register --namespace Microsoft.ContainerService
    

Implement the Terraform code

  1. Create a directory to test the sample Terraform code and set it as the current directory.

  2. Create a file named main.tf and add the following code:

    terraform {
      required_version = ">= 1.6.0"
    
      required_providers {
        azurerm = {
          source  = "hashicorp/azurerm"
          version = "~> 4.0"
        }
        azapi = {
          source  = "Azure/azapi"
          version = "~> 2.0"
        }
        random = {
          source  = "hashicorp/random"
          version = "~> 3.6"
        }
        time = {
          source  = "hashicorp/time"
          version = "~> 0.12"
        }
      }
    }
    
    provider "azurerm" {
      features {}
    }
    
    provider "azapi" {}
    
    data "azapi_client_config" "current" {}
    
    resource "random_pet" "suffix" {
      length = 2
    }
    
    locals {
      resource_group_name = "rg-agfc-alb-${random_pet.suffix.id}"
      aks_name            = "aks-alb-${random_pet.suffix.id}"
      location            = "eastus"
      # The ALB Controller add-on and the managed Gateway API installation are in preview
      # and require these subscription level feature registrations.
      preview_features = [
        "ApplicationLoadBalancerPreview",
        "ManagedGatewayAPIPreview",
      ]
    }
    
    resource "azapi_resource_action" "register_preview_features" {
      for_each = toset(local.preview_features)
    
      type        = "Microsoft.Features/featureProviders/subscriptionFeatureRegistrations@2021-07-01"
      resource_id = "${data.azapi_client_config.current.subscription_resource_id}/providers/Microsoft.Features/featureProviders/Microsoft.ContainerService/subscriptionFeatureRegistrations/${each.value}"
      method      = "PUT"
      body = {
        properties = {}
      }
    }
    
    # Feature registration is asynchronous, wait before refreshing the resource provider.
    resource "time_sleep" "wait_for_feature_registration" {
      create_duration = "10m"
    
      depends_on = [azapi_resource_action.register_preview_features]
    }
    
    # Re-registering the resource provider propagates the registered preview features.
    resource "azapi_resource_action" "register_container_service" {
      type        = "Microsoft.Resources/providers@2021-04-01"
      resource_id = "${data.azapi_client_config.current.subscription_resource_id}/providers/Microsoft.ContainerService"
      action      = "register"
      method      = "POST"
    
      depends_on = [time_sleep.wait_for_feature_registration]
    }
    
    resource "azurerm_resource_group" "rg" {
      name     = local.resource_group_name
      location = local.location
    }
    
    resource "azurerm_kubernetes_cluster" "aks" {
      name                      = local.aks_name
      location                  = azurerm_resource_group.rg.location
      resource_group_name       = azurerm_resource_group.rg.name
      dns_prefix                = local.aks_name
      oidc_issuer_enabled       = true
      workload_identity_enabled = true
    
      default_node_pool {
        name       = "systempool"
        node_count = 1
        vm_size    = "Standard_D2s_v7"
    
    upgrade_settings {
         drain_timeout_in_minutes      = 0
         max_surge                     = "10%"
         node_soak_duration_in_minutes = 0
       }
      }
    
      identity {
        type = "SystemAssigned"
      }
    
      network_profile {
        network_plugin    = "azure"
        network_policy    = "azure"
        load_balancer_sku = "standard"
      }
    }
    
    resource "azapi_update_resource" "enable_alb_controller_addon" {
      type        = "Microsoft.ContainerService/managedClusters@2025-09-02-preview"
      resource_id = azurerm_kubernetes_cluster.aks.id
      body = {
        properties = {
          ingressProfile = {
            applicationLoadBalancer = {
              enabled = true
            }
            gatewayAPI = {
              installation = "Standard"
            }
          }
        }
      }
    
      # Keep retrying while the preview feature registrations propagate to the resource provider.
      retry = {
        error_message_regex  = ["PreviewFeatureNotRegistered"]
        interval_seconds     = 60
        max_interval_seconds = 300
      }
    
      timeouts {
        create = "90m"
        update = "90m"
      }
    
      depends_on = [azapi_resource_action.register_container_service]
    }
    
    output "resource_group_name" {
      value = azurerm_resource_group.rg.name
    }
    
    output "aks_cluster_name" {
      value = azurerm_kubernetes_cluster.aks.name
    }
    
    output "aks_cluster_id" {
      value = azurerm_kubernetes_cluster.aks.id
    }
    

Note

The configuration registers the ApplicationLoadBalancerPreview and ManagedGatewayAPIPreview subscription features, waits for the registrations to propagate, and then re-registers the Microsoft.ContainerService resource provider so the propagated features take effect. The resource that enables the add-on retries automatically while the resource provider still reports the features as unregistered. Because of this registration and retry sequence, the first terraform apply can take considerably longer than a typical AKS deployment.

Initialize Terraform

Run terraform init to initialize the Terraform deployment. This command downloads the Azure provider required to manage your Azure resources.

terraform init -upgrade

Key points:

  • The -upgrade parameter upgrades the necessary provider plugins to the newest version that complies with the configuration's version constraints.

Create a Terraform execution plan

Run terraform plan to create an execution plan.

terraform plan -out main.tfplan

Key points:

  • The terraform plan command creates an execution plan, but doesn't execute it. Instead, it determines what actions are necessary to create the configuration specified in your configuration files. This pattern allows you to verify whether the execution plan matches your expectations before making any changes to actual resources.
  • The optional -out parameter allows you to specify an output file for the plan. Using the -out parameter ensures that the plan you reviewed is exactly what is applied.

Apply a Terraform execution plan

Run terraform apply to apply the execution plan to your cloud infrastructure.

terraform apply main.tfplan

Key points:

  • The example terraform apply command assumes you previously ran terraform plan -out main.tfplan.
  • If you specified a different filename for the -out parameter, use that same filename in the call to terraform apply.
  • If you didn't use the -out parameter, call terraform apply without any parameters.

Verify the results

  1. Get the resource group name, AKS cluster name, and AKS cluster resource ID from the Terraform state.

    resource_group_name=$(terraform output -raw resource_group_name)
    aks_cluster_name=$(terraform output -raw aks_cluster_name)
    aks_cluster_id=$(terraform output -raw aks_cluster_id)
    
  2. Get the AKS cluster credentials by using the az aks get-credentials command.

    az aks get-credentials --resource-group $resource_group_name --name $aks_cluster_name
    
  3. Confirm the AKS ingressProfile shows the Application Gateway for Containers ALB Controller add-on as enabled. Query the same preview API version that the Terraform configuration used to enable the add-on.

    az rest --method get --uri "https://management.azure.com${aks_cluster_id}?api-version=2025-09-02-preview" --query "properties.ingressProfile"
    

    The output shows applicationLoadBalancer.enabled set to true and gatewayAPI.installation set to Standard.

  4. Verify the ALB Controller pods are running in the kube-system namespace.

    kubectl get pods -n kube-system | grep alb-controller
    

    You should see two alb-controller pods in a Running state.

  5. Verify the azure-alb-external GatewayClass is installed on your cluster.

    kubectl get gatewayclass azure-alb-external -o yaml
    

    The output shows a condition of type Accepted with the message Valid GatewayClass, which confirms the ALB Controller manages the azure-alb-external GatewayClass.

Clean up resources

When you no longer need the resources created via Terraform, do the following steps:

  1. Run terraform plan and specify the destroy flag.

    terraform plan -destroy -out main.destroy.tfplan
    

    Key points:

    • The terraform plan command creates an execution plan, but doesn't execute it. Instead, it determines what actions are necessary to create the configuration specified in your configuration files. This pattern allows you to verify whether the execution plan matches your expectations before making any changes to actual resources.
    • The optional -out parameter allows you to specify an output file for the plan. Using the -out parameter ensures that the plan you reviewed is exactly what is applied.
  2. Run terraform apply to apply the execution plan.

    terraform apply main.destroy.tfplan
    

Running terraform destroy removes the resource group and the AKS cluster that Terraform created. It doesn't remove the ApplicationLoadBalancerPreview and ManagedGatewayAPIPreview feature registrations, or the Microsoft.ContainerService resource provider registration, because those registrations are subscription-wide settings that Terraform doesn't manage as destroyable resources. Before you unregister a preview feature manually, verify that no other clusters or workloads in your subscription still depend on it.

Troubleshoot Terraform on Azure

Troubleshoot common problems when using Terraform on Azure.

Next steps