VMware Horizon/AppVolumes Load Balancer con HAProxy y Keepalived sobre PhotonOS

En el post de hoy veremos cómo podemos balancear y dotar de alta disponibilidad a nuestros servidores de conexión de VMware Horizon y a nuestros AppVolumes Managers.

Para que mentalmente os podais hacer una idea de lo que vamos a hacer, os dejo con el siguiente esquema:

Horizon8-architecture-design

En él, podeis ver cómo añadiremos 2 nuevos servidores a nuestra infraestructura e instalaremos HAProxy + Keepalive en ellos.

Utilizaremos PhotonOS 3.0 revision3 para montar los servidores. PhotonOS es una versión optimizada para entornos vSphere con unos recursos mínimos. Podremos descargar la OVA with virtual hardware v13 (UEFI Secure Boot) desde aquí

Despiegue Photon OS

El despliegue de la OVA es muy sencillo y solo tendremos que seguir el asistente del propio vCenter

haproxy-00 haproxy-01 haproxy-02 haproxy-03 haproxy-04 haproxy-05 haproxy-06 haproxy-07 haproxy-08 haproxy-09 haproxy-10 haproxy-11 haproxy-12 haproxy-13 haproxy-14 haproxy-15

Configuración inicial

Por defecto, la ova de PhotonOS está configurada para coger IP por DHCP y SSH está habilitado en el arranque.

Nos conectaremos por SSH a la IP que nos ha proporcionado y accederemos con las credenciales por defecto (admin/changeme). La primera vez que hagamos login nos pedirá cambiar la contraseña.

changeme

Una vez tengamos desplegadas las 2 VMs haremos una pequeña configuración inicial para empezar.

  • Actualizamos el SO
1
tdnf upgrade -y
  • Configurar IP estática Por defecto, el fichero de configuración de IP se encuentra en /etc/systemd/network/99-dhcp-en.network

Con nuestro editor de textos preferido (vim, por ejemplo), deshabilitaremos DHCP

1
2
3
4
[Match]
Name=e*
[Network]
DHCP=no

Crearemos un nuevo fichero de configuración con la siguiente configuración y lo llamaremos /etc/systemd/network/10-static-en.network

1
2
3
4
5
6
7
8
9
[Match]

Name=eth0
[Network]
Address=192.168.6.120/24
Gateway=192.168.6.1
DNS=192.168.6.100
[DHCP]
UseDNS=false

NOTA: Pondremos la IP correspondiente a cada uno de los servidores

  • Cambiaremos el propietario del fichero con el siguiente comando:
1
chown systemd-network:systemd-network /etc/systemd/network/10-static-en.network

Para poder usar las VIP en ambos nodos de Keepalive y HAProxy, será necesario realizar ciertos cambios para permitir el reenvio a nivel IP y permitir que ambos servicios usen una IP que no está definida en la interfaz física de la VM.

Por defecto, PhotonOS tiene este comportamiento deshabilitado y lo podremos habilitar de la siguiente manera:

  • Creamos y editamos el fichero de configuración /etc/sysctl.d/55-keepalived.conf
1
2
3
4
#Enable IPv4 Forwarding
net.ipv4.ip_forward = 1
#Enable non-local IP bind
net.ipv4.ip_nonlocal_bind = 1

NOTA: Fijaros que en la misma carpeta, está un fichero llamado 50-security-hardening.conf. Al usar nosotros un numero superior en el fichero creado, es posible que se sobreescriban algunas configuraciones definidas por defecto.

Finalmente, necesitaremos configurar iptables para permitir el acceso http/https. /etc/systemd/scripts/ip4save

NOTA: Añadiremos también el puerto 8404 para configurar el acceso al portal de estadísticas de HAProxy. Lo veremos mas adelante.

Añadiremos estas 4 lineas:

1
2
3
4
-A INPUT -p icmp -m icmp --icmp-type 8 -j ACCEPT
-A INPUT -p tcp --dport 80 -j ACCEPT
-A INPUT -p tcp --dport 443 -j ACCEPT
-A INPUT -p tcp --dport 8404 -j ACCEPT

