26 dic

HaProxy con Consul-Template y zero downtime reload

¿Por qué HaProxy con Consul-template?

HaProxy con Consul-template en Docker

HaProxy con Consul-template en Docker

Llevamos un tiempo trabajando en Docker con el dinamismo que ello nos supone, HaProxy con Consul-template nos ofrece una solucion muy similar a marathon-lb, el cual habíamos hablado en como usar marathon-lb para conectar nuestras aplicaciones dentro del cluster de Apache Mesos.

Marahon-lb es una maravilla, pero no dispone de algunas características que nos hacen falta, así que pensamos, bueno pues nos lo montamos nosotros.

Idea principal

La idea principal es utilizar la información que tenemos de nuestros servicios registrados en Consul, para poder generar la configuración de HaProxy con Consul-template. Fácil.

Lo haremos en docker así lo podremos lanzar en la plataforma de Apache Mesos, y claro esta si queremos que HaProxy tenga una configuración dinámica deberemos implementar el zero downtime reload

¿Qué es el Zero downtime reload HaProxy?

Cada vez que tengamos un cambio de configuración en HaProxy deberemos hacer una recarga del servicio, en el caso que tengamos conexiones establecidas esta recarga nos llevara a perderlas y claro, eso no es para nada deseable, ¿cómo solventamos este problema?

Pues seguiremos las indicaciones de Willy Tarreau CTO de HAPROXY,  lo que nos comenta es que podemos implementar una solución para descartar los paquetes SYN durante el reinicio de HaProxy, y aprovecharnos del funcionamiento de TCP para que se recupere automáticamente, añadiremos la solución en la imagen.

A esta solución hay una vuelta de tuerca mas, que lo explican maravillosamente bien la gente de Yelp, True Zero Downtime HAProxy Reloads.

Creación de los Dockers

Vamos a crear dos imágenes de Docker, por un lado la imagen con Consul-Templat y por otro la imagen de HaProxy que heredara de la primera imagen.

Toda la explicación y los ficheros necesarios están en mi github y la imagen de haproxy la podeis bajar de https://hub.docker.com/r/maauso/docker-consul-template/

Consul-template

Una de las partes mas importantes es entender el Consul-template que utilizaremos para HaProxy, gracias a Raul Fiestas por la creación del mismo :), podéis pasaros por su github, que tiene cosas muy interesantes https://github.com/rfiestas o su tumblr http://sudevops.tumblr.com/

La idea no es hacer una clase de consul-template, pero lo importante es saber las opciones que podemos usar, explicadas a continuación y que también podéis encontrar en https://github.com/maauso/docker-haproxy

¿Qué necesitamos para añadir un nuevo servicio a nuestro HaProxy?

Toda la información del servicio deberá estar en Consul, haremos un ejemplo con el servicio “www”

SERVICE_NAME=www

Este será en nombre de nuestro backend y frontend en la configuración de HaProxy, también será la url de acceso, que se concatenará al valor de HAPROXY_DOM, www.maauso.com

frontend app_http_in
  bind *:8080
  mode http
  acl host_www.maauso.com hdr(host) -i www.maauso.com
  use_backend www.maauso.com if host_www.maauso.com

Deberemos usuar Consul Tags, para decidir que servicios de Consul queremos añadir a nuestro HaProxy

HAPROXY.ENABLE=true

Y tendremos otras opciones del backend usando tags.

HAPROXY.PROTOCOL=http
HAPROXY.BACKEND.BALANCE=roundrobin
HAPROXY.BACKEND.MAXCONN=10000
backend www.maauso.com
  balance roundrobin
  mode http
  option forwardfor
  option tcp-check
  default-server inter 10s fall 1
  http-request set-header X-Forwarded-Port %[dst_port]
  http-request add-header X-Forwarded-Proto https if { ssl_fc }
Opciones de configuración para HaProxy 

Variables Globales que podemos modificar

HAPROXY_MAXCONN_GLOBAL=50000
HAPROXY_SPREAD_CHECKS=5
HAPROXY_MAX_SPREAD_CHECKS=15000
HAPROXY_SPREAD-CHECKS=5

Variables que no tienen valor por defecto

HAPROXY_DOM=maauso.com

Variables por defecto que podemos cambiar

HAPROXY_RETRIES=3
HAPROXY_BACKLOG=10000
HAPROXY_MAXCONN=10000
HAPROXY_TIMEOUT_CONNECT=3s
HAPROXY_TIMEOUT_CLIENT=30s
HAPROXY_TIMEOUT_SERVER=30s
HAPROXY_TIMEOUT_HTTP_KEEP_ALIVE=1s
HAPROXY_TIMEOUT_HTTP_REQUEST=15s
HAPROXY_TIMEOUT_QUEUE=30s
Por último zero downtime reload. 

