Montando un Docker Cluster con Swarm Mode

30 Jul 2016

Desde que salio Docker lo primero que me vino a la mente fue que esto seria una herramienta perfecta para crear tu propio PaaS a la Heroku y tuve razón salieron proyectos muy buenos que te permitian tener tu propio PaaS personal y buscaban solucinar el problema de como orquestar y escalar servicio a travez de multiples nodos, el unico problema que era tedioso instalarlos y administrarlos. Luego llego Swarm por parte de Docker que hacia muy fácil escalar y orquestar servicio e incluso para esas epocas ya se estaba desarrollando la overlay network entre contenedores sin importar que estuvieran en distintos hosts, era sencillo y rápido armar un cluster pero aun tenias que depende de software de terceros y seguir varios pasos para tener todo configurado como se debe, la cosa es que hace unas semanas anunciaron que Swarm formaria parte de engine de Docker y que armar un cluster seria fácil y rapido, dicho y hecho hace dos días salio la version 1.12 de Docker y ya viene con todo esto incluido entre la ventajas del Swarm Mode:

  • Ya no necesitamos un key value store externo, antes necesitamos usar etcd, zookeeper o consul para almacenar el estado del cluster y configuraciones de la overlay network, ahora ya no Docker ya viene con su propia inplementación del Raft Consensus Algorithm y su key value store (que creo que es etcd) integrado para poder garantizar la integridad del estado del cluster y ser un cluster distribuido y tolerante a fallos.
  • Maneja certificados de forma automatica, ya no tenemos que configurar los certificados SSL para comunicar de forma segura y auntenticar conexiones entre nodos, esto ya lo hace solito Docker y ademas tambien los va rotando para mayor seguridad.
  • Ya viene incluido con service discovery por default y con un load balancer, ya no tenemos que estar lanzando servicios extras para esto.
  • Orientado a correr servicios por default, esto quiere decir que lo que correremos ahora seran servicios y no contenedores y podremos configurarlos al vuelo el manejo de estos ya es extremandamente sencillo tambien nos quita el usar herramientas de terceros para esto.

Montando mi Cluster Personal

Dentro del Swarm Mode se manejan dos tipos de nodos los Manager y los Worker, lo nodos Manager se encarga de supervisar la orquestación de servicios y mantener el estado saludable del cluster al implementar Raft Consensus Algorithm, por esto mismo lo recomentadable es tener de 3 a 7 nodos Manager y por otro lado tenemos a los nodos Workers que solo se encargar de ejecutar tareas o en otras palabras ejecutar contenedores, esta funcion tambien la pueden hacer los nodos Manager a menos que los configuremos para no ser Workers al mismo tiempo.

Entonces para tener mi cluster personal y desplegar mis experimentos y proyectos personales vamos a iniciar con lo recomendable 3 nodos master y lo iremos creciendo según se necesite con mas workers. Manejaremos los siguienetes nodos:

  • Monitor: Este nodo sera el primer Manager y el leader principal, ademas de tener mi VPN personal y el sistema de monitoreo de todos los nodos y servicios.
  • Database: Aqui pondre mi servidor postgres y servicio de backup.
  • Sandbox: Este sera mi servidor para correr pruebas y demas de aplicaciones.

Por el momento todos los nodos seran Ubuntu 16.04 con 2GB de RAM y 2 cores con 50 GB de espacio de disco, nada grande ni caro … por ahora :P.

Preparandos los nodos con Docker

Lo primero a hacer es tener Docker instalado y configurado en cada host entonces como root tenemos que hacer lo siguiente en cada nodo:

wget -qO- https://get.docker.com/ | sh

Eso es todo lo que necesitamos hacer para tener Docker instalado y configurado.

Iniciando el Swarm Modo en los nodos

Ahora tendremos que iniciar Docker en Swarm Mode en todos los nodos y formar el cluster, primero entramos al nodo Monitor que sera nuestro primer manager y lider, siempre como oot correremos:

docker swarm init

Esto nos debe dar una salida donde nos indica los comandos a correr en los otros nodos para unirnos ya sea como Manager o Worker, no sotros usaremos el comando para unirnos como Manager en los otros dos, que sera algo como esto:

