Esta pagina se ve mejor con JavaScript habilitado

Configuración dinámica HAProxy mediante DNS

 ·  🎃 kr0m

La manera mas sencilla de tener una entrada DNS por cada servidor web es utilizar un servidor Consul ya que este nos generará dichas entradas de forma automática, en este artículo anterior ya aprendimos como configurar HAProxy para que se reconfigurase en base a los servidores dados de alta en los servicios de Consul, la diferencia entre hacerlo basándonos en los servicios o en las entradas DNS son:

  • Servicio: Utilizamos DataPlaneAPI para la reescritura de la configuración, esto nos permite una absoluta flexibilidad, pudiendo aumentar o disminuir el pool de servidores del backend a antojo.
  • DNS: La configuración del HAProxy es mucho mas sencilla sin necesidad de aplicaciones de terceros(DataPlaneAPI), el problema es que el número de servidores del backend es semiestático ya que en la configuración del HAProxy se definirá el máximo número de servidores.

Para una mayor claridad el artículo se ha divido en varias partes:


INTRODUCCIóN:

El escenario se compone de un servidor Consul que actuará a modo de DNS, un HAProxy y algunos servidores Nginx , todos ellos jails creadas mediante IOCage .

CONSUL: NYNEX-King
HAPROXY: BlindSnipper
NGINX: PeanutBrain00/01/02/03/04/05/06/07/09/10/11
+-----+---------------+-------+--------------+---------------+
| JID |     NAME      | STATE |   RELEASE    |      IP4      |
+=====+===============+=======+==============+===============+
| 39  | BlindSnipper  | up    | 13.1-RELEASE | 192.168.69.51 |
+-----+---------------+-------+--------------+---------------+
| 36  | NYNEX-King    | up    | 13.1-RELEASE | 192.168.69.50 |
+-----+---------------+-------+--------------+---------------+
| 42  | PeanutBrain00 | up    | 13.1-RELEASE | 192.168.69.52 |
+-----+---------------+-------+--------------+---------------+
| 45  | PeanutBrain01 | up    | 13.1-RELEASE | 192.168.69.53 |
+-----+---------------+-------+--------------+---------------+
| 50  | PeanutBrain02 | up    | 13.1-RELEASE | 192.168.69.54 |
+-----+---------------+-------+--------------+---------------+
| 53  | PeanutBrain03 | up    | 13.1-RELEASE | 192.168.69.55 |
+-----+---------------+-------+--------------+---------------+
| 56  | PeanutBrain04 | up    | 13.1-RELEASE | 192.168.69.56 |
+-----+---------------+-------+--------------+---------------+
| 59  | PeanutBrain05 | up    | 13.1-RELEASE | 192.168.69.57 |
+-----+---------------+-------+--------------+---------------+
| 63  | PeanutBrain06 | up    | 13.1-RELEASE | 192.168.69.58 |
+-----+---------------+-------+--------------+---------------+
| 66  | PeanutBrain07 | up    | 13.1-RELEASE | 192.168.69.59 |
+-----+---------------+-------+--------------+---------------+
| 69  | PeanutBrain08 | up    | 13.1-RELEASE | 192.168.69.60 |
+-----+---------------+-------+--------------+---------------+
| 72  | PeanutBrain09 | up    | 13.1-RELEASE | 192.168.69.61 |
+-----+---------------+-------+--------------+---------------+
| 75  | PeanutBrain10 | up    | 13.1-RELEASE | 192.168.69.62 |
+-----+---------------+-------+--------------+---------------+
| 78  | PeanutBrain11 | up    | 13.1-RELEASE | 192.168.69.63 |
+-----+---------------+-------+--------------+---------------+

CONSUL SERVER:

Instalamos Consul:

pkg install consul

Arrancamos Consul para que nos genere él mismo el directorio de configuración:

sysrc consul_enable=YES
service consul start

Realizamos la configuración base:

vi /usr/local/etc/consul.d/consul.hcl

datacenter = "AlfaExploitDC01"
server = true
data_dir = "/var/db/consul"
bind_addr = "192.168.69.50"
client_addr = "192.168.69.50"
bootstrap = true
bootstrap_expect = 1

