¿Cómo usar Marathon-lb en Apache Mesos?

marathon-lb

Voy a explicar como trabajar con Marathon-lb (sustituto de marathon-haproxy-bridge) para Apache Mesos, hay parte teórica y parte práctica :),  hace un tiempo expliqué qué era Apache-Mesos y cómo empezar a trabajar con uno de su Frameworks llamado Marathon, también comentamos como utilizar marathon-haproxy-bridge para balancear peticiones de los Dockers que tengamos esparcidos por todo el cluster.

Antes de empezar nos debemos poner un poco en contexto, os recomiendo que leáis las entradas anteriores, para entender el ecosistema.

Parte teórica 

¿Qué es marathon-lb?

Marathon-lb es una solución que nos da la gente de Mesosphere para poder balancear de forma sencilla los servicios que tenemos en nuestro cluster de Apache Mesos, como sabemos por norma general cuando vamos desplegando Dockers en Apache Mesos estos empezaran a correr en slaves de Mesos aleatorios y en puertos aleatorios, esta dinámica hace complicado que podamos en trabajar con esos Dockers a no se que tengamos algún punto de entrada. Eso exactamente es lo que nos da marathon-lb.

¿Qué nos ofrece?

  1. Integración directa con Marathon, dependencia únicamente del Framework de Marathon
  2. Punto de entrada a los Dockers que tengamos corriendo en Apache Mesos
  3. Escalabilidad horizontal
  4. Actualizaciones de configuracion en tiempo real, conectando marathon-lb a Martahon usando SSE
  5. HealthChecks, tanto del propio HAProxy como a través de  Marathon
  6. TLS/SSL
  7. HaProxy Templates (la configuracion de HAProxy se realiza a través de labels de Docker, sublime)
  8. Imagen Docker para correrlo en Apache Mesos

¿Cómo funciona?

El funcionamiento en si es de lo más sencillo, marathon-lb «solo» es un script hecho en python que una vez conectado a Marathon  a través de SSE, y va actualizando la configuración del HAProxy que lleva en su interior, por cada aplicación que lancemos en Apache Mesos marathon-lb hará la asociación entre el punto de entrada que le hayamos dicho y el los Dockers con sus respectivos puertos.

La asociación entre HAProxy y los Dockers lo podemos hacer por dos métodos, puerto o usando un virtual host.

En el caso de querer una asociación por puerto, o sea que la url de acceso sea del tipo lo

http://marathon-lb.company.com:10001

Deberemos lanzar el Docker definiendo un puerto de servicio que será utilizado por marathon-lb como puerta de entrada, en este caso el 10001

Otro caso de uso es la asociación por virtual host, en este caso la url de entrada podría ser algo como.

http://miservicio.company.com

Para usar esta opción deberemos lanzar el Docker con la label

HAPROXY_{n}_VHOST

Por ejemplo

HAPROXY_VHOST = "http://miservicio.company.com" 

Antes de pasar a la parte practica decir que

Parte práctica

Objetivos

  • Tener un único punto de entrada que nos de acceso a todos los Dockers de un servicio que estén corriendo en nuestro Apache Mesos, en este ejemplo será un Nginx

Características de práctica

  1. Utilizaremos el acceso por Virtual Host
  2. Conectaremos marathon-lb a Marathon usando SSE
  3. Lanzaremos el docker de marathon-lb en modo Host.

¿Como lanzamos marathon-lb en Apache Mesos ?

Como es lógico primero de todo deberemos montar el JSON para poder lanzar marathon-lb en nuestro Apache Mesos a través del Framework Marathon, el JSON tiene una pinta tal que así y explicamos cada punto más abajo

Campos:

