Learn OpenStack · core/load-balancing
Octavia Architecture
Overview
Octavia implements load balancing by provisioning dedicated virtual machines called amphorae. Each amphora runs a hardened Linux image with HAProxy managing the actual traffic. Octavia itself orchestrates the lifecycle of these VMs through four main service processes and a pluggable provider driver framework.
┌─────────────────────────────────────────────┐
│ Octavia Services │
│ │
REST API ──────►│ octavia-api │
│ │ oslo.messaging (RabbitMQ) │
│ ▼ │
│ octavia-worker ──── Nova/Neutron/Glance │
│ │
│ health-manager ◄─── UDP heartbeats │
│ │ (update DB) │
│ housekeeping ──── spare pool, cleanup │
└─────────────────────────────────────────────┘
│ management network
┌─────────┴──────────┐
│ Amphora VM │
│ (HAProxy + agent)│
└────────────────────┘
│ VIP network
Client traffic in/out
Service Processes
octavia-api
The WSGI front-end for the Octavia v2 REST API. Responsibilities:
- Validates and authenticates incoming API requests (Keystone tokens)
- Enforces policy (oslo.policy)
- Persists resource state to the Octavia database
- Publishes Taskflow jobs to octavia-worker via RabbitMQ cast
- Returns
202 Acceptedfor asynchronous operations; the caller must poll untilprovisioning_statusreachesACTIVEorERROR
The API is versioned at /v2/lbaas/. The OpenStack SDK and python-openstackclient wrap this endpoint.
octavia-worker
Executes the actual lifecycle operations on amphorae and HAProxy. Responsibilities:
- Subscribes to the RabbitMQ task queue
- Runs Taskflow linear flows for each operation (create LB, create listener, failover, etc.)
- Calls the Nova API to boot/delete amphora VMs
- Calls the Neutron API to allocate VIP ports and management ports
- Connects to the amphora REST agent over the management network (HTTPS) to configure HAProxy
- Updates
provisioning_statusin the database as tasks complete or fail
Multiple octavia-worker processes can run for horizontal scaling. Each picks up jobs from the shared queue.
health-manager
Monitors the liveness of all running amphorae. Responsibilities:
- Listens on a UDP port on the management network for heartbeat packets from amphorae
- Each amphora sends a UDP heartbeat every
heartbeat_intervalseconds (default 10 s) containing its current status and statistics - health-manager updates the database with per-listener and per-member operational status
- If no heartbeat is received within
heartbeat_timeoutseconds (default 60 s), health-manager marks the amphora asERRORand triggers an automatic failover - health-manager is stateless; multiple instances can run behind a load balancer for HA, but each amphora's heartbeats are sticky to one instance (consistent hashing on amphora UUID)
housekeeping
Performs periodic maintenance tasks. Responsibilities:
- Spare pool management: pre-creates amphora VMs in the
READYstate so that new load balancer requests can be served quickly without waiting for Nova to boot a fresh VM - Expired amphora cleanup: deletes amphorae that are in
DELETEDstate and older thandelete_amphora_later_secseconds - Certificate rotation: rotates the client/server TLS certificates used between octavia-worker and the amphora REST agent before they expire
- Expired flow cleanup: removes stale Taskflow database entries
Amphora Design
Each amphora is a Nova VM running a purpose-built image built with diskimage-builder using the amphora-image element. Inside the VM:
Amphora VM
├── amphora-agent (Python REST API on port 9443 over TLS)
│ ├── Accepts HTTPS calls from octavia-worker
│ ├── Writes HAProxy config files
│ ├── Manages HAProxy process lifecycle
│ └── Sends UDP heartbeat to health-manager
├── HAProxy (actual packet forwarder)
│ ├── One HAProxy process per load balancer (listener namespace)
│ └── Config written to /var/lib/octavia/<lb-uuid>/haproxy.cfg
└── keepalived (VRRP for active-standby HA pairs)
Network Interfaces
Each amphora has two network interfaces:
| Interface | Purpose | Connected To |
|---|---|---|
eth0 (management) |
Communication with octavia-worker and health-manager; amphora REST agent and UDP heartbeat | Octavia management network (operator-managed, not tenant) |
eth1 (VIP / tenant) |
Carries load-balanced traffic; HAProxy binds listeners here | Neutron VIP port on the tenant subnet |
For active-standby HA amphorae a third interface (eth2) may carry the VRRP peer link.
Management Network
The management network is a dedicated Neutron network created by the operator during Octavia deployment. It is not exposed to tenants. The octavia-worker and health-manager connect to amphorae exclusively via this network using:
- HTTPS (TCP 9443): octavia-worker → amphora REST agent (mutual TLS; certs rotated by housekeeping)
- UDP heartbeat (configurable port, default 5555): amphora → health-manager
The management network should use a separate physical interface or a dedicated VLAN to ensure that health-check traffic is isolated from tenant data.
Active-Standby HA
When --vip-subnet-id is combined with an HA topology (the default SINGLE topology can be overridden to ACTIVE_STANDBY):
- Two amphora VMs are provisioned
- keepalived runs VRRP inside both amphorae
- The active amphora holds the VIP; the standby monitors it
- If the active amphora fails, the standby takes the VIP within the VRRP
advert_intinterval (default 1 s) - health-manager also triggers a full amphora failover if heartbeat is lost
Active-Active HA
When topology is ACTIVE_ACTIVE (requires OVN-Octavia or newer octavia-driver-lib support):
- Multiple active amphorae share traffic via the VIP
- Requires a provider driver that supports it (e.g., the OVN provider)
- The amphora provider implements active-active via conntrack sync and ECMP
Provider Driver Framework
Octavia decouples the API surface from the back-end implementation through a provider driver interface (octavia_lib.api.drivers). Operators can register multiple providers and users can choose which one to use when creating a load balancer.
Amphora Provider (default)
- Ships with Octavia
- Provisions a full HAProxy VM per load balancer
- Supports all LBaaS features: HTTP/HTTPS/TCP/UDP listeners, L7 policies, health monitors, TLS termination, connection limits
- Best for production workloads requiring full feature parity
OVN Provider
- Implemented in the
ovn-octavia-providerproject - Delegates load balancing to OVN's native load balancer (kernel-space conntrack DNAT)
- No amphora VMs are created; lower overhead
- Limitations: no L7 policies, no TLS termination, no UDP health monitors, limited algorithm support
- Best for lightweight internal TCP/HTTP load balancing in deployments already using ML2/OVN
Registering Providers
# /etc/octavia/octavia.conf
[api_settings]
enabled_provider_drivers = amphora:The Octavia Amphora driver.,ovn:OVN provider driver.
default_provider_driver = amphora
List available providers:
openstack loadbalancer provider list
Specify at creation time:
openstack loadbalancer create \
--name ovn-lb \
--vip-subnet-id private-subnet \
--provider ovn
Spare Pool
The spare pool keeps pre-booted amphora VMs warm so that new load balancer creation is fast (seconds rather than minutes). housekeeping continuously replenishes it.
[house_keeping]
spare_amphora_pool_size = 2 # number of warm spare amphorae to maintain
When a load balancer is created, octavia-worker first tries to claim a spare amphora. If no spare is available, it falls back to booting a new Nova VM. After an amphora is deleted, housekeeping eventually creates a replacement spare.
Anti-Affinity and Placement
For active-standby HA load balancers, Octavia uses Nova server groups with anti-affinity to place the two amphora VMs on different compute nodes. This is controlled by:
[nova]
enable_anti_affinity = True
anti_affinity_policy = anti-affinity # or soft-anti-affinity
When enable_anti_affinity = True, Octavia creates a Nova server group for each HA pair and passes scheduler_hints when booting each amphora so the scheduler places them on distinct hypervisors.
Flavors and Flavor Profiles
Octavia flavors allow operators to offer different load balancer tiers (e.g., small/medium/large) with different amphora Nova flavors, topologies, or provider drivers.
Flavor Profile
└── defines: compute_flavor (Nova flavor ID), amp_topology (SINGLE/ACTIVE_STANDBY),
loadbalancer_topology, provider_name
Flavor
└── references: a FlavorProfile
└── exposed to: tenants (via loadbalancer create --flavor)
# Create a flavor profile using a larger Nova flavor
openstack loadbalancer flavorprofile create \
--name large-profile \
--provider amphora \
--flavor-data '{"compute_flavor": "m1.large", "loadbalancer_topology": "ACTIVE_STANDBY"}'
# Create a user-facing flavor
openstack loadbalancer flavor create \
--name large \
--flavorprofile large-profile \
--description "HA load balancer on m1.large"
# Use the flavor
openstack loadbalancer create \
--name ha-lb \
--vip-subnet-id private-subnet \
--flavor large
Database Schema Overview
Octavia maintains its own database (separate from Neutron). Key tables:
| Table | Contents |
|---|---|
load_balancer |
VIP address, subnet, project, provisioning_status, operating_status |
listener |
Protocol, port, connection_limit, default_pool, TLS ref |
pool |
Algorithm, protocol, health_monitor ref |
member |
Address, protocol_port, weight, backup, operating_status |
health_monitor |
Type, delay, timeout, max_retries, HTTP path/codes |
amphora |
Nova instance ID, management IP, status, role (MASTER/BACKUP/STANDALONE) |
l7policy / l7rule |
L7 redirect and content-routing rules |
Operating Status vs Provisioning Status
Octavia resources carry two independent status fields:
| Field | Meaning | Values |
|---|---|---|
provisioning_status |
Control-plane operation state | ACTIVE, PENDING_CREATE, PENDING_UPDATE, PENDING_DELETE, DELETED, ERROR |
operating_status |
Data-plane health | ONLINE, DRAINING, OFFLINE, DEGRADED, ERROR, NO_MONITOR |
A load balancer is healthy when provisioning_status=ACTIVE and operating_status=ONLINE. A member shows ONLINE only when the health monitor confirms it is passing checks.