docker swarm join \
--token <token-muy-largo> \
<ip-nodo-monitor>:2377

Despues de correr el comando en los otros dos nodos, dentro de nuestro primer nodo podemos ejecutar docker node ls para ver que ya se unieron los otros dos nodos al cluster:

[email protected]:~# docker node ls
ID                           HOSTNAME  STATUS  AVAILABILITY  MANAGER STATUS
1sk3qap00r5bl9mnycsmi8pec    database  Ready   Active        Reachable
2h714cga80n09nn88th6v18na *  monitor   Ready   Active        Leader
ab6v9lfjjt6y1kp89j4325rf7    sandbox   Ready   Active        Reachable

Podemos ejecutar docker node ls en los otros nodos para comprobar que estan intercambiando información y aparece justamente lo mismo. Con esto ya tenemos nuestro cluter configurado y listo para usar.

Nuestros primeros servicios: El sistema de monitoreo

Para monitorear nuestro cluster usaremos tres cosas:

  • InfluxDB: Como base de datos.
  • Grafana: Como dashboard para visualizar datos.
  • Telegraf: Como agente en cada nodo que nos enviara información.

Los dos primeros los ejecutraremos como servicios dentro del cluster solo en el nodo monitor y telegraf lo instalaemos de forma independiente en cada nodo. Todo comando para crear servicios lo tenemos que ejecutar dentro de uno de los nodos manager, en este caso lo hare desde el nodo monitor, pero igual podriamos instalar Docker en nuestra maquina local y unirnos al cluster.

Primero vamos a instalar InfluxDB en el nodo monitor como servicio, hay que notar que estamos restringiendo donde instalarlo por que estamos tambien montando un directorio del host dentro del contenedor que ejecutara InfluxDB. No olvidar cambiar usuarios y passwords.

docker service create \
--name influxdb \
--constraint 'node.hostname == monitor' \
--mount type=bind,src=/data/influxdb,dst=/data \
--env ADMIN_USER=telegraf \
--env INFLUXDB_INIT_PWD=superpassword \
--env PRE_CREATE_DB=telegraf \
--publish 8086:8086 \
tutum/influxdb

Si hacemos en cualquier nodo docker service ls podemos ver que el servicio se esta ejecutando tambien podemos hacer un docker ps en el nodo monitor para ver que se esta corriendo ahi mismo el contenedor.

Ahora instalar Grafana para poder vizualizar datos:

docker service create \
--name grafana \
--constraint 'node.hostname == monitor' \
--mount type=bind,src=/data/grafana,dst=/var/lib/grafana \
--env GF_SECURITY_ADMIN_PASSWORD=superpassword \
--env GF_USERS_ALLOW_SIGN_UP=false \
--publish 3000:3000 \
grafana/grafana

Grafana puede ser configurado totalmente con variables de entorno, buen momento para leer la documentación y poder saber que tanto se puede configurar nosotros solo pasaremos el password por default del usuario admin para poder loguearnos por primera vez y luego obviamente cambiarlo y desactivaremos el registro de usuarios. Despues de que se terminen de instalar los servicios ya podemos acceder via http://ip-nodo-monitor:3000 a Grafana.

Una vez dentro de Grafana y despues de cambiar el password y personalizar nuestro perfil, podemos añadir una nueva Data Source con los datos de InfluxDB y ya por ultimo solo tenemos que instalar Telegraf en todos los nodos y configurarlo, Telegraf sera el encargado de eviar datos a InfluxDB, datos como, uso de cpu, memoria, información de la red, de lo contenedores, etc. Podemos agregar los repositorios de InfluxDB o bajar solo el deb, yo bajare solo el deb y lo inslare con dpkg en los tres nodos.

Podriamos ponerlo como un servicio Global que corra en todos los nodos, pero el problema esta en que si Docker muere dejara de mandar las demas metricas.

wget https://dl.influxdata.com/telegraf/releases/telegraf_1.0.0-beta3_amd64.deb
dpkg -i telegraf_1.0.0-beta3_amd64.deb

Luego tenemos que editar el archivo /etc/telegraf/telegraf.conf y no olvidar poner los datos para conectar a InfluxDB, son los mismos que usamos en Grafana.