«cmd» :

  •  /marathon-lb/run sse : Ejecucion de marathon-lb en modo sse
  • –marathon: Url de nuestro Marathon
  • –group : Con esta opcion estamos diciendo cuales son los dockers que queremos que se usen a través de marathon-lb, en nuestro caso aquello que lleven «HAPROXY_0_GROUP«: «qa«.
  • –health-check:  Con esta opcion estamos diciendo que HAProxy no active el docker hasta que el healthcheck de Marathon este ok. 

 «ports»:

  • Por seguridad al ejecutar el Docker en modo HOST, deberemos asegurar que los puertos que utiliza nuestro HAProxy están disponibles en el Slave de Mesos, junto con «requirePorts» : true, añadiendo los puertos tendremos  en PORT0-1-2 que los utilizaremos para hacer el healtcheck de HAProxy

«constraints»:

  • Con estas dos constraints nos aseguramos que no vayamos a tener dos Marathon-lb en el mismo host (puede ser redundante con la opción de ports) y decidimos en que datacenter queremos lanzadlos.

 «healthchecks»:

  • Con este COMMAND comprobamos que el servicio este levantado y Marathon pueda darnos información del estado de HAProxy

Lanzamos marathon-lb

curl -X POST -H "Content-Type: application/json"  --data @marathon-lb-test.json 'http://marathon.company.com:8080/v2/apps'

Veremos en Marathon:

marathon-lb

¿Cómo lanzamos Nginx para que trabaje con Marathon-lb?

Ejemplo de JSON que deberíamos lanzar para que trabajara con marathon-lb, la explicación mas abajo.

Aquí la parte más importante, los labels que hemos añadido en el JSON, a través de labels en nuestro Docker haremos la configuración de nuestro HAProxy, tenemos una lista bastante extensa de opciones, en este ejemplo explicare los que me parecieron más comunes de utilizar.

Podemos encontrar la lista en el github de Mesosphere

«labels»

  • «HAPROXY_BACKEND_WEIGHT»: Peso que tendrá esta backend en HAProxy respecto a otros.
  • «HAPROXY_MODE»: http o tcp
  • «HAPROXY_BALANCE»: Tipo de balance
  • «HAPROXY_GROUP»:  Grupo al que pertenece, con esta opcion asociaremos nuestro nginx al HAProxy que queramos.
  • «HAPROXY_BACKEND_STICKY_OPTIONS» :  Una sticky cookie 
  • «HAPROXY_VHOST»:  Pues lo más importante a que fqdn nuestro HAPoxy nos dará acceso 

Lanzamos nginx

curl -X POST -H "Content-Type: application/json"  --data @nginx.json 'http://marathon.company.com:8080/v2/apps'

Veremos en Marathon:

Apache Mesos Nginx Marathon

Escalamos a 5 nginx

Apche Mesos Marathon scale

Si nos fijamos tenemos, como esperábamos cada nginx en un puerto diferente.

Si comprobamos HAProxy veremos en el log interno qué es lo que hizo.

marathon_lb: received event of type deployment_success
marathon_lb: received event of type health_status_changed_event
marathon_lb: fetching apps
marathon_lb: received event of type deployment_step_success
marathon_lb: GET http://marathon.company.com:8080/v2/apps?embed=apps.tasks
marathon_lb: got apps ['/test/ha/nginx/nginx', '/tools/docker/registry', '/prova-logs','/test/ha/marathon-lb-test']
marathon_lb: generating config
marathon_lb: HAProxy dir is /marathon-lb
marathon_lb: configuring app /test/ha/nginx/nginx
marathon_lb: frontend at *:10001 with backend test_ha_nginx_nginx_10001
marathon_lb: adding virtual host for app with hostname miguel.haproxy.com
marathon_lb: adding virtual host for app with id /test/ha/nginx/nginx
marathon_lb: backend server 192.168.1.100:50071 on server
marathon_lb: backend server 192.168.1.101:58437 on server
marathon_lb: backend server 192.168.1.102:12213 on server
marathon_lb: backend server 192.168.1.103:45197 on server
marathon_lb: backend server 192.168.1.104:14673 on server
marathon_lb: reading running config from /marathon-lb/haproxy.cfg
marathon_lb: updating tasks finished, took 0.24720096588134766 seconds