Quedando un fichero similar a este:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# init
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT DROP [0:0]
# Allow local-only connections
-A INPUT -i lo -j ACCEPT
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
#keep commented till upgrade issues are sorted
#-A INPUT -j LOG --log-prefix "FIREWALL:INPUT "
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -p icmp -m icmp --icmp-type 8 -j ACCEPT
-A INPUT -p tcp --dport 80 -j ACCEPT
-A INPUT -p tcp --dport 443 -j ACCEPT
-A INPUT -p tcp --dport 8404 -j ACCEPT
-A OUTPUT -j ACCEPT
COMMIT

Reiniciamos el servidor con el comando reboot

Instalación alta disponibilidad con Keepalived

Para dotar de alta disponibilidad a nuestro balanceador, usaremos Keepalived. Keepalived utiliza VRRP (Virtual Router Redundancy Protocol) para asignar una virtual IP (VIP) al nodo master de HAProxy y que así esté siempre disponible.

Instalaremos keepalived en ambos nodos con el siguiente comando:

1
tdnf install keepalived -y

Una vez instalado haremos un backup de la configuración antes de modificarla.

1
mv /etc/keepalived/keepalived.conf /etc/keepalived/keepalived-original.conf

Y crearemos un nuevo fichero de configuración similar a este:

Nodo MSTER: PhotonLB-01

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
! Configuration File for keepalived PhotonLB-01

global_defs {
   router_id PhotonLB-01
   vrrp_skip_check_adv_addr
   vrrp_garp_interval 0
   vrrp_gna_interval 0
}
vrrp_script chk_haproxy {
  script "/usr/bin/kill -0 haproxy"
  interval 2
  weight 2
}
vrrp_instance LB_VIP {
  interface eth0
  state MASTER                  # BACKUP on PhotonLB-02
  priority 101                  # 100 on PhotonLB-02
  virtual_router_id 11          # same on all peers
  authentication {              # same on all peers
    auth_type AH
    auth_pass Pass1234
  }
  unicast_src_ip 192.168.6.120    # real IP of MASTER peer
  unicast_peer {
    192.168.1.121                 # real IP of BACKUP peer
  }
  virtual_ipaddress {
    192.168.6.122                 # Virtual IP for HAProxy loadbalancer
    192.168.6.123                 # Virtual IP for Horizon
    192.168.6.124                 # Virtual IP for AppVolumes Manager
  }
  track_script {
    chk_haproxy                 # if HAProxy is not running on this peer, start failover
  }
}

Nodo SLAVE: PhotonLB-02

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
! Configuration File for keepalived PhotonLB-02

global_defs {
   router_id PhotonLB-02
   vrrp_skip_check_adv_addr
   vrrp_garp_interval 0
   vrrp_gna_interval 0
}
vrrp_script chk_haproxy {
  script "/usr/bin/kill -0 haproxy"
  interval 2
  weight 2
}
vrrp_instance LB_VIP {
  interface eth0
  state BACKUP                  # MASTER on PhotonLB-01
  priority 100                  # 101 on PhotonLB-01
  virtual_router_id 11          # same on all peers
  authentication {              # same on all peers
    auth_type AH
    auth_pass Pass1234
  }
  unicast_src_ip 192.168.6.121    # real IP of BACKUP peer
  unicast_peer {
    192.168.1.120                 # real IP of MASTER peer
  }
  virtual_ipaddress {
    192.168.6.122                 # Virtual IP for HAProxy loadbalancer
    192.168.6.123                 # Virtual IP for Horizon
    192.168.6.124                 # Virtual IP for AppVolumes Manager
  }
  track_script {
    chk_haproxy                 # if HAProxy is not running on this peer, start failover
  }
}

