2

I would like to create a redundant HAProxy configuration with:

  • Keepalived - for determining which HA Proxy is active
  • HAProxy - for doing load balancing and failover

I will be using a cloud service provider and their VPSs

  • Each VPS has its own, public IP address
  • The provider has a “failover IP” that can be purchased

The issue I’ve encountered previously with using VRRP on a service level (as opposed to just a Layer 3 technology), is that the destination and reply IP addresses are different. For example, when I considered only using Keepalived for load-balancing and failover, I encountered the problem:

  • Clients would make a connection to the servers using the virtual failover IP
  • Responses from the server would be sent from the server’s physical IP address, and not from the virtual failover IP
  • The destination and response IP addresses would not match

Load-balancers, like HA Proxy, deal with this problem to an extent, by essentially NATing the traffic, such that the traffic from the servers appear to be sent to/from the Load-balancer’s IP address.

  • Instead of replies originating from the server’s physical IP address, the replies are NATed to the load-balancer’s IP address

However, I foresee the same problem, if I try to use a virtual failover IP with a pair of HA Proxys running keepalived. That is,

  • Traffic would be sent to the Virtual IP as the destination IP
  • Traffic response would be sent from the HA Proxy’s IP address, not from the Virtual IP

Does HA Proxy have a solution to this? Can I configure HA Proxy to reply with the virtual IP?

GeekGeek4
  • 21
  • 1
  • 2

1 Answers1

2

To keep the reply address consistent with the source address, configure your haproxy frontends to bind to the VIP.

For example, assume we have two haproxy servers:

  • 192.168.122.170
  • 192.168.122.91

We have a vip address:

  • 192.168.122.201

And we have a backend server:

  • 192.168.122.24

Our haproxy configuration might look like this:

frontend main
    bind 192.168.122.201:80
    default_backend             app

backend app
    balance roundrobin
    server app1 192.168.122.24:80 check

Look at the bind statement in the frontend section there: rather than binding to the wildcard address (bind *:80), we're binding specifically to the VIP address.

Now, you might be wondering: isn't that going to result in an error when haproxy starts up on the node that doesn't currently own the VIP? You might expect to see something like:

[ALERT]    (6559) : Starting frontend main: cannot bind socket (Cannot
assign requested address) [192.168.122.201:80]

Normally, you would be correct! But in this case, we're going to set the net.ipv4.ip_nonlocal_bind sysctl to 1:

sysctl -w net.ipv4.ip_nonlocal_bind=1

This allows software to bind to addresses that aren't currently available on the host. With this configuration in place, if we make a request to the VIP, we see the requests return from the VIP as well.

For example, if I make a request to 192.168.122.201 from a host on the 172.17.0.0/16 network, a tcpdump shows:

... 172.17.0.2.58250 > 192.168.122.201.http: Flags [S], ...
... 192.168.122.201.http > 172.17.0.2.58250: Flags [S.], ...
... 172.17.0.2.58250 > 192.168.122.201.http: Flags [.], ...
... 172.17.0.2.58250 > 192.168.122.201.http: Flags [P.], ...
... 192.168.122.201.http > 172.17.0.2.58250: Flags [P.], ...
... 172.17.0.2.58250 > 192.168.122.201.http: Flags [.], ...
... 192.168.122.201.http > 172.17.0.2.58250: Flags [F.], ...
... 172.17.0.2.58250 > 192.168.122.201.http: Flags [F.], ...
... 192.168.122.201.http > 172.17.0.2.58250: Flags [.], ...

You can find all the files I used to test this configuration here.

larsks
  • 43,623
  • 14
  • 121
  • 180