Podemos ver como marathon-lb

  1. Detecto un nuevo deploy
  2. Comprobó las aplicaciones y únicamente se quedo con las que cumplen la opción –group que explicamos mas arriba
  3. Creo el backend para nuestro ngnix y asigno el virtul host miguel.haproxy.com
  4. Añade todos los dockers que tenemos en nuestro mesos slave en
  5. Actualiza la configuracion
  6. Todo esto en 0.2472 segundos.

Si  comprobamos la pagina de stats de HAProxy podremos ver .

Apache Mesos HAPoxy

Por último comprobamos que nos contesta

curl -H "Host: miguel.haproxy.com" http://192.168.1.10
Welcome to nginx!
Thank you for using nginx.

Todo funcionando!

 

 

Raspberry + Tor + HAVP + SQUID + Privoxy

Tengo vacaciones, tengo vacaciones y una Raspberry apagada en una esquina, pobre de ella. Voy a explicar como utilizar raspberry para montar un sistema para mantener a «salvo» nuestra privacidad usando la red Tor + Privoxy + HAVP + SQUID, a más explicaré como añadir un antivirus que analice todas las peticiones que se hagan a través del sistema

La privacidad, que importante y que fácil es perderla.

La solución tiene diferentes piezas, vamos a ver que hace cada una de ellas.

Tor : Bien conocido por la mayoria https://es.wikipedia.org/wiki/Tor_(red_de_anonimato)

HAVP: Antivirus que escanea el trafico usando ClamAV http://www.server-side.de/features.htm

SQUID: Proxy https://es.wikipedia.org/wiki/Squid_(programa)

Privoxyhttps://es.wikipedia.org/wiki/Privoxy (filtra el contenido indeseable de las páginas, aumenta la seguridad del equipo, evita archivos que nos rastrean y elimina la publicidad.)

La idea viene siendo que las peticiones que hagamos a través de Squid se escaneen utilizando HAVP y se envien a Privoxy, este las limpie y las envíe a la red tor, algo así

RSHPT (3)
Squid HAVP Privoxy

 

En primera instancia lo que vamos a montar es la parte mas estandar que es 1 SQUID + PRIVOXY+TOR, esta solución funciona perfectamente en Raspberry

Algo así

RSHPT (2)
Squid HAVP Privoxy

 

 

La parte del segundo SQUID + HAVP es opcional y si queréis montarlo en Raspberry deberéis tener el modelo de 1GB. Por ello montamos la primera parte, que debe funcionara para todos y después ampliamos con a la parte del antivirus.

Empezamos.

[email protected]# aptitude install tor
[email protected]# aptitude install privoxy
[email protected]# aptitude install squid

Los tres paquetes esenciales, comenzaremos configurando los servidores tor.

Configuración del servicio Tor

Vamos a crear los ficheros de configurar tor

vim /etc/tor/torrc
SocksPort 9050 # what port to open for local application connections
SocksBindAddress 127.0.0.1 # accept connections only from localhost
AllowUnverifiedNodes middle,rendezvous
Log notice syslog
RunAsDaemon 1
User tor
Group tor
DataDirectory /var/lib/tor
Log notice file /var/log/tor/notices.log

Básicamente configuramos el puerto donde queremos que escuche el servidor de tor en nuestro caso por defecto en el 9050

Configuración del servicio Privoxy

Configuraremos Privoxy, este servicio tiene muchas opciones, segun comentan en la pagina del proyecto salir con las opciones por defecto es recomendable, después podremos jugar con más opciones si lo deseamos,  lo que debemos hacer es asociar un Privoxy con un Tor, ajustando el puerto en la linea froward-socks5

