A haproxy load balancerusing sticky sessions and optional let's encrypt ssl certificates via http-01 protocol.
Usually a load balancer has no state information for matching client's request with backend servers, the state information in the backends is stored in a shared storage as a dababase server. With this recommended approach session information is being sent to a backend or other with no particular problems.
When the backend servers are replicated but do not have all the client state information in the shared storage the previous approach will not work as expected and the user will receive responses indicated a non initated session from some of the backends.
In the case of not having the option of redesign the architecture of backends server with this proposed condfiguration the load balancer sends a backend-match cookie for being received in the next requests and used to send the requests to the same backend server.
In case you need it you might generate SSL certificates via Let's Encrypt and certbot package.
client1 client2 client3 client4 client5 client6
____ ____ ____ ____ ____ ____
| @ | | ^ | | @ | | ~ | | ^ | | ~ |
|____| |____| |____| |____| |____| |____|
/::::/ /::::/ /::::/ /::::/ /::::/ /::::/
\ | | | | /
\ | | | | /
\ | | | | /
\ | | | | /
v v v v v v
.--------------------------------------------.
| |
| load balancer |
'--------------------------------------------'
|
/|\
/ | \
/ | \
/ | \
/ | \
/ | \
/ | \
/ | \
/ | \
v v v
backend1 backend2 backend3
______ ______ ______
[.....°] [.....°] [.....°]
[.....°] [.....°] [.....°]
[|||||°] [|||||°] [|||||°]
[|||||°] [|||||°] [|||||°]
[_____°] [_____°] [_____°]
[__@__°] [__^__°] [__~__°]
[_____°] [_____°] [_____°]
Currently this role is developed for 20.04 LTS (Focal Fossa).
This role has been developed and tested with ansible 2.10.7
-
frontendshttp
: Array of dicts indicating each frontend on which the system will be listening. Valid keys:address:
address to be used forbind
keyword. Default:'*'
.port
: port forbind
directive. Default:80
.maxconn
:maconn
value. Default:'4000'
.
-
fronthttps
: Array of dicts indicating each https frontend on which the system will be listening. Valid keys:address:
address to be used forbind
keyword. Default:'*'
.port
: port forbind
directive. Default:80
.maxconn
:maconn
value. Default:'4000'
.crtdir
: CRT certificate file directory path. Default:/etc/haproxy
crtfile
: CRT certificate filename. Default:testcert.crt
.
-
certbot
: Dictionary with information for certbot. In case of not being necessary set tono
. Valid Keys:domain
: Domain to certify. Required.http01_port
: Port for http listeing (haproxy is going to proxy the challenge). Default:8888
.testcert
: Define if this is a test certificate. Default:no
.
-
backend
: Dictionary containing the backends servers info. The required keys are:name
: name for te backend. Since this system uses just a backend (composed of many servers) this name will be refered as default backend.cookie
: dictionary with information about the cookie. The valid keys are:name
: Name used for the cookie. Default:{{ ansible_fqdn }}_ha
.maxidle
: lifetime of the session when the user is inactive. As the cookie has the information for the associated server backend. If the user is active in this time window the datetime of expiry is renewed. Default:100m
.
default_server_settings
: array of dicts with the default settings for servers. Each dict has just one key-value pair. This information will be added to the settingdefault-server
askey value
.If you want to disable set this var tono
. Default values are:{ 'inter': '3s' }
{ 'fastinter': '1s' }
{ 'downinter': '10s' }
{ 'fall': '3' }
{ 'rise': '2' }
servers
: Dictionary with each backend server. Each dictionary key is the server name. From nowname
.address
: address to the server name. Example:foo.example.net
or192.168.0.1
. Default is{{ name }}
.port
: Port to the server. Default:80
.weight
: Weight directive for load balancing. Default:1
.cookie
: value used for the cookie in order to match the client with the apropiate backend server. This name will be inserted in the session cookie and will be visible for the web browser. Defaut values is going to be the first match for:- sha1sum for
{{ name }}-{{ address }}
. - sha1sum for
{{ name }}-{{ name }}
.
- sha1sum for
maxconn
: maxconn value for the server. Optional.
-
stats
: array of dictionaries containing the information about the stats section for being accessed via web. Optional. Valid keys in dictionary are:address
: address to listen. The default value is127.0.0.1
.port
: Port on which listen the admin web interface. Default value is9000
.uri
: uri on which the admin interface will be listenint. Default value is '/haproxy?stats'.realm
: Text to give for the Basic Auth dialog. DEfault value: 'Auth\ Access'.auth
: Array of dicts for the users and password valid for accessing this admin interface. The only two possible valid keys areuser
andpass
. The default value is:[ { 'user': 'fobar', 'pass': 'foopass'}, ]
.admin
: boolean indicating if the stats interfaces has admin level. Default:no
.
This role uses setup
module for getting ansible facts about Distro version and release since is expected to do portings to others targets.
#!/usr/bin/env ansible-playbook
# usually be invoqued
# ansible-playbook -i host:port, -u root haproxy-load-balancer.yml -e @file_vars.yml
---
- hosts: all
gather_facts: no
become: yes
tasks:
- include_role:
name: haproxy-sticky-load-balancer
vars:
frontendshttp:
- address: '*'
port: 80
maxconn: 4000
backend:
name: sys-backends
cookie:
name: bknsrv
maxidle: 5m
default_server_settings:
- inter: 3s
- fastinter: 1s
- downinter: 10s
- fall: 3
- rise: 2
servers:
alpha:
address: 192.168.0.103
port: 80
weight: 1
maxconn: 512
cookie: peer1
beta:
address: 192.168.0.104
cookie: peer2
stats: [{}] # default values will be used.
BSD
for -vvv info:
Matías Pecchia https://github.com/mabeett/
and many others social networks.