ui_config {
    enabled = true
}

enable_syslog = true
log_level = "INFO"

Reiniciamos Consul:

service consul restart

Accedemos a la interfaz web, tan solo veremos un servicio registrado, el del propio Consul:
http://192.168.69.50:8500


HAPROXY:

Instalamos el software necesario:

pkg install haproxy

Nos aseguramos de que el servicio syslod esté bindeado por red, consultamos las flags de configuración, si aparece el parámetro -ss debemos reconfigurarlo:

sysrc syslogd_flags

syslogd_flags: -c -ss

Lo reconfiguramos y reiniciamos el servicio:

sysrc syslogd_flags="-c"
service syslogd restart

Configuramos HAProxy:

vi /usr/local/etc/haproxy.conf

global
    daemon
    maxconn 5000
    log 192.168.69.51:514 local0
    user nobody
    group nobody
    stats socket /var/run/haproxy.sock user nobody group nobody mode 660 level admin

    ssl-default-bind-ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256
    ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets
    
defaults
    timeout connect 10s
    timeout client 30s
    timeout server 30s
    log global
    mode http
    option httplog

listen stats
    bind *:8404
    stats enable
    stats uri /stats
    stats refresh 5s
    stats auth kr0m:PASSWORD

frontend http_front
   bind *:80
   default_backend http_back

backend http_back
    balance roundrobin
    server-template mywebapp 1-10 _web._tcp.service.consul resolvers consul resolve-opts allow-dup-ip resolve-prefer ipv4 check

resolvers consul
    nameserver consul 192.168.69.50:8600
    accepted_payload_size 8192
    hold valid 5s

La línea mas importante es server-template, en ella indicamos como debe generarse el backend:

  • mywebapp: Nombre de la app web, los servidores se nombrarán en base a este parámetro.
  • 1-10: Número de servidores que habrá en el backend, como vemos se trata de un valor estático.
  • _web._tcp.service.consul: Entrada DNS a consultar para obtener los servidores web del backend: _SERVICE_NAME._tcp.service.consul
  • resolvers consul: Que resolver utilizar para realizar la query DNS.
  • resolve-opts allow-dup-ip resolve-prefer ipv4 check: Opciones adicionales sobre la resolución DNS.

Asignamos los permisos correctos del fichero:

chmod 660 /usr/local/etc/haproxy.conf

Comprobamos manualmente que la configuración sea correcta:

haproxy -c -f /usr/local/etc/haproxy.conf

[NOTICE]   (83382) : haproxy version is 2.6.1-f6ca66d
[NOTICE]   (83382) : path to executable is /usr/local/sbin/haproxy
[WARNING]  (83382) : config : ca-file: 0 CA were loaded from '@system-ca'
Warnings were found.
Configuration file is valid

Arrancamos el servicio:

sysrc haproxy_enable=YES
service haproxy start


NGINX:

Instalamos Consul y Nginx en los servidores web:

pkg install consul nginx

Arrancamos Nginx:

sysrc nginx_enable=YES
service nginx start

Arrancamos Consul para que nos genere él mismo el directorio de configuración:

sysrc consul_enable=YES
service consul start

En la configuración de Consul definimos la ip a la que bindearse y la ip del consul-server(192.168.69.50):

vi /usr/local/etc/consul.d/consul.hcl

datacenter = "AlfaExploitDC01"
server = false
data_dir = "/var/db/consul"
bind_addr = "192.168.69.XX"
retry_join = ["192.168.69.50"]
enable_syslog = true
log_level = "INFO"

Reiniciamos el servicio:

service consul restart

Damos de alta el servidor como servidor web:

vi web.json

{
  "service": {
    "name": "web",
    "port": 80
  }
}
consul services register ./web.json
Node name "PeanutBrain00.alfaexploit.com" will not be discoverable via DNS due to invalid characters. Valid characters include all alpha-numerics and dashes.
Registered service: web

NOTA: Por ahora solo vamos a dar de alta del nodo 00-08, 9 en total, esto comprende las ips de la 192.168.69.52-60.

Podemos consultar las entradas DNS manualmente:

dig @192.168.69.50 -p 8600 _web._tcp.service.consul