vim /etc/privoxy/config
confdir /etc/privoxy
logdir /var/log/privoxy
actionsfile standard.action  # Internal purpose, recommended
actionsfile default.action   # Main actions file
actionsfile user.action      # User customizations
filterfile default.filter
logfile logfile
listen-address  127.0.0.1:8118
toggle  1
enable-remote-toggle  0
enable-remote-http-toggle  0
enable-edit-actions 0
enforce-blocks 0
buffer-limit 4096
forward-socks5   /               127.0.0.1:9050 .
forwarded-connect-retries  0
accept-intercepted-requests 0
allow-cgi-request-crunching 0
split-large-forms 0

Con privoxy y tor ya tendremos las dos piezas esenciales, levantamos los servicios y comprobamos que si realizamos una petición al puerto del privoxy este ya se comunica con tor y nos envia por la red tor.

La idea de poner el SQUID por delante es que nos permite si lo deseamos aplicar acl y diferentes reglas, a mi parecer es algo más potente que privoxy

Configuración del servicio SQUID 1

Como hemos explicado en otro post, podéis montar vuestro propio paquete Squid para habilitar algunas opciones, en mi casa por ejemplo la posibilidad de añadir certificados ssl.

La instalación es sencilla

[email protected]# aptitude install squid3

Una vez instalado modificamos el fichero de configuración

acl SSL_ports port 443
acl Safe_ports port 80          # http
acl Safe_ports port 21          # ftp
acl Safe_ports port 443         # https
acl Safe_ports port 70          # gopher
acl Safe_ports port 210         # wais
acl Safe_ports port 1025-65535  # unregistered ports
acl Safe_ports port 280         # http-mgmt
acl Safe_ports port 488         # gss-http
acl Safe_ports port 591         # filemaker
acl Safe_ports port 777         # multiling http
acl CONNECT method CONNECT
http_access deny !Safe_ports
http_access deny CONNECT !SSL_ports
acl user src 192.168.1.138/32 ::1
acl userlist src all
http_access allow user
http_access allow userlist
http_access allow localhost manager
http_access deny manager
http_access allow localhost
http_access deny all
http_port 3400
cache_peer 192.168.1.101 parent 8118 0 no-query no-digest
never_direct allow all
coredump_dir /var/spool/squid3
refresh_pattern ^ftp:           1440    20%     10080
refresh_pattern ^gopher:        1440    0%      1440
refresh_pattern -i (/cgi-bin/|\?) 0     0%      0
refresh_pattern .               0       20%     4320
access_log /var/log/squid3/access_squid.log

Las lines que son un poco diferentes son

Acl de acceso, aqui teneis dos ejemplos, en uno limitamos por ip y en el otro damos permiso a todo (es un ejemplo y son redundantes entre ellas, es mas mejor no dar acceso a todo el mundo )

acl user src 192.168.1.138/32 ::1
acl userlist src all

Puerto del squid3

http_port 3400

Y a donde se enviará las peticiones, en este caso al puerto del privoxy

cache_peer 192.168.1.101 parent 8118 0 no-query no-digest
never_direct allow all

El log

access_log /var/log/squid3/access_squid.log

Arrancamos el servicio y comprobamos que la solución funciona

systemctl start squid3

Vamos a realizar 2 curls, el primero normal y el siguiente utilizando el sistema que hemos montado.

Sin Proxy

[email protected]:~#  curl ipv4.icanhazip.com
37.135.18.39

Con Proxy

curl -x 192.168.1.101:3400 ipv4.icanhazip.com
207.244.70.35

Claramente podemos ver el cambio de ip ya que estamos saliendo por la red TOR, con lo que conlleva.

Vamos a por la segunda parte, instalación y configuración de Squid 2 y HAVP

 Instalación de paquetes

Recordar que allí donde vayamos a instalar HAVP deberemos tener como mínimo 1 GB de RAM.