Resumiendo:

  • El nodo MASTER tiene una prioridad 101 y el BACKUP 100
  • Cada 2 segundos Keepalived chequea que HAProxy esté corriendo. Si está UP incrementa en 2 la prioridad y si está DOWN la baja 2
  • Mientras HAProxy esté UP en ambos servidores, el que tenga prioridad mas alta será MASTER
  • Si HAProxy se para en el nodo MASTER, la prioridad bajará y el BACKUP se convertirá en MASTER

En este punto, ya tenemos la configuración básica de keepalive. Se puede arrancar pero dará algunos fallos ya que todavia no tenemos instalado HAProxy y el script de chequeo fallará.

1
systemctl start keepalived

NOTA: Con el comando journalctl -r podemos ver el registro de logs

En el log veremos una salida similar a esta, el servicio se ha arrancado correctamente pero el script de HAProxy falla porque aún no está instalado.

1
2
3
4
5
6
Keepalived_vrrp[777]: Script `chk_haproxy` now returning 1
Keepalived_vrrp[777]: VRRP_Script(chk_haproxy) failed (exited with status 1)
Keepalived_vrrp[777]: (LB_VIP) Receive advertisement timeout
Keepalived_vrrp[777]: (LB_VIP) Entering MASTER STATE

Keepalived_vrrp[777]: (LB_VIP) setting VIPs.

Para acabar, habilitaremos el servicio keepalived para que arranque durante el boot del servidor.

1
systemctl enable keepalived

Instalación de HAProxy

Instalamos HAProxy con el siguiente comando:

1
tdnf install haproxy -y

Antes de empezar con la config, crearemos un directorio extra donde guardaremos información de estadísticas.

1
2
mkdir /var/lib/haproxy
chmod 755 /var/lib/haproxy

Al igual que con el fichero de configuración de keepalived, haremos un backup previo de la configuración original.

1
mv /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy-original.cfg

NOTA: A diferencia que keepalived, HAProxy tiene que tener idéntica configuración en ambos servidores. Así que asegurate de que los cambios que se realicen, se hagan de forma idéntica en ambos nodos.

El nuevo fichero de configuración tendrá la siguiente información:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# HAProxy configuration

#Global definitions
global
  chroot /var/lib/haproxy
  stats socket /var/lib/haproxy/stats
  daemon

defaults
  timeout connect 5s
  timeout client 30s
  timeout server 30s

### Statistics & Admin configuration ###
userlist stats-auth
  group admin   users admin
  user admin insecure-password LetMeIn
  group ro users stats
  user stats insecure-password ReadOnly
frontend stats-http8404
  mode http
  bind *:8404
  default_backend statistics
backend statistics
  mode http
  stats enable
  stats show-legends
  stats show-node
  stats refresh 30s
  acl AUTH http_auth(stats-auth)
  acl AUTH_ADMIN http_auth_group(stats-auth) admin
  stats http-request auth unless AUTH
  stats admin if AUTH_ADMIN
  stats uri /stats
  server PhotonLB01 192.168.6.120:8404 weight 1 check inter 30s fastinter 2s downinter 5s rise 3 fall 3
  server PhotonLB02 192.168.6.121:8404 weight 1 check inter 30s fastinter 2s downinter 5s rise 3 fall 3

######

### Horizon Connection servers ###
frontend horizon-http
  mode http
  bind 192.168.6.123:80
  # Redirect http to https
  redirect scheme https if !{ ssl_fc }

frontend horizon-https
  mode tcp
  bind 192.168.6.123:443
  default_backend horizon
backend horizon
  mode tcp
  option ssl-hello-chk
  balance source
  server Horizon_Connection_Server_01 192.168.6.113:443 weight 1 check inter 30s fastinter 2s downinter 5s rise 3 fall 3
  server Horizon_Connection_Server_02 192.168.6.114:443 weight 1 check inter 30s fastinter 2s downinter 5s rise 3 fall 3
######

### AppVolume Managers ###
frontend appvol-http
  mode http
  bind 192.168.6.124:80
  redirect scheme https if !{ ssl_fc }
frontend appvol-https
  mode tcp
  bind 192.168.6.124:443
  default_backend appvol