[agent]
  interval = "10s"
  round_interval = true
  metric_batch_size = 1000
  metric_buffer_limit = 10000
  collection_jitter = "0s"
  flush_interval = "10s"
  flush_jitter = "0s"
  precision = ""
  debug = false
  quiet = false
  hostname = ""
  omit_hostname = false
[[outputs.influxdb]]
  urls = ["http://ip-nodo-monitor:8086"]
  database = "telegraf"
  retention_policy = ""
  write_consistency = "any"
  timeout = "5s"
  username = "telegraf"
  password = "superpassword"
[[inputs.cpu]]
  percpu = true
  totalcpu = true
  fielddrop = ["time_*"]
[[inputs.disk]]
  ignore_fs = ["tmpfs", "devtmpfs"]
[[inputs.diskio]]
[[inputs.kernel]]
[[inputs.mem]]
[[inputs.processes]]
[[inputs.swap]]
[[inputs.docker]]
  endpoint = "unix:///var/run/docker.sock"
[[inputs.net]]
  interfaces = ["eth0"]

Por ulitimo solo es necesario agregar al usuario del sistema telegraf al grupo docker y reiniciar el servicio:

usermod -aG docker telegraf
service telegraf restart

Con esto ya tenemos a todos nuestros nodos mandando información a InfluxDB para poder monitorear desde Grafana y ver el estado de nuesto cluster.

Un ejemplo de query que podemos usar para monitorear el uso del CPU de nuestro nodo monitor seria la siguiente:

SELECT "usage_user" FROM "cpu" WHERE "host" = 'monitor'

Ahora ya les toca jugar un poco con Grafana para descurbrir como visualizar los datos :) y podr hacer sus propias configuraciones de monitoreo, Grafana es bastante intuitivo y fácil de usar y entender, no creo que tengan problemas para empezar a armar visualizaciones con el.

Crea una VPN descentralizada entre tus servidores

24 Jun 2016

Uno de los principales problemas que he tenido con mis experimentos es crear redes seguras entre distintos VPS, alguno de los servicios que uso no cuentan con Red Privada otros sin incluyen pero no es por usuario, si no compartida entre varios usuarios, ademas de que en algunas ocaciones uso mas de un proveedor o datacenter.

Por lo mismo me puse a investigar de como montar una red entre distintos nodos sin importar si están con el mismo proveedor o datacenter. Investigando sobre como montar una LAN entre datacenters de forma accesible me tope con PeerVPN, un simple binario que nos ayuda a crear una red peer to peer entre distintos nodos, la ventaja de esta red es que es descentralizada, por lo tanto si un nodo falla los demás se siguen pudiendo ver entre si.

Creando la red

Supongamos que tenemos tres servidores con la siguientes IP’s:

  • 192.168.1.1
  • 192.168.1.2
  • 192.168.1.3

Y queremos crear una VPN entre ellos con el rango de red 10.254.0.116.

En cada uno de los servidores tenemos que instalar PeerVPN, podemos descargar el binario compilado o el código fuente y compilarlo.

Una vez teniendo el binario solo basta con ponerlo en /usr/local/bin y darle permisos de ejecución. Luego solo es necesario crear el archivo de configuración /etc/peervpn.conf y crear el script de inicio /etc/init.d/peervpn y también darle permisos de ejecución.

En mi caso ahora uso Alpine Linux, el script de inicio quedaría así:

#!/sbin/runscript

description="PeerVPN"
command="/usr/local/bin/peervpn"
command_args="/etc/peervpn.conf"
procname="peervpn"
pidfile="/var/run/peervpn.pid"
stopsig="SIGTERM"

start() {
    ebegin "Starting PeerVPN"
    start-stop-daemon -b --start \
        --exec "$command" \
        --pidfile "$pidfile" \
    -- "$command_args"
    eend $?
}

Luego podemos añadirl el script para que se ejecute al inicio:

rc-update add peervpn

Por ultimo solo falta configurar PeerVPN en cada nodo.

Supongamos que el servidor 192.168.1.1 es el primero que vamos a iniciar, lo podemos iniciar con la siguiente configuración:

## ******************************
## * PeerVPN configuration file *
## ******************************

networkname NETNAME
psk SECRET
#initpeers main-node-ip 7000
local 0.0.0.0
port 7000

enablerelay yes
enabletunneling yes

interface tap0
ifconfig4 10.254.0.1/16

enableprivdrop yes
user nobody
group nogroup
chroot /var/empty

Con esto estamos creando una red llamada NETNAME con el password SECRET, que estará escuchando en todos las IPs del servidor 192.168.1.1 en el puerto 7000 UDP. La IP de la nueva VPN será 10.254.0.1 y estará vinculada a la nueva interfaz llamada tap0.

Con esto ya podemos iniciar el primer nodo de la VPN:

/etc/init.d/peervpn start

Con ifconfig podemos asegurarnos que se creo una nueva interfaz y con netstat podemos verificar que el puerto 7000 este escuchando en la IP 192.168.1.1.

Como esta es una red Peer to Peer, todos los servidores tienen que estar conectados entre si, PeerVPN hace esto de forma automática, cuando iniciamos un nuevo servidor este se debe conectar a uno o mas existente y este le dirá información de todos los servidores de la red.

Para el servidor 192.168.1.2 podemos tomar el mismo archivo de configuración y solo será necesario cambiar un par de lineas, la linea ifconfig4 10.254.0.1/16 que seria ifconfig4 10.254.0.2/16 y descomentaríamos la linea initpeers main-node-ip 7000 donde en vez de main-node-ip pondríamos la ip del primer servidor 192.168.1.1. Para el ultimo servidor con IP 192.168.1.3 usamos la misma configuación anterior con la única diferencia de que la ip de tendrá el nodo en la VPN será 10.254.0.3.

Ya podemos iniciar PeerVPN en los últimos dos servidores y estos ya deben esta en la misma VPN.

Podemos tratar de hacer ping entre ellos para ver que todo funcione bien.

PeerVPN solo funciona en linux, en caso de querer acceder a la VPN desde otro sistema operativo tendríamos que instalar OpenVPN en alguno de los nodos y hacer que redireccione el trafico hacia la VPN Peer to Peer, podríamos agregar la siguiente linea en la configuración del servidor OpenVPN para que funcione:

push "route 10.254.0.0 255.255.0.0"

Hostea tu blog en Gitlab Pages

24 Jun 2016

Por un lado tenemos a Hugo que es un fantastico generador de sitios estaticos escrito en Go, es bastante rapido y flexible permite generar sitios que manejen diferentes tipos de contenido e incluso que muestren contenido “dinamico”. Por otro lado tenemos a Gitlab una alternativa a Github pero con superpoderes y open source, aparte de administrar repositorios git desde un entorno web, tambien nos da la opcion de automatizar builds y de crear un repositorio para imagenes de Docker.

Juntando estas dos herramientas podemos usar los builds de Gitlab para que ejecuten Hugo en cada push a nuestro repositorio remoto en gitlab, esto generara todo el sitio estatico y tambien activando las Pages de Gitlab podemos servir nuestro sitio completamente gratis con un dominio propio.

Como Crear Nuestro Sitio en Gitlab Pages

Tomemos de ejemplo este mismo blog:

  • Lo primero es descargar hugo y crear un nuevo sitio con nuestras configuraciones y tema seleccionado (documentacion de Hugo).
  • Debemos crear un repositorio en Gitlab y en las preferencias activar los builds.
  • Debemos agregar un archivo llamado .gitlab-ci.yml en la raiz de nuestro proyecto con el siguiente contenido.
image: publysher/hugo

pages:
  script:
  - hugo
  artifacts:
    paths:
    - public
  only:
  - master
  • Debemos configurar el repositorio remoto y hacer push de nuestro contenido para que automaticamente se construya el sitio estatico dentro de Gitlab.
  • Configurar el dominio en las preferencias de nuestro repositorio en gitlab.

Ahora despues de cada cambio solo tenemos que hacer commit y push para actualizar el sitio. Con estas dos simples herramientas podemos hospedar de forma gratuita sitios personales o incluso hasta sitios con estructuras de contenido mas complejas mientras sean estaticos.