10.5 Load Balancer Setup¶
Overview¶
The Azure Load Balancer distributes incoming traffic across multiple VMs, providing high availability and scalability. This configuration uses a Standard SKU public load balancer with health probes and load balancing rules.
Load Balancer Architecture¶
Internet
↓
[Public IP: Static]
↓
┌──────────────────────┐
│ Azure Load Balancer │
│ (Standard SKU) │
└──────────────────────┘
↓
┌──────────┴──────────┐
↓ ↓
[Health Probe] [LB Rule: Port 80]
(Port 80) (TCP)
↓ ↓
┌───────────────────────────────┐
│ Backend Address Pool │
└───────────────────────────────┘
↓ ↓
[VM 0] [VM 1]
(10.0.1.x) (10.0.1.y)
Load Balancer Resource¶
Terraform Configuration¶
resource "azurerm_lb" "example" {
name = var.load_balancer_name
location = azurerm_resource_group.example.location
resource_group_name = azurerm_resource_group.example.name
sku = "Standard"
frontend_ip_configuration {
name = var.public_ip_name
public_ip_address_id = azurerm_public_ip.example.id
}
}
Key Properties¶
| Property | Value | Description |
|---|---|---|
| name | test-lb |
Load balancer identifier |
| sku | Standard |
Standard SKU (required for zones, outbound rules) |
| frontend_ip_configuration | Public IP | Entry point for traffic |
SKU Comparison¶
| Feature | Basic | Standard |
|---|---|---|
| Backend Pool Size | Up to 300 | Up to 1000 |
| Health Probes | HTTP, TCP | HTTP, HTTPS, TCP |
| Availability Zones | ❌ | ✅ |
| Outbound Rules | ❌ | ✅ |
| SLA | None | 99.99% |
| Cost | Free | Paid |
| Security | Open by default | Closed by default |
Why Standard?: Better features, SLA, and required for production workloads.
Backend Address Pool¶
Terraform Configuration¶
resource "azurerm_lb_backend_address_pool" "example" {
loadbalancer_id = azurerm_lb.example.id
name = "test-pool"
}
Purpose¶
The backend pool is a collection of VMs that receive traffic from the load balancer. VMs are added via NIC associations (configured in section 10.3).
Backend Pool Members¶
Backend Pool: "test-pool"
├── VM 0 (via NIC 0)
│ └── Private IP: 10.0.1.x
└── VM 1 (via NIC 1)
└── Private IP: 10.0.1.y
Health Probe¶
Terraform Configuration¶
resource "azurerm_lb_probe" "example" {
loadbalancer_id = azurerm_lb.example.id
name = "test-probe"
port = 80
}
How Health Probes Work¶
- Probe Interval: Load balancer sends HTTP request to port 80 every 15 seconds (default)
- Success Criteria: HTTP 200 OK response
- Failure Threshold: 2 consecutive failures mark VM as unhealthy (default)
- Action: Unhealthy VMs removed from rotation
Health Probe Flow¶
Load Balancer
↓ (every 15s)
GET / HTTP/1.1
↓
VM responds
↓
┌─────────────────┐
│ HTTP 200 OK? │
└─────────────────┘
↓ ↓
Yes No
↓ ↓
Healthy Unhealthy
(in pool) (removed)
Probe Configuration Options¶
resource "azurerm_lb_probe" "example" {
loadbalancer_id = azurerm_lb.example.id
name = "test-probe"
protocol = "Http" # Http, Https, or Tcp
port = 80
request_path = "/" # For HTTP/HTTPS probes
interval_in_seconds = 15 # Default: 15
number_of_probes = 2 # Failures before unhealthy
}
Load Balancing Rule¶
Terraform Configuration¶
resource "azurerm_lb_rule" "example_rule" {
loadbalancer_id = azurerm_lb.example.id
name = "test-rule"
protocol = "Tcp"
frontend_port = 80
backend_port = 80
disable_outbound_snat = true
frontend_ip_configuration_name = var.public_ip_name
probe_id = azurerm_lb_probe.example.id
backend_address_pool_ids = [azurerm_lb_backend_address_pool.example.id]
}
Rule Breakdown¶
| Property | Value | Description |
|---|---|---|
| name | test-rule |
Rule identifier |
| protocol | Tcp |
TCP protocol |
| frontend_port | 80 |
Port on load balancer |
| backend_port | 80 |
Port on VMs |
| disable_outbound_snat | true |
Use outbound rule instead |
| frontend_ip_configuration_name | Public IP name | Which frontend IP to use |
| probe_id | Health probe | Which probe determines health |
| backend_address_pool_ids | Backend pool | Which VMs receive traffic |
Traffic Flow¶
Client Request
↓
http://PUBLIC_IP:80
↓
Load Balancer (Frontend Port 80)
↓
[Check Health Probe]
↓
Distribute to Healthy VMs
↓
┌─────────┴─────────┐
↓ ↓
VM 0:80 VM 1:80
(if healthy) (if healthy)
Load Distribution Algorithm¶
Default: 5-tuple hash (source IP, source port, destination IP, destination port, protocol)
Result: Same client typically goes to same VM (session affinity)
Alternative: 2-tuple (source IP, destination IP) or 3-tuple (source IP, destination IP, protocol)
resource "azurerm_lb_rule" "example_rule" {
# ... other configuration ...
load_distribution = "SourceIP" # 2-tuple hash
}
Session Affinity Options¶
| Mode | Hash Tuple | Use Case |
|---|---|---|
| Default | 5-tuple | Stateless apps |
| SourceIP | 2-tuple | Session persistence |
| SourceIPProtocol | 3-tuple | Protocol-specific persistence |
Outbound Rule¶
Terraform Configuration¶
resource "azurerm_lb_outbound_rule" "example" {
name = "test-outbound"
loadbalancer_id = azurerm_lb.example.id
protocol = "Tcp"
backend_address_pool_id = azurerm_lb_backend_address_pool.example.id
frontend_ip_configuration {
name = var.public_ip_name
}
}
Purpose¶
Outbound rules enable VMs in the backend pool to access the internet using the load balancer's public IP.
Why Needed?¶
When disable_outbound_snat = true in the load balancing rule, you must explicitly configure outbound connectivity.
Outbound Traffic Flow¶
VM needs to access internet
↓
VM → Subnet → Load Balancer
↓
Load Balancer applies SNAT
(Source NAT)
↓
Outbound traffic uses Public IP
↓
Internet sees: PUBLIC_IP
SNAT Port Allocation¶
Default: 1024 ports per VM Calculation: Total ports / Number of VMs
Advanced Outbound Configuration¶
resource "azurerm_lb_outbound_rule" "example" {
name = "test-outbound"
loadbalancer_id = azurerm_lb.example.id
protocol = "All" # All, Tcp, or Udp
backend_address_pool_id = azurerm_lb_backend_address_pool.example.id
allocated_outbound_ports = 10000 # Ports per VM
idle_timeout_in_minutes = 4 # Default: 4, Max: 30
frontend_ip_configuration {
name = var.public_ip_name
}
}
Complete Load Balancer Flow¶
Inbound Request¶
1. Client → http://PUBLIC_IP
2. Load Balancer receives on port 80
3. Health probe checks VM status
4. Load balancer selects healthy VM (hash algorithm)
5. Forwards to VM:80
6. VM processes request
7. VM responds
8. Load balancer forwards response to client
Outbound Request¶
1. VM needs to access internet
2. VM sends packet to load balancer
3. Load balancer applies SNAT
4. Packet sent with Public IP as source
5. Response returns to Public IP
6. Load balancer forwards to VM
Variables¶
variable "load_balancer_name" {
type = string
default = "test-lb"
description = "Name of the Load Balancer."
}
variable "public_ip_name" {
type = string
default = "test-public-ip"
description = "Name of the Public IP."
}
Azure CLI Verification¶
Show Load Balancer¶
List Backend Pool Members¶
az network lb address-pool show \
--resource-group <resource-group-name> \
--lb-name test-lb \
--name test-pool \
--output json
Check Health Probe Status¶
az network lb probe show \
--resource-group <resource-group-name> \
--lb-name test-lb \
--name test-probe \
--output json
View Load Balancing Rules¶
az network lb rule list \
--resource-group <resource-group-name> \
--lb-name test-lb \
--output table
Test Load Balancer¶
# Get public IP
PUBLIC_IP=$(az network public-ip show \
--resource-group <resource-group-name> \
--name test-public-ip \
--query ipAddress \
--output tsv)
# Test HTTP endpoint
curl http://$PUBLIC_IP
# Test multiple times to see load distribution
for i in {1..10}; do
curl http://$PUBLIC_IP
echo ""
done
Monitoring and Troubleshooting¶
Check Backend Health¶
az network lb show \
--resource-group <resource-group-name> \
--name test-lb \
--query "backendAddressPools[0].backendIpConfigurations[*].id" \
--output table
View Metrics in Portal¶
- Navigate to Load Balancer in Azure Portal
- Click "Metrics"
- View:
- Data path availability (health probe status)
- Byte count
- Packet count
- SNAT connection count
Common Issues¶
Issue: No Response from Load Balancer¶
Causes: - Health probe failing - NSG blocking traffic - VMs not running
Debug:
# Check VM status
az vm list \
--resource-group <resource-group-name> \
--show-details \
--output table
# Check NSG rules
az network nsg rule list \
--resource-group <resource-group-name> \
--nsg-name test-nsg \
--output table
Issue: Traffic Only Goes to One VM¶
Cause: Session affinity (5-tuple hash)
Solution: Same client will typically hit same VM. Test from different IPs or change distribution mode.
Issue: SNAT Port Exhaustion¶
Symptoms: Outbound connections fail
Solution: - Increase allocated outbound ports - Add more public IPs to load balancer - Reduce idle timeout
Advanced Configurations¶
Multiple Frontend IPs¶
resource "azurerm_public_ip" "example2" {
name = "test-public-ip-2"
location = azurerm_resource_group.example.location
resource_group_name = azurerm_resource_group.example.name
allocation_method = "Static"
sku = "Standard"
}
resource "azurerm_lb" "example" {
name = var.load_balancer_name
location = azurerm_resource_group.example.location
resource_group_name = azurerm_resource_group.example.name
sku = "Standard"
frontend_ip_configuration {
name = "frontend1"
public_ip_address_id = azurerm_public_ip.example.id
}
frontend_ip_configuration {
name = "frontend2"
public_ip_address_id = azurerm_public_ip.example2.id
}
}
Internal Load Balancer¶
For internal traffic only:
resource "azurerm_lb" "internal" {
name = "internal-lb"
location = azurerm_resource_group.example.location
resource_group_name = azurerm_resource_group.example.name
sku = "Standard"
frontend_ip_configuration {
name = "internal-frontend"
subnet_id = azurerm_subnet.example.id
private_ip_address_allocation = "Dynamic"
}
}
Best Practices¶
- Use Standard SKU: Better features and SLA
- Configure Health Probes: Essential for high availability
- Monitor Metrics: Track data path availability
- Plan SNAT Ports: Avoid port exhaustion
- Use Availability Zones: For zone redundancy (requires zone-redundant public IP)
- Implement Logging: Enable diagnostic logs
- Test Failover: Verify behavior when VMs fail
Cost Considerations¶
Standard Load Balancer Pricing (East US example): - Rules: $0.025/hour per rule (~$18/month) - Data Processed: $0.005 per GB
Example Monthly Cost: - 1 rule: $18 - 100 GB data: $0.50 - Total: ~$18.50/month
Next Steps¶
Proceed to 10.6-VM-Extensions.md to learn about installing Nginx on the VMs using VM extensions.