Para conseguir el zero downtime reload consul-template enviará un SIGHUB al proceso que maneja a HaProxy, este proceso recibirá la señal con un trap y realizará el DROP de los paquetes SYN con iptables.

Acto seguido creara un nuevo proceso de HaProxy con la opción -sf $LATEST_HAPROXY_PID y eliminara la regla de iptables

 

12 abr

Balanceo de servicios con Marathon en Mesos

Dentro de la temática de los últimos post sobre Mesos, esta vez vamos a explicar como conseguir balanceo de servicios con Marathon en Mesos o sea tener un montón de servicios corriendo a través de Marathon en nuestro cluster de Mesos y poder trabajar con ellos a lo unisono.

Primero de todo debemos ver donde esta el problema, tenerlo claro para entender la solución.

Imaginemos que tenemos un servidor web, como hemos explicado en los post anteriores este servicio puede correr en cualquier puerto en cualquier nodo del cluster, es mas podemos tener mil servicios iguales en el mismo nodo corriendo en diferentes puertos. Como es de esperar esto hace muy difícil poder utilizarlos todos como si fuera uno solo (idea principal)

Vamos a verlo en una imagine

Balanceo de servicios con Marathon en Mesos

Balanceo de servicios con Marathon en Mesos

  1. Tenemos dos Slaves
  2. Tenemos los servicios (SVC 1 y 2) corriendo en los puertos 31000 y 31200, como sabemos estoy puertos son asignados aleatoriamente por Marathon.
  3. Nos interesa que cuando accedamos al puerto X este nos envíe a uno de los servicios (SVC) que este corriendo en el cluster.

Ahora que vemos la problemática vamos a ver como al solucionamos, al lío!

Balanceo de servicios con Marathon en apache mesos

Nota: Debemos quedarnos con la idea, la solución propuesta nos puede gustar más o menos

Instalaremos un HAProxy en cada nodo de Slave, Marathon nos ofrece un script que nos facilita la solución.

Instalación balanceo de servicios

Descargamos e instalamos en cada nodo el siguiente script, lo que hace es conectarse a la api de Marathon para sacar información de en qué puerto esta corriendo los servicios.


wget https://raw.githubusercontent.com/mesosphere/marathon/master/bin/haproxy-marathon-bridge

Necesita saber las urls y puertos donde esta corriendo Marathon, en nuestro caso esta en los nodos master, para ello crearemos un fichero y pondremos la información

/etc/haproxy-marathon-bridge/marathons

Y añadimos

marathon1.company.com:8080
marathon2.company.com:8080
marathon3.company.com:8080

Por último, deberemos añadir un cron que se ejecute cada minuto, de tal manera que se conecte a la API de Marathon vea en que puertos esta corriendo nuestros servicios y nos lo añada a la configuración de HA proxy.

./haproxy-marathon-bridge install_cronjob

Vamos a ver un ejemplo de como funciona esta solución.

Primero de todo os explico la situación inicial, para que podáis entender rápidamente el gif que hay mas abajo.

Balanceo de servicios con Marathon en Mesos

Balanceo de servicios con Marathon en Mesos

Tenemos un json que nos crea en el cluster de Mesos instancias http con python a través de Marathon, en la situación inicial tenemos 1 instancia corriendo únicamente.

Haremos incrementar el numero de instancias a 10, de tal manera que tendremos 10 instancias en el cluster corriendo en puertos aleatorios, y veremos como la configuración de HAProxy se actualiza con las nuevas instancias.

Por último veremos como atacando al puerto 8080 (puerto que decidimos donde queríamos tener el servicio corriendo), veremos el slave host, donde estamos atacando y veremos como se van balanceando las peticiones.

Tendremos

  • Panel 0 : Donde lanzaremos el curl para incrementar el numero de instancias.
  • Panel 1 : Número de servicio http que tenemos en un salve, situación inicial 1
  • Panel 2 : Curl al servicio web donde veremos como entre en el balanceo un nuevo salve.
  • Panel 3 : Configuración de HAProxy
Balanceo de servicios con Marathon en Mesos

Balanceo de servicios con Marathon en Mesos

Como podemos ver, con esta solución lo que conseguimos es poder escalar nuestras aplicaciones sin necesidad de “preocuparnos” del puerto en el que esta corriendo.

El concepto cambia, escalamos aplicaciones, no escalamos servidores para montar aplicaciones.

Ahora reflexionemos sobre ello.