backend appvol
  mode tcp
  option ssl-hello-chk
  balance source
  server AppVolumes_Manager_01 192.168.6.118:443 weight 1 check inter 30s fastinter 2s downinter 5s rise 3 fall 3
  server AppVolumes_Manager_02 192.168.6.119:443 weight 1 check inter 30s fastinter 2s downinter 5s rise 3 fall 3
######

  • Statistics & Admin configuration: En esta parte creamos 2 grupos y 2 usuarios (Uno admin y otro read-only). Este grupo se usará para ver las estadísticas de HAProxy y para poner los servidores de backend en modo mantenimiento. Definimos el frontend para que acepte conexiones a cualquier ip bind: *:8404 Este es el puerto que definimos en iptables, os acordais? Para acceder al frontend y poder ver las estadísticas y habilitar/deshabilitar backend nos conectaremos a la URL http://192.168.6.122:8404/stats

  • Horizon Connection Servers: La primera parte sólo hacemos una redirección de HTTP a HTTPS. A continuación, la interfaz se configura utilizando la VIP para Horizon. En el backend se especifican los servidores de conexión y el algoritmo de equilibrio de carga. La opción ssl-hello-chk es necesaria para asegurarse de que HAProxy no solo verifique si el puerto 443 está abierto en el backend para configurar el backend como activo, sino también para verificar que realmente haya una conexión SSL válida al backend. Si no especificamos esto, el backend se activará para HAProxy, mientras que es posible que los servicios de Horizon aún se estén iniciando y aún no estén disponibles para su uso. En condiciones normales, cada 30 segundos se comprueban los backends. Cuando un backend está inactivo, la verificación se realiza cada 5 s (downinter 5s), y cuando una verificación falla o tiene éxito después de una falla anterior, los backends se verifican cada 2s (fastinter 2s).

  • AppVolumes Managers: Esta sección es similar a la de los Connection Server

Una vez tengamos la configuración hecha en ambos servidores, es momento de arrancar el servicio

1
systemctl start haproxy

La salida del comando journalctl -r deberia ser similar a esta:

1
2
3
4
5
6
systemd[1]: Starting HAProxy Load Balancer...
haproxy[3143]: [NOTICE] 040/100726 (3143) : New worker #1 (3145) forked
systemd[1]: Started HAProxy Load Balancer.
Keepalived_vrrp[3127]: Script `chk_haproxy` now returning 0
Keepalived_vrrp[3127]: VRRP_Script(chk_haproxy) succeeded
Keepalived_vrrp[3127]: (LB_VIP) Changing effective priority from 101 to 103

Para acabar, habilitaremos el servicio haproxy para que arranque durante el boot del servidor.

1
systemctl enable haproxy

Si todo ha ido bien y los servicios han arrancado sin errores, nos podremos conectar al portal de estadísticas en la url http://192.168.6.122:8404/stats (nos pedirá el usuario/contraseña que hemos definido en la configuración de haproxy)

stats

Comprobar estado keepalive

No quiero despedirme sin antes enseñaros un pequeño método para verificar el estado del Keepalive y quien es MASTER y quien es BACKUP

Con el siguiente comando, podremos verificar el “role” que tiene cada servidor:

1
2
root@PhotonLB-01 [ ~ ]# journalctl -u keepalived |grep Entering
Aug 25 12:27:01 PhotonLB-01 Keepalived_vrrp[539]: (LB_VIP) Entering MASTER STATE

Y con este la prioridad que tiene cada uno de ellos

1
2
root@PhotonLB-01 [ ~ ]# journalctl -u keepalived |grep effective
Aug 25 12:26:58 PhotonLB-01 Keepalived_vrrp[539]: (LB_VIP) Changing effective priority from 101 to 103

También otro comando interesante es el que vacia el log, por si tenemos muchos registros y nos cuesta indentificar cada acción

1
2
journalctl --rotate
journalctl --vacuum-time=1s

Y hasta aquí el post de hoy.

Espero sea de utilidad.

Un saludo!

Miquel.

0%