Configuración de Squid 2
vim /etc/squid3/squid.conf
acl SSL_ports port 443
acl Safe_ports port 80          # http
acl Safe_ports port 21          # ftp
acl Safe_ports port 443         # https
acl Safe_ports port 70          # gopher
acl Safe_ports port 210         # wais
acl Safe_ports port 1025-65535  # unregistered ports
acl Safe_ports port 280         # http-mgmt
acl Safe_ports port 488         # gss-http
acl Safe_ports port 591         # filemaker
acl Safe_ports port 777         # multiling http
acl CONNECT method CONNECT
http_access deny !Safe_ports
http_access deny CONNECT !SSL_ports
acl user src 192.168.1.138/32 ::1
acl userlist src all
http_access allow user
http_access allow userlist
http_access allow localhost manager
http_access deny manager
http_access allow localhost
http_access deny all
http_port 3128
cache_peer 127.0.0.1 parent 3410 0 no-query no-digest
never_direct allow all
coredump_dir /var/spool/squid3
refresh_pattern ^ftp:           1440    20%     10080
refresh_pattern ^gopher:        1440    0%      1440
refresh_pattern -i (/cgi-bin/|\?) 0     0%      0
refresh_pattern .               0       20%     4320
access_log /var/log/squid3/access_squid.log

Es la misma configuración que el anterior proxy pero lo que haremos es cambiar el puerto de entrada (en el caso que lo tengamos en la misma maquina) y apuntar el cache_peer al puerto del HAVP en este caso el 3410

cache_peer 127.0.0.1 parent 3410 0 no-query no-digest
 Configuración de HAVP

Deberemos decirle al servicio que todas aquella peticiones desde el SQUID 2 las debe reenviar al SQUID 1.

USER havp
GROUP havp
DAEMON true
PIDFILE /tmp/havp.pid
SERVERNUMBER 1
MAXSERVERS 1
SCANTEMPFILE /tmp/havp-XXXXXX
TEMPDIR /tmp
DBRELOAD 60
PARENTPROXY 192.168.1.101
PARENTPORT 3400
FORWARDED_IP false
X_FORWARDED_FOR false
PORT 3410
BIND_ADDRESS 127.0.0.1
ENABLECLAMLIB true
ENABLECLAMD false
ENABLEFPROT false
ENABLEAVG false
ENABLEAVESERVER false
ENABLESOPHIE false
ENABLETROPHIE false
ENABLENOD32 false
ENABLEAVAST false
ENABLEARCAVIR false
ENABLEDRWEB false

Por ultimo deberemos montar el sistema de ficheros donde tengamos HAVP con la opcion -o mand.

/dev/mmcblk0p2  /  ext4    defaults,noatime,mand  0       1
mount -o remount /

Arrancamos y comprobamos

 /etc/init.d/havp start
Starting havp (via systemctl): havp.service.
Comprovación

En el gif podeis ver 4 ventanas cada una de ellas es una de las piezas principales del sistema, la idea es lanzar un curl desde un cliente y ver como la peticion pasa por todas las piezas.

status

Lanzamos

curl to NSA

Como podemos ver la petición pasa por todos los sistemas, si que es verdad que introducir la pieza de HAVP hace que la petición sea mas lenta.

¿Cómo podemos utilizar la solución de forma sencilla?

En mi caso utilizo la extensión  para chrome FoxyProxy, con ella de forma sencilla podemos tener más de un proxy configurado y decidir cual utilizar en cada momento.

Por último un resultado de una página con bloqueos de Privoxy es

Captura O una prueba completa en una pagina que tiene bastantes anuncios, cookies y cosas raras y feas

Result_maauso.com

¿Cómo compilar Squid con SSL?

Como bien sabemos Squid con ssl no viene por defecto, para activar esta opción debemos compilar el paquete Squid con la opción –enable-ssl, entonces ¿cómo compilar squid con ssl?

En mi caso me hizo falta para arm, pero el procedimiento es igual para arquitecturas x86

Paquetes necesarios

