# Load Balancer

Source: /azure/services/load-balancer/

## Introduction

Azure Load Balancer distributes inbound TCP and UDP traffic across a pool of backend instances, such as virtual machines and scale set instances, at layer 4.
A load balancer has frontend IP configurations that receive traffic, backend address pools that serve it, load-balancing rules and inbound NAT rules that map frontend ports to backend ports, health probes that decide which backends receive traffic, and outbound rules for outbound connectivity. For more information, see [What is Azure Load Balancer?](https://learn.microsoft.com/en-us/azure/load-balancer/load-balancer-overview).

LocalStack for Azure provides a local environment for building and testing applications that make use of Azure Load Balancer.
The supported APIs are available on our [API Coverage section](#api-coverage), which provides information on the extent of Load Balancer's integration with LocalStack.

## Getting started

This guide is designed for users new to Azure Load Balancer and assumes basic knowledge of the Azure CLI and our `lstk az` proxy.

Launch LocalStack using your preferred method. For more information, see [Introduction to LocalStack for Azure](/azure/getting-started/). Once the container is running, enable Azure CLI interception by running:

```bash
lstk az start-interception
```

This command points the `az` CLI away from the public Azure management REST API and toward the LocalStack for Azure emulator API.
To revert this configuration, run:

```bash
lstk az stop-interception
```

This reconfigures the `az` CLI to send commands to the official Azure management REST API.

### Create a resource group and a network

Create a resource group, a virtual network with a backend subnet, and a Standard public IP address for the load balancer's frontend:

```bash
az group create \
  --name rg-lb-demo \
  --location westeurope

az network vnet create \
  --name vnet-lb-demo \
  --resource-group rg-lb-demo \
  --location westeurope \
  --address-prefixes 10.1.0.0/16 \
  --subnet-name subnet-backend \
  --subnet-prefixes 10.1.1.0/24

az network public-ip create \
  --name pip-lb-demo \
  --resource-group rg-lb-demo \
  --location westeurope \
  --sku Standard \
  --allocation-method Static
```

```bash title="Output"
{
  "publicIp": {
    "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-lb-demo/providers/Microsoft.Network/publicIPAddresses/pip-lb-demo",
    "ipAddress": "20.114.33.207",
    "location": "westeurope",
    "name": "pip-lb-demo",
    "provisioningState": "Succeeded",
    "publicIPAllocationMethod": "Static",
    "sku": {
      "name": "Standard",
      "tier": "Regional"
    },
    "type": "Microsoft.Network/publicIPAddresses"
    ...
  }
}
```

### Create a load balancer

Create a Standard load balancer with a public frontend and an empty backend address pool:

```bash
az network lb create \
  --name lb-demo \
  --resource-group rg-lb-demo \
  --location westeurope \
  --sku Standard \
  --public-ip-address pip-lb-demo \
  --frontend-ip-name fe-public \
  --backend-pool-name be-pool
```

```bash title="Output"
{
  "loadBalancer": {
    "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-lb-demo/providers/Microsoft.Network/loadBalancers/lb-demo",
    "location": "westeurope",
    "name": "lb-demo",
    "properties": {
      "backendAddressPools": [
        {
          "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-lb-demo/providers/Microsoft.Network/loadBalancers/lb-demo/backendAddressPools/be-pool",
          "name": "be-pool",
          ...
        }
      ],
      "frontendIPConfigurations": [
        {
          "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-lb-demo/providers/Microsoft.Network/loadBalancers/lb-demo/frontendIPConfigurations/fe-public",
          "name": "fe-public",
          "properties": {
            "privateIPAllocationMethod": "Dynamic",
            "provisioningState": "Succeeded",
            "publicIPAddress": {
              "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-lb-demo/providers/Microsoft.Network/publicIPAddresses/pip-lb-demo",
              "resourceGroup": "rg-lb-demo"
            },
            ...
          },
          ...
        }
      ],
      "inboundNatRules": [],
      "loadBalancingRules": [],
      "outboundRules": [],
      "probes": [],
      "provisioningState": "Succeeded"
    },
    "resourceGroup": "rg-lb-demo",
    "sku": {
      "name": "Standard",
      "tier": "Regional"
    },
    "type": "Microsoft.Network/loadBalancers"
  }
}
```

### Add a health probe and a load-balancing rule

Create an HTTP health probe:

```bash
az network lb probe create \
  --lb-name lb-demo \
  --resource-group rg-lb-demo \
  --name probe-http \
  --protocol Http \
  --port 80 \
  --path /
```

```bash title="Output"
{
  "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-lb-demo/providers/Microsoft.Network/loadBalancers/lb-demo/probes/probe-http",
  "intervalInSeconds": 15,
  "loadBalancingRules": [],
  "name": "probe-http",
  "numberOfProbes": 2,
  "port": 80,
  "probeThreshold": 1,
  "protocol": "Http",
  "provisioningState": "Succeeded",
  "requestPath": "/",
  "resourceGroup": "rg-lb-demo",
  "type": "Microsoft.Network/loadBalancers/probes"
}
```

Then create a rule that balances TCP port 80 across the backend pool, using the probe:

```bash
az network lb rule create \
  --lb-name lb-demo \
  --resource-group rg-lb-demo \
  --name rule-http \
  --protocol Tcp \
  --frontend-port 80 \
  --backend-port 80 \
  --frontend-ip-name fe-public \
  --backend-pool-name be-pool \
  --probe-name probe-http
```

```bash title="Output"
{
  "backendAddressPool": {
    "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-lb-demo/providers/Microsoft.Network/loadBalancers/lb-demo/backendAddressPools/be-pool",
    "resourceGroup": "rg-lb-demo"
  },
  "backendPort": 80,
  "enableFloatingIP": false,
  "enableTcpReset": false,
  "frontendIPConfiguration": {
    "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-lb-demo/providers/Microsoft.Network/loadBalancers/lb-demo/frontendIPConfigurations/fe-public",
    "resourceGroup": "rg-lb-demo"
  },
  "frontendPort": 80,
  "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-lb-demo/providers/Microsoft.Network/loadBalancers/lb-demo/loadBalancingRules/rule-http",
  "idleTimeoutInMinutes": 4,
  "loadDistribution": "Default",
  "name": "rule-http",
  "probe": {
    "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-lb-demo/providers/Microsoft.Network/loadBalancers/lb-demo/probes/probe-http",
    "resourceGroup": "rg-lb-demo"
  },
  "protocol": "Tcp",
  "provisioningState": "Succeeded",
  "type": "Microsoft.Network/loadBalancers/loadBalancingRules"
  ...
}
```

### Add an inbound NAT rule

Map frontend port 50001 to SSH on a backend instance:

```bash
az network lb inbound-nat-rule create \
  --lb-name lb-demo \
  --resource-group rg-lb-demo \
  --name nat-ssh \
  --protocol Tcp \
  --frontend-port 50001 \
  --backend-port 22 \
  --frontend-ip-name fe-public
```

```bash title="Output"
{
  "backendPort": 22,
  "enableFloatingIP": false,
  "enableTcpReset": false,
  "frontendIPConfiguration": {
    "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-lb-demo/providers/Microsoft.Network/loadBalancers/lb-demo/frontendIPConfigurations/fe-public",
    "resourceGroup": "rg-lb-demo"
  },
  "frontendPort": 50001,
  "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-lb-demo/providers/Microsoft.Network/loadBalancers/lb-demo/inboundNatRules/nat-ssh",
  "idleTimeoutInMinutes": 4,
  "name": "nat-ssh",
  "protocol": "Tcp",
  "provisioningState": "Succeeded",
  "resourceGroup": "rg-lb-demo",
  "type": "Microsoft.Network/loadBalancers/inboundNatRules"
}
```

### Add a network interface to the backend pool

Create a network interface in the backend subnet and add its IP configuration to the backend pool:

```bash
az network nic create \
  --name nic-lb-demo \
  --resource-group rg-lb-demo \
  --location westeurope \
  --vnet-name vnet-lb-demo \
  --subnet subnet-backend \
  --lb-name lb-demo \
  --lb-address-pools be-pool
```

The backend pool now lists the network interface's IP configuration:

```bash
az network lb address-pool show \
  --lb-name lb-demo \
  --resource-group rg-lb-demo \
  --name be-pool
```

```bash title="Output"
{
  "backendIPConfigurations": [
    {
      "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-lb-demo/providers/Microsoft.Network/networkInterfaces/nic-lb-demo/ipConfigurations/ipconfig1",
      "resourceGroup": "rg-lb-demo"
    }
  ],
  "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-lb-demo/providers/Microsoft.Network/loadBalancers/lb-demo/backendAddressPools/be-pool",
  "inboundNatRules": [],
  "loadBalancerBackendAddresses": [],
  "loadBalancingRules": [],
  "name": "be-pool",
  "outboundRules": [],
  "provisioningState": "Succeeded",
  "resourceGroup": "rg-lb-demo",
  "tunnelInterfaces": [],
  "type": "Microsoft.Network/loadBalancers/backendAddressPools"
}
```

### List and delete load balancers

List the load balancers in the resource group:

```bash
az network lb list \
  --resource-group rg-lb-demo \
  --output table
```

```bash title="Output"
Location    Name     ProvisioningState    ResourceGroup
----------  -------  -------------------  ---------------
westeurope  lb-demo  Succeeded            rg-lb-demo
```

Delete the network interface and the load balancer, then list the load balancers again to confirm the deletion:

```bash
az network nic delete \
  --name nic-lb-demo \
  --resource-group rg-lb-demo

az network lb delete \
  --name lb-demo \
  --resource-group rg-lb-demo

az network lb list \
  --resource-group rg-lb-demo
```

```bash title="Output"
[]
```

## Features

The Load Balancer emulator supports the following features:

- **Create and manage load balancers**: Full lifecycle management including create, get, update tags, list, and delete, with Basic and Standard SKUs.
- **Frontend IP configurations**: Public frontends that reference a public IP address, and private frontends whose IP address is allocated from the subnet (dynamic) or reserved (static), and released again when the load balancer is deleted.
- **Child resources**: Backend address pools and inbound NAT rules can be managed on their own; frontend IP configurations, load-balancing rules, health probes and outbound rules are managed through the load balancer, as the `az network lb` subcommands do.
- **Backend pool membership**: Network interfaces that join a backend pool appear in the pool's `backendIPConfigurations`.
- **AKS integration**: Each AKS cluster gets a Standard load balancer named `kubernetes` in its node resource group, which the cluster's cloud controller manager updates for `LoadBalancer` services.

## Limitations

- **No traffic distribution**: Load balancers are stored and returned faithfully, but no traffic is balanced, probed, or translated by inbound NAT or outbound rules.
- **Limited validation**: Rules and probes are not validated against each other; for example, a rule that references a probe that does not exist is accepted. Port ranges are not checked.
- **Some properties are not stored**: For example, a load-balancing rule's `disableOutboundSnat` is always returned as `false`.
- **Back-references stay empty**: A frontend IP configuration does not list the rules that use it, and the list of network interfaces of a load balancer is always empty.
- **Inbound NAT pools**: Inbound NAT pools are accepted as part of the load balancer, but they are only stored.

## API Coverage


### Load Balancer API coverage

Source service: `load-balancer`. 23 of 26 tracked operations are implemented.

Service documentation: /azure/services/load-balancer/

| Operation | Status |
| --- | --- |
| InboundNatRules.CreateOrUpdate | Implemented |
| InboundNatRules.Delete | Implemented |
| InboundNatRules.Get | Implemented |
| InboundNatRules.List | Implemented |
| LoadBalancerBackendAddressPools.CreateOrUpdate | Implemented |
| LoadBalancerBackendAddressPools.Delete | Implemented |
| LoadBalancerBackendAddressPools.Get | Implemented |
| LoadBalancerBackendAddressPools.List | Implemented |
| LoadBalancerFrontendIpConfigurations.Get | Implemented |
| LoadBalancerFrontendIpConfigurations.List | Implemented |
| LoadBalancerLoadBalancingRules.Get | Implemented |
| LoadBalancerLoadBalancingRules.Health | Not implemented |
| LoadBalancerLoadBalancingRules.List | Implemented |
| LoadBalancerNetworkInterfaces.List | Implemented |
| LoadBalancerOutboundRules.Get | Implemented |
| LoadBalancerOutboundRules.List | Implemented |
| LoadBalancerProbes.Get | Implemented |
| LoadBalancerProbes.List | Implemented |
| LoadBalancers.CreateOrUpdate | Implemented |
| LoadBalancers.Delete | Implemented |
| LoadBalancers.Get | Implemented |
| LoadBalancers.List | Implemented |
| LoadBalancers.ListAll | Implemented |
| LoadBalancers.ListInboundNatRulePortMappings | Not implemented |
| LoadBalancers.MigrateToIpBased | Not implemented |
| LoadBalancers.UpdateTags | Implemented |