; <<>> DiG 9.18.5 <<>> @192.168.69.50 -p 8600 _web._tcp.service.consul
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 41802
;; flags: qr aa rd; QUERY: 1, ANSWER: 9, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;_web._tcp.service.consul.	IN	A

;; ANSWER SECTION:
_web._tcp.service.consul. 0	IN	A	192.168.69.52
_web._tcp.service.consul. 0	IN	A	192.168.69.55
_web._tcp.service.consul. 0	IN	A	192.168.69.58
_web._tcp.service.consul. 0	IN	A	192.168.69.56
_web._tcp.service.consul. 0	IN	A	192.168.69.59
_web._tcp.service.consul. 0	IN	A	192.168.69.54
_web._tcp.service.consul. 0	IN	A	192.168.69.60
_web._tcp.service.consul. 0	IN	A	192.168.69.53
_web._tcp.service.consul. 0	IN	A	192.168.69.57

;; Query time: 6 msec
;; SERVER: 192.168.69.50#8600(192.168.69.50) (UDP)
;; WHEN: Tue Sep 13 09:18:35 CEST 2022
;; MSG SIZE  rcvd: 197

Si accedemos de nuevo a la interfaz del servidor de Consul podremos ver las intancias dadas de alta en el servicio web:
http://192.168.69.50:8500/ui/alfaexploitdc01/services

Podemos ver como en el HAProxy se van añadiendo los servidores, en caso de haber menos de 10 servidores dados de alta en el DNS se deshabilita el excedente:

Damos de alta en Consul el resto de los servidores web: 192.168.69.61-63 y consultando las entradas DNS:

dig @192.168.69.50 -p 8600 _web._tcp.service.consul

; <<>> DiG 9.18.5 <<>> @192.168.69.50 -p 8600 _web._tcp.service.consul
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 65031
;; flags: qr aa rd; QUERY: 1, ANSWER: 12, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;_web._tcp.service.consul.	IN	A

;; ANSWER SECTION:
_web._tcp.service.consul. 0	IN	A	192.168.69.56
_web._tcp.service.consul. 0	IN	A	192.168.69.62
_web._tcp.service.consul. 0	IN	A	192.168.69.53
_web._tcp.service.consul. 0	IN	A	192.168.69.60
_web._tcp.service.consul. 0	IN	A	192.168.69.52
_web._tcp.service.consul. 0	IN	A	192.168.69.63
_web._tcp.service.consul. 0	IN	A	192.168.69.58
_web._tcp.service.consul. 0	IN	A	192.168.69.61
_web._tcp.service.consul. 0	IN	A	192.168.69.57
_web._tcp.service.consul. 0	IN	A	192.168.69.55
_web._tcp.service.consul. 0	IN	A	192.168.69.54
_web._tcp.service.consul. 0	IN	A	192.168.69.59

;; Query time: 1 msec
;; SERVER: 192.168.69.50#8600(192.168.69.50) (UDP)
;; WHEN: Tue Sep 13 09:25:01 CEST 2022
;; MSG SIZE  rcvd: 245

A pesar de haber 12 servidores web activos HAProxy solo utiliza 10 de ellos ya que en la configuración asignamos de forma estática dicho valor, esto se podría mitigar configurando un número muy alto de servidores al que sabemos que nunca vamos a llegar o utilizando DataPlaneAPI :

Los servidores utilizados los decide internamente HAProxy sin manera de conocer sus ips.


TROUBLESHOOTING:

Podemos consultar los logs de HAProxy:

tail -f /var/log/messages

Arrancar HAProxy en modo debug desde el script de RC:

cp /usr/local/etc/rc.d/haproxy /usr/local/etc/rc.d/haproxy.ori

vi /usr/local/etc/rc.d/haproxy
: ${haproxy_flags:="-d -V -f ${haproxy_config} -p ${pidfile}"}

Arrancar manualmente HAProxy:

haproxy -d -V -f /usr/local/etc/haproxy.conf

Consultar manualmente las entradas DNS:

dig @192.168.69.50 -p 8600 _web._tcp.service.consul

Si te ha gustado el artículo puedes invitarme a un RedBull aquí