vr_balancing - OpenNebula/one-apps GitHub Wiki
The virtual router provides to open source solutions for load balancing TCP services:
- Keepalived + LVS (IPVS).
- HAProxy.
In this guide we will assume the following configuration:
public network
ββββββββββββββββ Users
β
ββββ΄ββ 10.0.1.1
ββββ€eth0ββββββββββ
β ββββββ β LB service (http:80)
β Virtual Router β
β β 10.0.1.1:80 ββββββΊ 172.20.0.104:8080
β Load Balancer β β
β ββββββ β ββββββΊ 172.20.0.105:8080
ββββ€eth1ββββββββββ
βββ¬βββ
β private network
ββββββ¬ββββββββββββββββββ¬βββ
172.20.0.104 172.20.0.105
ββββ΄βββ ββββ΄βββ
β LB1 β β LB2 β
βββββββ βββββββ
Note
The Load Balancing service can be provisioned in a failover setup activating the associated keepalived services, see more details here
Additionally we will consider two LB deployment modes:
- Static, when the number LB servers are fixed and known
- Dynamic, when LB servers can be added/removed from the backend
To configure the LB services you need to define the public (user-facing) IP. This IP is only known once the Virtual Router is deployed and the IP assignment is resolved. Usually, you can refer to the public facing IP of the Virtual router as ETH0_EP0
For advanced scenarios, OpenNebula provides you with some convenient placeholders that are resolved automatically at runtime:
-
<ETHx_IPy>
means "interpolate (in-place) the y-th IP of the x-th NIC" -
<ETHx_VIPy>
means "interpolate (in-place) the y-th Virtual IP of the x-th NIC" -
<ETHx_EPy>
means "interpolate (in-place) the y-th EndPoint of the x-th NIC"
Values of ETHx_IPy
and ETHx_VIPy
are always merged together to produce ETHx_EPy
. When ETHx_VIPy
is undefined, then ETHx_EPy
is always set to ETHx_IPy
as a fallback, that way you can always have some valid "endpoints" even in non-HA scenarios (no VIPs defined).
Note
Virtual IP refers to the IP assigned to the NIC of the virtual router when FLOATING_IP
has been set.
To configure keepalived LVS you need to define:
- The front-end IP and port to expose the service
ONEAPP_VNF_LBx_IP
,ONEAPP_VNF_LBx_PORT
- The IP and port of the backend severs
ONEAPP_VNF_LBx_SERVERy_HOST
,ONEAPP_VNF_LBx_SERVERy_PORT
set at deployment time - The protocol and mode where keepalive will use to load balance the services (e.g.
ONEAPP_VNF_LBx_PROTOCOL
)
Note
Each variable is indexed for each balanced service LB0, LB1, etc.. and each backend server is indexed as well with SERVER0, SERVER1,.. etc..
For example, to create a static LVS-based TCP LB, for the topology above, you can use:
CONTEXT = [
...
ONEAPP_VNF_LB_ENABLED = "YES",
ONEAPP_VNF_LB0_IP = "<ETH0_EP0>", # Interpolate the first "endpoint".
ONEAPP_VNF_LB0_PORT = "80",
ONEAPP_VNF_LB0_PROTOCOL = "TCP",
ONEAPP_VNF_LB0_METHOD = "NAT",
ONEAPP_VNF_LB0_SCHEDULER = "rr", # "Round-robin".
# Static backends:
ONEAPP_VNF_LB0_SERVER0_HOST = "172.20.0.104",
ONEAPP_VNF_LB0_SERVER0_PORT = "8080",
ONEAPP_VNF_LB0_SERVER1_HOST = "172.20.0.105",
ONEAPP_VNF_LB0_SERVER1_PORT = "8080",
...
]
You can see in the example above, that we defined the LB0 by providing the IP
/ PORT
pair with some extra settings. Then two (static) backends are defined for the LB0.
Similarly for HAProxy you need to define:
- The front-end IP and port to expose the service
ONEAPP_VNF_HAPROXY_LBx_IP
,ONEAPP_VNF_HAPROXY_LBx_PORT
- The IP and port of the backend severs
ONEAPP_VNF_HAPROXY_LBx_SERVERy_HOST
,ONEAPP_VNF_HAPROXY_LBx_SERVERy_PORT
For example, to create a HAProxy-based TCP LB for the topology above, you can use:
CONTEXT = [
...
ONEAPP_VNF_HAPROXY_ENABLED = "YES",
ONEAPP_VNF_HAPROXY_LB0_IP = "<ETH0_EP0>", # Interpolate the first "endpoint".
ONEAPP_VNF_HAPROXY_LB0_PORT = "80",
# Static backends:
ONEAPP_VNF_HAPROXY_LB0_SERVER0_HOST = "172.20.0.104",
ONEAPP_VNF_HAPROXY_LB0_SERVER0_PORT = "8080",
ONEAPP_VNF_HAPROXY_LB0_SERVER1_HOST = "172.20.0.105",
ONEAPP_VNF_HAPROXY_LB0_SERVER1_PORT = "8080",
...
]
Important
To dynamically add and remove LBs the Virutal Router cannot be instantiated as an standalone VM. It has to be an OpenNebula Virtual Router or part of an OpenNebula flow.
Important
To dynamically add and remove LBs the OpenNebula Gate service needs to be configured.
The procedure is as follows:
- Add
ONEAPP_VNF_LB_ONEGATE_ENABLED="YES"
orONEAPP_VNF_HAPROXY_ONEGATE_ENABLED="YES"
to the Virtual Router context, to set one or both LBs in the dynamic mode. - Create a new Virtual Machine that includes
BACKEND = YES
in itsCONTEXT
attribute (not required in OneFlow). - Update the VM to include the IP/HOST, and PORT pairs with the target IP
Let's assume you already have deployed a Virtual Router in static mode with backends 172.20.0.104 and 172.20.0.105, as described above. To add a new backend. Create a new Virtual Machine, for example you could use the following template:
NAME = MyBackend
...
NIC = [ NETWORK = "private" ]
# The ONEGATE_* values below are created inside the "User Template" of the backend VM.
ONEGATE_LB0_IP = "<ETH0_EP0>"
ONEGATE_LB0_PORT = 80
CONTEXT = [
...
NETWORK = YES,
SSH_PUBLIC_KEY = "$USER[SSH_KEY]",
BACKEND = YES, # NOTE: This isn't required when running inside OneFlow.
...
]
Once the VM is created look for the assigned IP in the private
network (for example let's assume it is 172.20.0.133) and update the user template contents with the IP/PORT pairs (e.g. onevm update
):
ONEGATE_LB0_SERVER_HOST = "172.20.0.133"
ONEGATE_LB0_SERVER_PORT = 8080
Note
Dynamic variable ONEGATE_LB0_SERVER_HOST
does not contain the server index, this is different from the static definition ONEAPP_VNF_LB0_SERVER0_HOST
.
Important
The LB's ONEGATE_LBx_IP
/ ONEGATE_LBx_PORT
pair in the VM template must match those of a statically defined Virtual Router. If this is not the case, then no change will be produced.
Equivalently you'll need to create a VM that includes the following attributes in its template:
NAME = MyBackend
...
NIC = [ NETWORK = "private" ]
# The ONEGATE_* values below are created inside the "User Template" of the backend VM.
ONEGATE_HAPROXY_LB0_IP = "<ETH0_EP0>"
ONEGATE_HAPROXY_LB0_PORT = 80
CONTEXT = [
...
NETWORK = YES,
SSH_PUBLIC_KEY = "$USER[SSH_KEY]",
BACKEND = YES, # NOTE: This isn't required when running inside OneFlow.
TOKEN = YES
...
]
And then update it with the target IP/PORT pairs (e.g. onevm update
):
ONEGATE_HAPROXY_LB0_SERVER_HOST = "172.20.0.133"
ONEGATE_HAPROXY_LB0_SERVER_PORT = 8080
This can be added as a start script on the VM template, so the VM is configured on instantiation:
onegate vm update --data "ONEGATE_HAPROXY_LB0_SERVER_HOST=\"$ETH0_IP\""
onegate vm update --data "ONEGATE_HAPROXY_LB0_SERVER_PORT=\"8080\""
The Virtual Router appliance can deployed in three different ways:
- As a proper OpenNebula Virtual Router instance.
- As a standalone VM, but inside an OneFlow service instance.
- As a standalone VM. (not supported)
When running both types of LBs (static and dynamic) in modes 1. and 2. the context and OneGate interface is exactly the same (with the important caveat, that the mode 1. requires backends to have the CONTEXT = [..., BACKEND = "YES", ...]
flag defined).
Under the hood the source of updates is different, it both cases OneGate is used, but in the mode 1. all VNETs attached to the VR are scanned (recursively), in the mode 2. OneFlow provides API responses.
In that sense mode 1. is superior to mode 2., because a "proper" VR can reverse-proxy to any VMs in its attached VNETs (also to VMs running in OneFlow instances), at the same time mode 2. allows for backends from within its OneFlow instance only.
Parameter | Default | Description |
---|---|---|
ONEAPP_VNF_LB_ENABLED |
NO |
Enable/Disable LB feature (YES/NO ) |
ONEAPP_VNF_LB_ONEGATE_ENABLED |
NO |
Enable/Disable dynamic real servers via OneGate (YES/NO ) |
ONEAPP_VNF_LB_INTERFACES |
all NICs | List of NICs to listen on (<[!]ethX> ... ) |
ONEAPP_VNF_LB_REFRESH_RATE |
30 |
Refresh rate between updates of the pool of real servers (seconds ) |
ONEAPP_VNF_LB_FWMARK_OFFSET |
10000 |
Default starting firewall mark for LVS/IPVS |
ONEAPP_VNF_LB[0-9]_IP |
none | Mandatory: Load balanced IP address |
ONEAPP_VNF_LB[0-9]_PORT |
none | Optional: IP port to specify connection |
ONEAPP_VNF_LB[0-9]_PROTOCOL |
UDP |
IP protocol to specify connection (TCP or UDP ) |
ONEAPP_VNF_LB[0-9]_METHOD |
NAT |
LVS/IPVS method (NAT or DR ) |
ONEAPP_VNF_LB[0-9]_SCHEDULER |
wlc |
LVS/IPVS scheduler |
ONEAPP_VNF_LB[0-9]_SERVER[0-9]_HOST |
none | Real server address (IP or hostname ) |
ONEAPP_VNF_LB[0-9]_SERVER[0-9]_PORT |
none | Optional: Real server port |
ONEAPP_VNF_LB[0-9]_SERVER[0-9]_WEIGHT |
1 |
Real server weight |
ONEAPP_VNF_LB[0-9]_SERVER[0-9]_ULIMIT |
0 (disabled) |
Real server upper limit on connections |
ONEAPP_VNF_LB[0-9]_SERVER[0-9]_LLIMIT |
0 (disabled) |
Real server lower limit on connections |
ONEGATE_LB[0-9]_IP |
none | Mandatory: The load balanced IP address |
ONEGATE_LB[0-9]_PORT |
none | Mandatory: The load balanced IP port |
ONEGATE_LB[0-9]_SERVER_HOST |
none | Real server address (IP or hostname ) |
ONEGATE_LB[0-9]_SERVER_PORT |
none | Real server port |
ONEGATE_LB[0-9]_SERVER_WEIGHT |
1 |
Real server weight |
ONEGATE_LB[0-9]_SERVER_ULIMIT |
0 (disabled) |
Real server upper limit on connections |
ONEGATE_LB[0-9]_SERVER_LLIMIT |
0 (disabled) |
Real server lower limit on connections |
Warning
In the static scenario parameters ONEAPP_VNF_LB[0-9]_PORT
and ONEAPP_VNF_LB[0-9]_SERVER[0-9]_PORT
are optional, when undefined, LVS assumes all ports have to be forwarded. In result a mapping similar to SDNAT4
is created, the differences are that (unlike SDNAT4
) it's unidirectional and load-balanced. Since LVS takes precedence over ports opened in the VR, you may lose SSH access to your VR instance when misconfigured.
Parameter | Default | Description |
---|---|---|
ONEAPP_VNF_HAPROXY_ENABLED |
NO |
Enable/Disable HAProxy feature (YES/NO ) |
ONEAPP_VNF_HAPROXY_ONEGATE_ENABLED |
NO |
Enable/Disable dynamic backends via OneGate (YES/NO ) |
ONEAPP_VNF_HAPROXY_INTERFACES |
all NICs | List of NICs to listen on (<[!]ethX> ... ) |
ONEAPP_VNF_HAPROXY_REFRESH_RATE |
30 |
Refresh rate between updates of the pool of backends (seconds ) |
ONEAPP_VNF_HAPROXY_LB[0-9]_IP |
none | Mandatory: Load balanced IP address |
ONEAPP_VNF_HAPROXY_LB[0-9]_PORT |
none | Mandatory: IP port to specify connection |
ONEAPP_VNF_HAPROXY_LB[0-9]_SERVER[0-9]_HOST |
none | Backend address (IP or hostname ) |
ONEAPP_VNF_HAPROXY_LB[0-9]_SERVER[0-9]_PORT |
none | Backend port |
ONEGATE_HAPROXY_LB[0-9]_IP |
none | Mandatory: The load balanced IP address |
ONEGATE_HAPROXY_LB[0-9]_PORT |
none | Mandatory: The load balanced IP port |
ONEGATE_HAPROXY_LB[0-9]_SERVER_HOST |
none | Backend address (IP or hostname ) |
ONEGATE_HAPROXY_LB[0-9]_SERVER_PORT |
none | Backend port |