[codeBusc]
sudo apt-get install devscripts build-essential fakeroot libssl-dev
[/code]

Código fuente de Squid3

apt-get source squid3
apt-get build-dep squid3

Dependencias

dpkg-source -x squid3_3.4.8-6+deb8u1.dsc
Preparación del paquete

Añadimos las opciones de compilación en el fichero rules

vim squid3-3.4.8/debian/rules

DEB_CONFIGURE_EXTRA_FLAGS := --datadir=/usr/share/squid3 \
                --sysconfdir=/etc/squid3 \
                --mandir=/usr/share/man \
                --enable-inline \
                --disable-arch-native \
                --enable-async-io=8 \
                --enable-storeio="ufs,aufs,diskd,rock" \
                --enable-removal-policies="lru,heap" \
                --enable-delay-pools \
                --enable-ssl \
                --enable-ssl-crtd \
Compilación de Squid con SSL

Y por último a compilar y a esperar, en mi caso fueron varias horas, pobre Raspberry

 dpkg-buildpackage -rfakeroot -b 

Una vez finalizado dispondremos de diferentes paquetes, los dos que nos hacen falta son

squid3_3.4.8-6+deb8u1_armhf.deb
squid3-common_3.4.8-6+deb8u1_all.deb

Una vez instalados podremos comprobar que mirando la versión de squid tendremos activada la opcion –enable-ssl 

[email protected]:~# squid3 -v | grep ssl
configure options:  '--build=arm-linux-gnueabihf' '--prefix=/usr' '--includedir=${prefix}/include' '--mandir=${prefix}/share/man' '--infodir=${prefix}/share/info' '--sysconfdir=/etc' '--localstatedir=/var' '--libexecdir=${prefix}/lib/squid3' '--srcdir=.' '--disable-maintainer-mode' '--disable-dependency-tracking' '--disable-silent-rules' '--datadir=/usr/share/squid3' '--sysconfdir=/etc/squid3' '--mandir=/usr/share/man' '--enable-inline' '--disable-arch-native' '--enable-async-io=8' '--enable-storeio=ufs,aufs,diskd,rock' '--enable-removal-policies=lru,heap' '--enable-delay-pools' '--enable-ssl' '--enable-ssl-crtd' '--enable-cache-digests' '--enable-icap-client' '--enable-follow-x-forwarded-for' '--enable-auth-basic=DB,fake,getpwnam,LDAP,MSNT,MSNT-multi-domain,NCSA,NIS,PAM,POP3,RADIUS,SASL,SMB' '--enable-auth-digest=file,LDAP' '--enable-auth-negotiate=kerberos,wrapper' '--enable-auth-ntlm=fake,smb_lm' '--enable-external-acl-helpers=file_userip,kerberos_ldap_group,LDAP_group,session,SQL_session,unix_group,wbinfo_group' '--enable-url-rewrite-helpers=fake' '--enable-eui' '--enable-esi' '--enable-icmp' '--enable-zph-qos' '--enable-ecap' '--disable-translation' '--with-swapdir=/var/spool/squid3' '--with-logdir=/var/log/squid3' '--with-pidfile=/var/run/squid3.pid' '--with-filedescriptors=65536' '--with-large-files' '--with-default-user=proxy' '--enable-build-info=Raspbian linux' '--enable-linux-netfilter' 'build_alias=arm-linux-gnueabihf' 'CFLAGS=-g -O2 -fPIE -fstack-protector-strong -Wformat -Werror=format-security -Wall' 'LDFLAGS=-fPIE -pie -Wl,-z,relro -Wl,-z,now' 'CPPFLAGS=-D_FORTIFY_SOURCE=2' 'CXXFLAGS=-g -O2 -fPIE -fstack-protector-strong -Wformat -Werror=format-security'

Con esto ya disponemos de Squid con SSL, ahora podemos añadir certificados para la creación del una conexión segura cliente servidor.