Paginas

12 July 2020

VMware Horizon with HAProxy Cluster LoadBalancer



It's been a while and since I had this post in draft for a long time I finally decided to finish it and publish it. What I'm going to show you is how to make a HAProxy Cluster for VMware Horizon connections with Load Balancing (LB) for two or more active VMware Horizon Connection Servers.
This LB Cluster solution is free (Linux environments) and can be used for other solutions that do not use the same ports (in this case 80, 443 and 8443). In turn, Connection Servers communicate with vCenter to redirect users to the correct VDI Pools after Active Directory authentication.
Let's see how to configure HAProxy redundantly using two CentOS 7 servers.


The general diagram of a possible redundant architecture is as follows:


Note: We could also have the Security/Gateway Server redundant with another HAProxy cluster in the DMZ.

The internal access architecture:
  • Internal DNS points to the VIP IP of the HAProxy cluster where clients connect via Horizon Client or Web Browser;
  • HAProxy cluster with two active-passive nodes that receive requests and redirect them to Connection Servers;
  • Two Horizon connection servers in active-active mode that receive HAProxy requests and forward them to the respective VDI Pools;
  • Connection servers communicate with vCenter for the VDI management and with Active Directory for authentication;
  • The Horizon database is located on an external server in SQL Server;
  • File Persona was also configured to store the profiles of VDI users (very important if you have  VDI floating pools);
  • The Horizon Composer component is also located on an external server to manage pools of desktops that share a common virtual disk;
  • The vCenter and the database can also be redundant with the features of vCenter High availability and SQL Always-On respectively.

The external access architecture:
  • External DNS points to the Public IP and NAT in the Firewall for the Security/Gateway Server. It is necessary to open port 443 (Browser access) and 8443 (Blast) in the Firewall. You may also use port 4172 UDP/TCP for PCoIP;
  • Public certificate with the same name as horizon.domain.local that points to the Public IP address;
  • In order to have full redundancy we could have the Security/Gateway Server redundant with another HAProxy cluster in the DMZ that would receive external requests;
  • Security/Gateway server forward requests to the internal Connection Servers
    • Note that in older architectures it was only possible to connect Security/Gateway Server to one of the Connection Servers. At this moment, we can also have redundancy in this aspect.

For Firewall configurations, all Horizon communications are described in the following image (nice picture to print):

Cluster configurations in active-passive mode:

Active Node:

Add the repo:
rpm -ivh http://download.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm
Install binaries:
yum -y install haproxy keepalived
Edit keepalived file and change configurations for the Cluster Active node:
# vi /etc/keepalived/keepalived.conf
global_defs {
   notification_email {
     name@domain.xxx
   }
   notification_email_from HAPROXY_01@domain.xxx
   smtp_server X.X.X.X # IP of STMP Server with relay permissions
   smtp_connect_timeout 30
   router_id X.X.X.X # IP of the VIP Address
}
vrrp_script chk_haproxy {
script "killall -0 haproxy"
interval 1
weight 2
}
vrrp_instance VI_1 {  # Name of the Cluster Instance
    state MASTER
    interface ens192 # name of the interface
    virtual_router_id 51 # ID of the Cluster
    priority 101 # Master with Higher priority
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass XXXXXX # same password in all nodes
    }
    virtual_ipaddress {
        X.X.X.X # IP of the VIP Address
    }
track_script {
chk_haproxy
}
}
Check VIP Address:
ip addr sh ens192
Start keepalived Auto:
chkconfig keepalived on

Passive/Backup Node:

Add the repo:
rpm -ivh http://download.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm
Install binaries:
yum -y install haproxy keepalived
Edit keepalived file and change configurations for the Cluster Active node:
# vi /etc/keepalived/keepalived.conf
global_defs {
   notification_email {
     name@domain.xxx
   }
   notification_email_from HAPROXY_02@domain.xxx
   smtp_server X.X.X.X # IP of STMP Server with relay permissions
   smtp_connect_timeout 30
   router_id X.X.X.X # IP of the VIP Address
}
vrrp_script chk_haproxy {
script "killall -0 haproxy"
interval 1
weight 2
}
vrrp_instance VI_1 {  # Name of the Cluster Instance
    state BACKUP
    interface ens192 # name of the interface
    virtual_router_id 51 # ID of the Cluster
    priority 60 # Backup with Lower priority
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass XXXXXX # same password in all nodes
    }
    virtual_ipaddress {
        X.X.X.X # IP of the VIP Address
    }
track_script {
chk_haproxy
}
}
Start keepalived Auto:
chkconfig keepalived on


HAProxy configurations for each Node:


Firewall:

Install binaries:
yum install iptables-services
Configure IPTables and Services
systemctl enable iptables
# vi /etc/sysctl.conf:
net.ipv4.ip_nonlocal_bind = 1
# Run the command:
sysctl -p
# Add Multicat in IPTables
iptables -I INPUT -d 224.0.0.0/8 -j ACCEPT

# Add protocol VRRP in IPTables iptables -I INPUT -p 112 -j ACCEPT

# Add Horizon ports in IPTables iptables -I INPUT -p tcp --dport 80 -j ACCEPT iptables -I INPUT -p tcp --dport 443 -j ACCEPT iptables -I INPUT -p tcp --dport 8443 -j ACCEPT
# Add Horizon status ports in IPTables
iptables -I INPUT -p tcp --dport 9000 -j ACCEPT
# disable firewalld if installed
systemctl disable firewalld
# save configurations
service iptables save
# start keepalived services
service keepalived start
systemctl enable keepalived

HAProxy:

Edit haproxy file and change configurations:
# vi /etc/haproxy/haproxy.cfg
#-----------------
# Global settings
#-----------------
global
    log         127.0.0.1 local2
    chroot      /var/lib/haproxy
    pidfile     /var/run/haproxy.pid
    maxconn     4000
    user        haproxy
    group       haproxy
    daemon
# turn on stats unix socket
stats socket /var/lib/haproxy/stats
defaults
    mode                    http
    log                     global
    option                  httplog
    option                  dontlognull
    option http-server-close
    option forwardfor       except 127.0.0.0/8
    option                  redispatch
    retries                 3
    timeout http-request    10s
    timeout queue           1m
    timeout connect         10s
    timeout client          1m
    timeout server          1m
    timeout http-keep-alive 10s
    timeout check           10s
    maxconn                 3000
# ------
# STATS
# ------
listen stats
    bind 0.0.0.0:9000 ssl crt /etc/haproxy/cert.pem  # the certificate of horizon.domain.XXX
    mode http
    balance
    timeout client 5000
    timeout connect 4000
    timeout server 30000
    #This is the virtual URL to access the stats page
    stats uri /stats
    #Authentication realm. This can be set to anything. Escape space characters with a backslash.
    stats realm HAProxy\ Statistics
    #The user/pass you want to use. Change this password!
 stats auth admin:PASSWORD_STATS
    #This will produce an error on older versions of HAProxy.
 stats admin if TRUE

# ---------
# FRONTENDS
# ---------
# Redirect to HTTPS
frontend unsecured     bind VIP_ADDRESS:80     redirect location https://horizon.domain.XXX
# Frontend HTTPS
frontend secured
    bind VIP_ADDRESS:443 ssl crt /etc/haproxy/cert.pem  # the certificate of horizon.domain.XXX
    mode tcp
    default_backend view
frontend blast
    bind VIP_ADDRESS:8443 ssl crt /etc/haproxy/cert.pem  # the certificate of horizon.domain.XXX
    mode tcp
    default_backend blast
#----------------------------------------------
# balancing between the various backends HTTPS
#----------------------------------------------
backend view
    mode tcp
    balance source
    server  NAME_CONNEC_SERVER_01 IP_CONNEC_01:443 weight 1 check port 443 inter 2000 rise 2 fall 5
    server  NAME_CONNEC_SERVER_02 IP_CONNEC_02:443 weight 1 check port 443 inter 2000 rise 2 fall 5
#----------------------------------------------
# balancing between the various backends BLAST
#----------------------------------------------
backend blast
    mode tcp
    balance source
    server  NAME_CONNEC_SERVER_01 IP_CONNEC_01:8443 weight 1 check port 8443 inter 2000 rise 2 fall 5
    server  NAME_CONNEC_SERVER_02 IP_CONNEC_02:8443 weight 1 check port 8443 inter 2000 rise 2 fall 5

Start HAProxy Auto:
service haproxy start
chkconfig haproxy on
Check keepalived:
journalctl -u keepalived
Check stats:
https://VIP_ADDRESS:9000/stats (enter the credentials that are in the haproxy configuration file)

To convert your certificates into PEM file you can use this useful link:

Note: Only use certificates on HAProxy if you want to offload them from Connection Servers.
Otherwise and if certificates are used on connection servers, put only "bind VIP_ADDRESS:443" or "bind VIP_ADDRESS:8443" without reference to certificates. You should use the certificate for the STATS service is both circunstances.


After having the entire VMware Horizon infrastructure configured, you can test access via HAProxy. To test the redundancies, you can disconnect one of the nodes and check that the keeapalived and the VIP will move to the remaining node. When the master node is operational again, services automatically move to the master node again because it has a higher priority.
I hope it was enlightening and if you have any questions, please comment!
See you next time! Hopefully not next year.

No comments:

Post a Comment